arshtech commited on
Commit
57f57c4
·
verified ·
1 Parent(s): 5a6a88a

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +48 -306
templates/index.html CHANGED
@@ -5,270 +5,45 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Face Detection App</title>
7
  <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- font-family: Arial, sans-serif;
13
- }
14
-
15
- body {
16
- background: linear-gradient(135deg, #667eea, #764ba2);
17
- min-height: 100vh;
18
- padding: 20px;
19
- }
20
-
21
- .container {
22
- max-width: 1000px;
23
- margin: 0 auto;
24
- background: white;
25
- border-radius: 15px;
26
- padding: 30px;
27
- box-shadow: 0 10px 30px rgba(0,0,0,0.2);
28
- }
29
-
30
- header {
31
- text-align: center;
32
- margin-bottom: 30px;
33
- }
34
-
35
- h1 {
36
- color: #333;
37
- margin-bottom: 10px;
38
- }
39
-
40
- .subtitle {
41
- color: #666;
42
- font-size: 1.1rem;
43
- }
44
-
45
- .main-content {
46
- display: grid;
47
- grid-template-columns: 1fr 1fr;
48
- gap: 30px;
49
- margin-bottom: 30px;
50
- }
51
-
52
- @media (max-width: 768px) {
53
- .main-content {
54
- grid-template-columns: 1fr;
55
- }
56
- }
57
-
58
- .input-section, .output-section {
59
- background: #f8f9fa;
60
- padding: 25px;
61
- border-radius: 10px;
62
- border: 2px dashed #dee2e6;
63
- }
64
-
65
- .section-title {
66
- color: #495057;
67
- margin-bottom: 20px;
68
- font-size: 1.3rem;
69
- }
70
-
71
- .input-options {
72
- display: flex;
73
- gap: 10px;
74
- margin-bottom: 20px;
75
- }
76
-
77
- .btn {
78
- padding: 12px 20px;
79
- border: none;
80
- border-radius: 8px;
81
- background: #6c757d;
82
- color: white;
83
- cursor: pointer;
84
- flex: 1;
85
- text-align: center;
86
- transition: background 0.3s;
87
- }
88
-
89
- .btn:hover {
90
- background: #5a6268;
91
- }
92
-
93
- .btn.active {
94
- background: #007bff;
95
- }
96
-
97
- .upload-area {
98
- border: 2px dashed #adb5bd;
99
- border-radius: 10px;
100
- padding: 40px 20px;
101
- text-align: center;
102
- margin-bottom: 20px;
103
- cursor: pointer;
104
- transition: border-color 0.3s;
105
- }
106
-
107
- .upload-area:hover {
108
- border-color: #007bff;
109
- }
110
-
111
- .upload-icon {
112
- font-size: 3rem;
113
- margin-bottom: 15px;
114
- color: #6c757d;
115
- }
116
-
117
- .camera-container {
118
- position: relative;
119
- width: 100%;
120
- height: 300px;
121
- background: #000;
122
- border-radius: 10px;
123
- overflow: hidden;
124
- margin-bottom: 20px;
125
- display: none;
126
- }
127
-
128
- #videoElement {
129
- width: 100%;
130
- height: 100%;
131
- object-fit: cover;
132
- }
133
-
134
- .capture-btn {
135
- position: absolute;
136
- bottom: 20px;
137
- left: 50%;
138
- transform: translateX(-50%);
139
- background: #dc3545;
140
- width: 60px;
141
- height: 60px;
142
- border-radius: 50%;
143
- border: 4px solid white;
144
- cursor: pointer;
145
- }
146
-
147
- .slider-container {
148
- margin: 20px 0;
149
- }
150
-
151
- .slider-label {
152
- display: flex;
153
- justify-content: space-between;
154
- margin-bottom: 10px;
155
- color: #495057;
156
- }
157
-
158
- .slider {
159
- width: 100%;
160
- height: 8px;
161
- -webkit-appearance: none;
162
- background: #dee2e6;
163
- border-radius: 5px;
164
- outline: none;
165
- }
166
-
167
- .slider::-webkit-slider-thumb {
168
- -webkit-appearance: none;
169
- width: 20px;
170
- height: 20px;
171
- border-radius: 50%;
172
- background: #007bff;
173
- cursor: pointer;
174
- }
175
-
176
- .detect-btn {
177
- width: 100%;
178
- padding: 15px;
179
- background: #28a745;
180
- color: white;
181
- border: none;
182
- border-radius: 8px;
183
- font-size: 1.1rem;
184
- cursor: pointer;
185
- transition: background 0.3s;
186
- }
187
-
188
- .detect-btn:hover {
189
- background: #218838;
190
- }
191
-
192
- .detect-btn:disabled {
193
- background: #6c757d;
194
- cursor: not-allowed;
195
- }
196
-
197
- .image-container {
198
- width: 100%;
199
- height: 300px;
200
- background: #e9ecef;
201
- border-radius: 10px;
202
- overflow: hidden;
203
- margin-bottom: 20px;
204
- display: flex;
205
- align-items: center;
206
- justify-content: center;
207
- }
208
-
209
- #outputImage {
210
- max-width: 100%;
211
- max-height: 100%;
212
- display: none;
213
- }
214
-
215
- .placeholder-text {
216
- color: #6c757d;
217
- text-align: center;
218
- }
219
-
220
- .results-container {
221
- background: white;
222
- border-radius: 10px;
223
- padding: 20px;
224
- border: 2px solid #e9ecef;
225
- }
226
-
227
- .result-item {
228
- display: flex;
229
- justify-content: space-between;
230
- padding: 12px 0;
231
- border-bottom: 1px solid #dee2e6;
232
- }
233
-
234
- .result-item:last-child {
235
- border-bottom: none;
236
- }
237
-
238
- .result-label {
239
- font-weight: bold;
240
- color: #495057;
241
- }
242
-
243
- .result-value {
244
- color: #007bff;
245
- font-weight: bold;
246
- }
247
-
248
- .loading {
249
- display: none;
250
- text-align: center;
251
- margin: 20px 0;
252
- }
253
-
254
- .spinner {
255
- border: 4px solid #f3f3f3;
256
- border-radius: 50%;
257
- border-top: 4px solid #007bff;
258
- width: 40px;
259
- height: 40px;
260
- animation: spin 1s linear infinite;
261
- margin: 0 auto 15px;
262
- }
263
-
264
- @keyframes spin {
265
- 0% { transform: rotate(0deg); }
266
- 100% { transform: rotate(360deg); }
267
- }
268
-
269
- #fileInput {
270
- display: none;
271
- }
272
  </style>
273
  </head>
274
  <body>
@@ -281,24 +56,19 @@
281
  <div class="main-content">
282
  <div class="input-section">
283
  <h2 class="section-title">Input</h2>
284
-
285
  <div class="input-options">
286
  <button id="uploadBtn" class="btn active">Upload Image</button>
287
  <button id="cameraBtn" class="btn">Use Camera</button>
288
  </div>
289
-
290
  <div id="uploadArea" class="upload-area">
291
  <div class="upload-icon">📁</div>
292
  <p>Click to upload an image</p>
293
- <p style="font-size: 0.9rem; color: #6c757d; margin-top: 5px;">Supported: JPG, PNG</p>
294
  <input type="file" id="fileInput" accept="image/*">
295
  </div>
296
-
297
  <div id="cameraContainer" class="camera-container">
298
  <video id="videoElement" autoplay playsinline></video>
299
  <button id="captureBtn" class="capture-btn"></button>
300
  </div>
301
-
302
  <div class="slider-container">
303
  <div class="slider-label">
304
  <span>Detection Scale:</span>
@@ -306,39 +76,31 @@
306
  </div>
307
  <input type="range" min="1.1" max="2.0" step="0.1" value="1.1" class="slider" id="scaleSlider">
308
  </div>
309
-
310
  <button id="detectBtn" class="detect-btn" disabled>Detect Faces</button>
311
-
312
  <div id="loading" class="loading">
313
  <div class="spinner"></div>
314
  <p>Processing image...</p>
315
  </div>
316
  </div>
317
-
318
  <div class="output-section">
319
  <h2 class="section-title">Output</h2>
320
-
321
  <div class="image-container">
322
  <img id="outputImage" alt="Processed Image">
323
  <p id="placeholderText" class="placeholder-text">Processed image will appear here</p>
324
  </div>
325
-
326
  <div id="resultsContainer" class="results-container" style="display: none;">
327
  <h3 style="margin-bottom: 15px; color: #495057;">Detection Results</h3>
328
  <div class="result-item">
329
  <span class="result-label">Faces Detected:</span>
330
  <span id="facesCount" class="result-value">0</span>
331
  </div>
332
- <div id="facesDetails">
333
- <!-- Face details will be added here -->
334
- </div>
335
  </div>
336
  </div>
337
  </div>
338
  </div>
339
 
340
  <script>
341
- // DOM Elements
342
  const uploadBtn = document.getElementById('uploadBtn');
343
  const cameraBtn = document.getElementById('cameraBtn');
344
  const uploadArea = document.getElementById('uploadArea');
@@ -356,11 +118,9 @@
356
  const facesDetails = document.getElementById('facesDetails');
357
  const loading = document.getElementById('loading');
358
 
359
- // State variables
360
  let currentImage = null;
361
  let stream = null;
362
 
363
- // Event Listeners
364
  uploadBtn.addEventListener('click', () => {
365
  uploadBtn.classList.add('active');
366
  cameraBtn.classList.remove('active');
@@ -377,19 +137,12 @@
377
  startCamera();
378
  });
379
 
380
- uploadArea.addEventListener('click', () => {
381
- fileInput.click();
382
- });
383
-
384
  fileInput.addEventListener('change', handleImageUpload);
385
  captureBtn.addEventListener('click', captureImage);
386
  detectBtn.addEventListener('click', detectFaces);
 
387
 
388
- scaleSlider.addEventListener('input', () => {
389
- scaleValue.textContent = scaleSlider.value;
390
- });
391
-
392
- // Functions
393
  function handleImageUpload(event) {
394
  const file = event.target.files[0];
395
  if (file) {
@@ -407,14 +160,14 @@
407
  }
408
 
409
  function startCamera() {
410
- if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
411
  navigator.mediaDevices.getUserMedia({ video: true })
412
- .then(function(mediaStream) {
413
  stream = mediaStream;
414
  videoElement.srcObject = stream;
415
  detectBtn.disabled = false;
416
  })
417
- .catch(function(error) {
418
  console.error("Camera error: ", error);
419
  alert("Unable to access camera. Please check permissions.");
420
  });
@@ -436,7 +189,6 @@
436
  canvas.height = videoElement.videoHeight;
437
  const ctx = canvas.getContext('2d');
438
  ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
439
-
440
  currentImage = canvas.toDataURL('image/png');
441
  outputImage.src = currentImage;
442
  outputImage.style.display = 'block';
@@ -456,17 +208,11 @@
456
  try {
457
  const response = await fetch('/detect', {
458
  method: 'POST',
459
- headers: {
460
- 'Content-Type': 'application/json',
461
- },
462
- body: JSON.stringify({
463
- image: currentImage,
464
- scale: scaleSlider.value
465
- })
466
  });
467
 
468
  const data = await response.json();
469
-
470
  if (data.success) {
471
  outputImage.src = data.result_image;
472
  displayResults(data.faces_detected, data.face_data);
@@ -474,7 +220,6 @@
474
  alert('Error detecting faces: ' + data.error);
475
  }
476
  } catch (error) {
477
- console.error('Detection error:', error);
478
  alert('Error detecting faces. Please try again.');
479
  } finally {
480
  loading.style.display = 'none';
@@ -484,7 +229,6 @@
484
 
485
  function displayResults(faceCount, faceData) {
486
  facesCount.textContent = faceCount;
487
-
488
  facesDetails.innerHTML = '';
489
  faceData.forEach(face => {
490
  const faceElement = document.createElement('div');
@@ -495,12 +239,10 @@
495
  `;
496
  facesDetails.appendChild(faceElement);
497
  });
498
-
499
  resultsContainer.style.display = 'block';
500
  }
501
 
502
- // Initialize
503
- uploadBtn.click(); // Start with upload mode
504
  </script>
505
  </body>
506
  </html>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Face Detection App</title>
7
  <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; font-family: Arial, sans-serif; }
9
+ body { background: linear-gradient(135deg, #667eea, #764ba2); min-height: 100vh; padding: 20px; }
10
+ .container { max-width: 1000px; margin: 0 auto; background: white; border-radius: 15px; padding: 30px; }
11
+ header { text-align: center; margin-bottom: 30px; }
12
+ h1 { color: #333; margin-bottom: 10px; }
13
+ .subtitle { color: #666; }
14
+ .main-content { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 30px; }
15
+ @media (max-width: 768px) { .main-content { grid-template-columns: 1fr; } }
16
+ .input-section, .output-section { background: #f8f9fa; padding: 25px; border-radius: 10px; border: 2px dashed #dee2e6; }
17
+ .section-title { color: #495057; margin-bottom: 20px; }
18
+ .input-options { display: flex; gap: 10px; margin-bottom: 20px; }
19
+ .btn { padding: 12px; border: none; border-radius: 8px; background: #6c757d; color: white; cursor: pointer; flex: 1; }
20
+ .btn:hover { background: #5a6268; }
21
+ .btn.active { background: #007bff; }
22
+ .upload-area { border: 2px dashed #adb5bd; border-radius: 10px; padding: 40px 20px; text-align: center; margin-bottom: 20px; cursor: pointer; }
23
+ .upload-area:hover { border-color: #007bff; }
24
+ .upload-icon { font-size: 3rem; margin-bottom: 15px; color: #6c757d; }
25
+ .camera-container { position: relative; width: 100%; height: 300px; background: #000; border-radius: 10px; overflow: hidden; margin-bottom: 20px; display: none; }
26
+ #videoElement { width: 100%; height: 100%; object-fit: cover; }
27
+ .capture-btn { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); background: #dc3545; width: 60px; height: 60px; border-radius: 50%; border: 4px solid white; cursor: pointer; }
28
+ .slider-container { margin: 20px 0; }
29
+ .slider-label { display: flex; justify-content: space-between; margin-bottom: 10px; color: #495057; }
30
+ .slider { width: 100%; height: 8px; background: #dee2e6; border-radius: 5px; outline: none; }
31
+ .slider::-webkit-slider-thumb { width: 20px; height: 20px; border-radius: 50%; background: #007bff; cursor: pointer; }
32
+ .detect-btn { width: 100%; padding: 15px; background: #28a745; color: white; border: none; border-radius: 8px; font-size: 1.1rem; cursor: pointer; }
33
+ .detect-btn:hover { background: #218838; }
34
+ .detect-btn:disabled { background: #6c757d; cursor: not-allowed; }
35
+ .image-container { width: 100%; height: 300px; background: #e9ecef; border-radius: 10px; overflow: hidden; margin-bottom: 20px; display: flex; align-items: center; justify-content: center; }
36
+ #outputImage { max-width: 100%; max-height: 100%; display: none; }
37
+ .placeholder-text { color: #6c757d; text-align: center; }
38
+ .results-container { background: white; border-radius: 10px; padding: 20px; border: 2px solid #e9ecef; }
39
+ .result-item { display: flex; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid #dee2e6; }
40
+ .result-item:last-child { border-bottom: none; }
41
+ .result-label { font-weight: bold; color: #495057; }
42
+ .result-value { color: #007bff; font-weight: bold; }
43
+ .loading { display: none; text-align: center; margin: 20px 0; }
44
+ .spinner { border: 4px solid #f3f3f3; border-radius: 50%; border-top: 4px solid #007bff; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto 15px; }
45
+ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
46
+ #fileInput { display: none; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  </style>
48
  </head>
49
  <body>
 
56
  <div class="main-content">
57
  <div class="input-section">
58
  <h2 class="section-title">Input</h2>
 
59
  <div class="input-options">
60
  <button id="uploadBtn" class="btn active">Upload Image</button>
61
  <button id="cameraBtn" class="btn">Use Camera</button>
62
  </div>
 
63
  <div id="uploadArea" class="upload-area">
64
  <div class="upload-icon">📁</div>
65
  <p>Click to upload an image</p>
 
66
  <input type="file" id="fileInput" accept="image/*">
67
  </div>
 
68
  <div id="cameraContainer" class="camera-container">
69
  <video id="videoElement" autoplay playsinline></video>
70
  <button id="captureBtn" class="capture-btn"></button>
71
  </div>
 
72
  <div class="slider-container">
73
  <div class="slider-label">
74
  <span>Detection Scale:</span>
 
76
  </div>
77
  <input type="range" min="1.1" max="2.0" step="0.1" value="1.1" class="slider" id="scaleSlider">
78
  </div>
 
79
  <button id="detectBtn" class="detect-btn" disabled>Detect Faces</button>
 
80
  <div id="loading" class="loading">
81
  <div class="spinner"></div>
82
  <p>Processing image...</p>
83
  </div>
84
  </div>
 
85
  <div class="output-section">
86
  <h2 class="section-title">Output</h2>
 
87
  <div class="image-container">
88
  <img id="outputImage" alt="Processed Image">
89
  <p id="placeholderText" class="placeholder-text">Processed image will appear here</p>
90
  </div>
 
91
  <div id="resultsContainer" class="results-container" style="display: none;">
92
  <h3 style="margin-bottom: 15px; color: #495057;">Detection Results</h3>
93
  <div class="result-item">
94
  <span class="result-label">Faces Detected:</span>
95
  <span id="facesCount" class="result-value">0</span>
96
  </div>
97
+ <div id="facesDetails"></div>
 
 
98
  </div>
99
  </div>
100
  </div>
101
  </div>
102
 
103
  <script>
 
104
  const uploadBtn = document.getElementById('uploadBtn');
105
  const cameraBtn = document.getElementById('cameraBtn');
106
  const uploadArea = document.getElementById('uploadArea');
 
118
  const facesDetails = document.getElementById('facesDetails');
119
  const loading = document.getElementById('loading');
120
 
 
121
  let currentImage = null;
122
  let stream = null;
123
 
 
124
  uploadBtn.addEventListener('click', () => {
125
  uploadBtn.classList.add('active');
126
  cameraBtn.classList.remove('active');
 
137
  startCamera();
138
  });
139
 
140
+ uploadArea.addEventListener('click', () => fileInput.click());
 
 
 
141
  fileInput.addEventListener('change', handleImageUpload);
142
  captureBtn.addEventListener('click', captureImage);
143
  detectBtn.addEventListener('click', detectFaces);
144
+ scaleSlider.addEventListener('input', () => scaleValue.textContent = scaleSlider.value);
145
 
 
 
 
 
 
146
  function handleImageUpload(event) {
147
  const file = event.target.files[0];
148
  if (file) {
 
160
  }
161
 
162
  function startCamera() {
163
+ if (navigator.mediaDevices?.getUserMedia) {
164
  navigator.mediaDevices.getUserMedia({ video: true })
165
+ .then(mediaStream => {
166
  stream = mediaStream;
167
  videoElement.srcObject = stream;
168
  detectBtn.disabled = false;
169
  })
170
+ .catch(error => {
171
  console.error("Camera error: ", error);
172
  alert("Unable to access camera. Please check permissions.");
173
  });
 
189
  canvas.height = videoElement.videoHeight;
190
  const ctx = canvas.getContext('2d');
191
  ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
 
192
  currentImage = canvas.toDataURL('image/png');
193
  outputImage.src = currentImage;
194
  outputImage.style.display = 'block';
 
208
  try {
209
  const response = await fetch('/detect', {
210
  method: 'POST',
211
+ headers: { 'Content-Type': 'application/json' },
212
+ body: JSON.stringify({ image: currentImage, scale: scaleSlider.value })
 
 
 
 
 
213
  });
214
 
215
  const data = await response.json();
 
216
  if (data.success) {
217
  outputImage.src = data.result_image;
218
  displayResults(data.faces_detected, data.face_data);
 
220
  alert('Error detecting faces: ' + data.error);
221
  }
222
  } catch (error) {
 
223
  alert('Error detecting faces. Please try again.');
224
  } finally {
225
  loading.style.display = 'none';
 
229
 
230
  function displayResults(faceCount, faceData) {
231
  facesCount.textContent = faceCount;
 
232
  facesDetails.innerHTML = '';
233
  faceData.forEach(face => {
234
  const faceElement = document.createElement('div');
 
239
  `;
240
  facesDetails.appendChild(faceElement);
241
  });
 
242
  resultsContainer.style.display = 'block';
243
  }
244
 
245
+ uploadBtn.click();
 
246
  </script>
247
  </body>
248
  </html>