Docfile commited on
Commit
deddb46
1 Parent(s): c8dbde4

Create templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +237 -0
templates/index.html ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Application de Reconnaissance Faciale</title>
7
+ <!-- Tailwind CSS -->
8
+ <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
9
+ <!-- Font Awesome (pour les icônes) -->
10
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css">
11
+ <style>
12
+ /* Styles personnalisés (si nécessaire) */
13
+ .preview-image {
14
+ background-size: cover;
15
+ background-position: center;
16
+ min-height: 150px;
17
+ }
18
+
19
+ .github-link {
20
+ position: fixed;
21
+ bottom: 20px;
22
+ right: 20px;
23
+ padding: 10px;
24
+ background-color: #333;
25
+ color: white;
26
+ border-radius: 5px;
27
+ text-decoration: none;
28
+ display: flex;
29
+ align-items: center;
30
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
31
+ }
32
+
33
+ .github-link i {
34
+ margin-right: 8px;
35
+ font-size: 20px;
36
+ }
37
+
38
+ .github-link:hover {
39
+ background-color: #555;
40
+ }
41
+ </style>
42
+ </head>
43
+ <body class="bg-gray-100 font-sans">
44
+ <div class="container mx-auto p-4">
45
+ <h1 class="text-4xl font-bold text-center text-blue-700 mb-8">
46
+ <i class="fas fa-user-check text-5xl mr-3"></i>
47
+ Reconnaissance et Comparaison Faciale
48
+ </h1>
49
+
50
+ <div class="grid md:grid-cols-2 gap-8">
51
+ <!-- Section de sélection d'images -->
52
+ <div class="bg-white p-6 rounded-lg shadow-lg">
53
+ <h2 class="text-2xl font-semibold mb-4 text-gray-700">
54
+ <i class="fas fa-images text-blue-500 mr-2"></i>
55
+ Sélectionner des images
56
+ </h2>
57
+ <input type="file" id="imageUpload" accept="image/*" class="mb-4 hidden">
58
+ <label for="imageUpload" class="cursor-pointer bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-lg inline-flex items-center transition duration-200 ease-in-out">
59
+ <i class="fas fa-upload mr-2"></i>
60
+ Choisir un fichier
61
+ </label>
62
+
63
+ <button id="cameraButton" class="bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-6 rounded-lg ml-4 inline-flex items-center transition duration-200 ease-in-out">
64
+ <i class="fas fa-camera mr-2"></i>
65
+ Utiliser la caméra
66
+ </button>
67
+
68
+ <video id="videoFeed" width="320" height="240" autoplay class="hidden mt-4 rounded-lg"></video>
69
+ <canvas id="canvas" width="320" height="240" class="hidden"></canvas>
70
+
71
+ <!-- Prévisualisation des images -->
72
+ <div class="grid grid-cols-2 gap-4 mt-6">
73
+ <div id="imagePreview1" class="w-full aspect-w-1 aspect-h-1 rounded-lg overflow-hidden preview-image"></div>
74
+ <div id="imagePreview2" class="w-full aspect-w-1 aspect-h-1 rounded-lg overflow-hidden preview-image"></div>
75
+ </div>
76
+ </div>
77
+
78
+ <!-- Section des résultats -->
79
+ <div class="bg-white p-6 rounded-lg shadow-lg">
80
+ <h2 class="text-2xl font-semibold mb-4 text-gray-700">
81
+ <i class="fas fa-poll-h text-blue-500 mr-2"></i>
82
+ Résultats de la comparaison
83
+ </h2>
84
+ <div id="results" class="text-center">
85
+ <p class="text-gray-600">Veuillez sélectionner des images ou utiliser la caméra pour commencer.</p>
86
+ </div>
87
+ <button id="compareButton" class="hidden bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mt-4">
88
+ Comparer les visages
89
+ </button>
90
+ </div>
91
+ </div>
92
+ </div>
93
+
94
+ <!-- Lien GitHub -->
95
+ <a href="https://github.com/Yusufibin" target="_blank" class="github-link">
96
+ <i class="fab fa-github"></i>
97
+ <span>Yusufibin</span>
98
+ </a>
99
+
100
+ <script>
101
+ const imageUpload = document.getElementById('imageUpload');
102
+ const cameraButton = document.getElementById('cameraButton');
103
+ const videoFeed = document.getElementById('videoFeed');
104
+ const canvas = document.getElementById('canvas');
105
+ const imagePreview1 = document.getElementById('imagePreview1');
106
+ const imagePreview2 = document.getElementById('imagePreview2');
107
+ const resultsDiv = document.getElementById('results');
108
+ const compareButton = document.getElementById('compareButton');
109
+ const API_BASE_URL = 'http://127.0.0.1:5000'; // URL de base de ton API Flask
110
+
111
+ let usingCamera = false;
112
+ let currentImage = 1; // 1 or 2 pour suivre quelle image prévisualiser
113
+
114
+ // Gestionnaire pour le téléchargement de fichiers
115
+ imageUpload.addEventListener('change', async (event) => {
116
+ const file = event.target.files[0];
117
+ if (file) {
118
+ const reader = new FileReader();
119
+ reader.onload = (e) => {
120
+ if (currentImage === 1) {
121
+ imagePreview1.style.backgroundImage = `url(${e.target.result})`;
122
+ currentImage = 2;
123
+ } else {
124
+ imagePreview2.style.backgroundImage = `url(${e.target.result})`;
125
+ currentImage = 1;
126
+ }
127
+ compareButton.classList.remove('hidden'); // Affiche le bouton de comparaison
128
+ };
129
+ reader.readAsDataURL(file);
130
+ }
131
+ });
132
+
133
+ // Gestionnaire pour le bouton de la caméra
134
+ cameraButton.addEventListener('click', async () => {
135
+ usingCamera = !usingCamera;
136
+
137
+ if (usingCamera) {
138
+ cameraButton.textContent = 'Arrêter la caméra';
139
+ try {
140
+ const stream = await navigator.mediaDevices.getUserMedia({ video: true });
141
+ videoFeed.srcObject = stream;
142
+ videoFeed.classList.remove('hidden');
143
+ } catch (err) {
144
+ console.error("Erreur lors de l'accès à la caméra :", err);
145
+ }
146
+ } else {
147
+ cameraButton.textContent = 'Utiliser la caméra';
148
+ const tracks = videoFeed.srcObject.getTracks();
149
+ tracks.forEach(track => track.stop());
150
+ videoFeed.classList.add('hidden');
151
+ }
152
+ });
153
+
154
+ // Capture d'image à partir de la caméra
155
+ function captureImageFromCamera() {
156
+ const context = canvas.getContext('2d');
157
+ context.drawImage(videoFeed, 0, 0, canvas.width, canvas.height);
158
+ const imageDataURL = canvas.toDataURL('image/png');
159
+
160
+ if (currentImage === 1) {
161
+ imagePreview1.style.backgroundImage = `url(${imageDataURL})`;
162
+ currentImage = 2;
163
+ } else {
164
+ imagePreview2.style.backgroundImage = `url(${imageDataURL})`;
165
+ currentImage = 1;
166
+ }
167
+ compareButton.classList.remove('hidden'); // Affiche le bouton de comparaison
168
+ }
169
+
170
+ // Gestionnaire pour le bouton de comparaison
171
+ compareButton.addEventListener('click', () => {
172
+ if (imagePreview1.style.backgroundImage && imagePreview2.style.backgroundImage) {
173
+ const formData = new FormData();
174
+ const imageData1 = dataURLtoBlob(imagePreview1.style.backgroundImage.slice(5, -2));
175
+ const imageData2 = dataURLtoBlob(imagePreview2.style.backgroundImage.slice(5, -2));
176
+
177
+ formData.append('image1', imageData1, 'image1.png');
178
+ formData.append('image2', imageData2, 'image2.png');
179
+
180
+ fetch(`${API_BASE_URL}/verify`, {
181
+ method: 'POST',
182
+ body: formData,
183
+ })
184
+ .then(response => response.json())
185
+ .then(data => {
186
+ displayResults(data);
187
+ })
188
+ .catch(error => {
189
+ console.error('Erreur lors de la comparaison des visages:', error);
190
+ resultsDiv.innerHTML = `<p>Erreur lors de la comparaison.</p>`;
191
+ });
192
+ } else {
193
+ alert('Veuillez télécharger deux images pour la comparaison.');
194
+ }
195
+ });
196
+
197
+ // Fonction pour convertir une URL de données en Blob
198
+ function dataURLtoBlob(dataURL) {
199
+ const parts = dataURL.split(';base64,');
200
+ const contentType = parts[0].split(':')[1];
201
+ const raw = window.atob(parts[1]);
202
+ const rawLength = raw.length;
203
+ const uInt8Array = new Uint8Array(rawLength);
204
+
205
+ for (let i = 0; i < rawLength; ++i) {
206
+ uInt8Array[i] = raw.charCodeAt(i);
207
+ }
208
+
209
+ return new Blob([uInt8Array], { type: contentType });
210
+ }
211
+
212
+ // Fonction pour afficher les résultats de la comparaison
213
+ function displayResults(data) {
214
+ let resultHTML = '';
215
+
216
+ if (data.error) {
217
+ resultHTML = `<p class="text-red-600">${data.error}</p>`;
218
+ } else {
219
+ const similarity = data.verified ? 'Visages similaires' : 'Visages différents';
220
+ resultHTML += `<p class="text-lg ${data.verified ? 'text-green-600' : 'text-red-600'}">${similarity}</p>`;
221
+
222
+ if (data.distance !== undefined && data.threshold !== undefined) {
223
+ resultHTML += `<p class="mt-2">Distance : ${data.distance.toFixed(4)}</p>`;
224
+ resultHTML += `<p>Seuil de similarité : ${data.threshold.toFixed(4)}</p>`;
225
+ }
226
+
227
+ if (data.image1_url && data.image2_url) {
228
+ resultHTML += `<img src="${API_BASE_URL}/${data.image1_url}" alt="Image 1" class="w-32 h-32 mt-4 rounded-lg">`;
229
+ resultHTML += `<img src="${API_BASE_URL}/${data.image2_url}" alt="Image 2" class="w-32 h-32 mt-4 rounded-lg">`;
230
+ }
231
+ }
232
+
233
+ resultsDiv.innerHTML = resultHTML;
234
+ }
235
+ </script>
236
+ </body>
237
+ </html>