Paradise151 commited on
Commit
a00f917
·
verified ·
1 Parent(s): d12995f

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +180 -1
index.html CHANGED
@@ -1,5 +1,7 @@
1
  <!-- indexPhoto.html -->
2
- <!DOCTYPE html>
 
 
3
  <html>
4
  <head>
5
  <meta charset="utf-8">
@@ -158,4 +160,181 @@
158
  })();
159
  </script>
160
  </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  </html>
 
1
  <!-- indexPhoto.html -->
2
+
3
+ <!--рабочая версия 1 -->
4
+ <!-- <!DOCTYPE html>
5
  <html>
6
  <head>
7
  <meta charset="utf-8">
 
160
  })();
161
  </script>
162
  </body>
163
+ </html> -->
164
+
165
+
166
+
167
+
168
+ <!DOCTYPE html>
169
+ <html>
170
+ <head>
171
+ <meta charset="utf-8">
172
+ <title>GrechnikNet — Snapshot Detection</title>
173
+ <style>
174
+ body { background:#111; color:#eee; font-family:sans-serif; margin:0; text-align:center; }
175
+ header { padding:16px; }
176
+ video, img { width: min(100vw, 720px); height:auto; border:1px solid #333; border-radius:8px; margin:10px 0; }
177
+ .controls { display:flex; gap:16px; flex-wrap:wrap; justify-content:center; margin:16px 0; }
178
+ .control { background:#1b1b1b; padding:10px 12px; border-radius:8px; }
179
+ label { display:block; font-size:14px; margin-bottom:6px; }
180
+ input[type="range"] { width:200px; }
181
+ button { padding:10px 16px; border:none; border-radius:6px; background:#3a6df0; color:#fff; cursor:pointer; }
182
+ button:disabled { background:#555; cursor:not-allowed; }
183
+ pre { text-align:left; background:#0e0e0e; padding:12px; border-radius:8px; width:min(100vw,720px); margin:10px auto; }
184
+ </style>
185
+ </head>
186
+ <body>
187
+ <header>
188
+ <h2>GrechnikNet — Snapshot Detection</h2>
189
+ <p>Сверху поток с камеры, снизу результат последнего снимка</p>
190
+ </header>
191
+
192
+ <!-- Панель управления -->
193
+ <div class="controls">
194
+ <div class="control">
195
+ <label>Камера:</label>
196
+ <select id="cameraSelect"></select>
197
+ </div>
198
+ <div class="control">
199
+ <label>Степень уверенности (conf): <span id="confVal">0.25</span></label>
200
+ <input type="range" id="confSlider" min="0" max="1" step="0.05" value="0.25">
201
+ </div>
202
+ <div class="control">
203
+ <label>Степень пересечения (IoU): <span id="iouVal">0.45</span></label>
204
+ <input type="range" id="iouSlider" min="0" max="1" step="0.05" value="0.45">
205
+ </div>
206
+ <div class="control">
207
+ <label>Режим ответа:</label>
208
+ <select id="modeSelect">
209
+ <option value="image">Аннотированное изображение</option>
210
+ <option value="json">Только боксы (JSON)</option>
211
+ </select>
212
+ </div>
213
+ <div class="control">
214
+ <button id="startBtn">Старт</button>
215
+ <button id="stopBtn" disabled>Стоп</button>
216
+ </div>
217
+ </div>
218
+
219
+ <!-- Верхнее окно: поток -->
220
+ <video id="video" autoplay playsinline muted></video>
221
+
222
+ <!-- Кнопка между окнами -->
223
+ <button id="snapBtn">Сделать фото</button>
224
+
225
+ <!-- Нижнее окно: результат -->
226
+ <img id="resultImg" alt="Результат появится здесь">
227
+ <pre id="jsonOut" style="display:none;"></pre>
228
+
229
+ <script>
230
+ const video = document.getElementById('video');
231
+ const resultImg = document.getElementById('resultImg');
232
+ const jsonOut = document.getElementById('jsonOut');
233
+ const snapBtn = document.getElementById('snapBtn');
234
+ const cameraSelect = document.getElementById('cameraSelect');
235
+ const confSlider = document.getElementById('confSlider');
236
+ const iouSlider = document.getElementById('iouSlider');
237
+ const confVal = document.getElementById('confVal');
238
+ const iouVal = document.getElementById('iouVal');
239
+ const modeSelect = document.getElementById('modeSelect');
240
+ const startBtn = document.getElementById('startBtn');
241
+ const stopBtn = document.getElementById('stopBtn');
242
+
243
+ let stream = null;
244
+ let currentDeviceId = null;
245
+
246
+ confSlider.oninput = () => confVal.textContent = confSlider.value;
247
+ iouSlider.oninput = () => iouVal.textContent = iouSlider.value;
248
+
249
+ async function enumerateCameras() {
250
+ const devices = await navigator.mediaDevices.enumerateDevices();
251
+ cameraSelect.innerHTML = '';
252
+ const cams = devices.filter(d => d.kind === 'videoinput');
253
+ cams.forEach((cam, i) => {
254
+ const opt = document.createElement('option');
255
+ opt.value = cam.deviceId || i;
256
+ opt.textContent = cam.label || `Камера ${i+1}`;
257
+ cameraSelect.appendChild(opt);
258
+ });
259
+ if (cams.length > 0) currentDeviceId = cams[0].deviceId;
260
+ }
261
+
262
+ async function startCamera(deviceId) {
263
+ if (stream) stopCamera();
264
+ const constraints = {
265
+ video: {
266
+ deviceId: deviceId ? { exact: deviceId } : undefined,
267
+ facingMode: 'environment',
268
+ width: { ideal: 720 },
269
+ height: { ideal: 720 }
270
+ },
271
+ audio: false
272
+ };
273
+ stream = await navigator.mediaDevices.getUserMedia(constraints);
274
+ video.srcObject = stream;
275
+ await video.play();
276
+ }
277
+
278
+ function stopCamera() {
279
+ if (stream) {
280
+ stream.getTracks().forEach(t => t.stop());
281
+ stream = null;
282
+ }
283
+ }
284
+
285
+ cameraSelect.onchange = async () => {
286
+ currentDeviceId = cameraSelect.value;
287
+ await startCamera(currentDeviceId);
288
+ };
289
+
290
+ async function takePhoto() {
291
+ if (!video.srcObject) return;
292
+
293
+ const canvas = document.createElement('canvas');
294
+ const w = Math.min(720, video.videoWidth || 640);
295
+ const h = Math.floor(w * (video.videoHeight / video.videoWidth));
296
+ canvas.width = w;
297
+ canvas.height = h;
298
+ const ctx = canvas.getContext('2d');
299
+ ctx.drawImage(video, 0, 0, w, h);
300
+
301
+ const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', 0.9));
302
+ const formData = new FormData();
303
+ formData.append('file', blob, 'frame.jpg');
304
+ formData.append('conf', confSlider.value);
305
+ formData.append('iou', iouSlider.value);
306
+ const returnImage = (modeSelect.value === 'image') ? 1 : 0;
307
+ formData.append('return_image', returnImage.toString());
308
+
309
+ const resp = await fetch('/predict', { method: 'POST', body: formData });
310
+ if (returnImage === 1) {
311
+ const arrBuf = await resp.arrayBuffer();
312
+ const blobRes = new Blob([arrBuf], { type: 'image/jpeg' });
313
+ resultImg.src = URL.createObjectURL(blobRes);
314
+ resultImg.style.display = 'block';
315
+ jsonOut.style.display = 'none';
316
+ } else {
317
+ const data = await resp.json();
318
+ jsonOut.textContent = JSON.stringify(data, null, 2);
319
+ jsonOut.style.display = 'block';
320
+ resultImg.style.display = 'none';
321
+ }
322
+ }
323
+
324
+ snapBtn.onclick = takePhoto;
325
+
326
+ startBtn.onclick = async () => {
327
+ await enumerateCameras();
328
+ await startCamera(currentDeviceId);
329
+ startBtn.disabled = true;
330
+ stopBtn.disabled = false;
331
+ };
332
+
333
+ stopBtn.onclick = () => {
334
+ stopCamera();
335
+ startBtn.disabled = false;
336
+ stopBtn.disabled = true;
337
+ };
338
+ </script>
339
+ </body>
340
  </html>