TDN-M commited on
Commit
7f57424
·
verified ·
1 Parent(s): 105029f

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +89 -50
index.html CHANGED
@@ -8,14 +8,15 @@
8
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/selfie_segmentation.js" crossorigin="anonymous"></script>
9
  </head>
10
  <body>
 
 
 
11
  <div class="card" id="controlPanel">
12
  <h1>OBS AI Background Remover</h1>
13
  <div>
14
  <h2>Live Preview</h2>
15
- <video id="videoPreview" autoplay playsinline></video>
16
- <canvas id="canvasOutput" width="1920" height="1080"></canvas>
17
  <p id="status">Loading AI Model...</p>
18
- <p id="noVideo" style="display: none;">No video source selected</p>
19
  </div>
20
 
21
  <div>
@@ -64,10 +65,6 @@
64
  <input type="checkbox" id="enableBgRemoval" checked>
65
  <label for="enableBgRemoval">Enable Background Removal</label>
66
  </div>
67
- <div>
68
- <input type="checkbox" id="showPreview" checked>
69
- <label for="showPreview">Show Preview</label>
70
- </div>
71
  <div>
72
  <label for="modelQuality">AI Model Quality</label>
73
  <input type="range" id="modelQuality" min="0" max="1" value="1" step="1">
@@ -106,7 +103,7 @@
106
  </div>
107
  </div>
108
 
109
- <p>Made with DeepSite - 🧬 Remix</p>
110
 
111
  <script>
112
  // Initialize elements
@@ -117,7 +114,7 @@
117
  const noVideoElement = document.getElementById('noVideo');
118
  const videoSourceSelect = document.getElementById('videoSource');
119
  const enableBgRemoval = document.getElementById('enableBgRemoval');
120
- const showPreview = document.getElementById('showPreview');
121
  const controlPanel = document.getElementById('controlPanel');
122
  const processingTimeElement = document.getElementById('processingTime');
123
  const fpsElement = document.getElementById('fps');
@@ -139,16 +136,21 @@
139
 
140
  // Initialize MediaPipe Selfie Segmentation
141
  async function initModel() {
142
- selfieSegmentation = new SelfieSegmentation({
143
- locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/${file}`
144
- });
145
- selfieSegmentation.setOptions({
146
- modelSelection: parseInt(modelQuality.value), // 0: General, 1: Landscape
147
- selfieMode: true
148
- });
149
- selfieSegmentation.onResults(onResults);
150
- await selfieSegmentation.initialize();
151
- statusElement.textContent = 'AI Model Loaded';
 
 
 
 
 
152
  }
153
 
154
  // Populate video sources
@@ -156,17 +158,20 @@
156
  try {
157
  const devices = await navigator.mediaDevices.enumerateDevices();
158
  videoSourceSelect.innerHTML = '<option value="">Select a video source</option>';
159
- devices.forEach(device => {
160
- if (device.kind === 'videoinput') {
161
- const option = document.createElement('option');
162
- option.value = device.deviceId;
163
- option.text = device.label || `Camera ${videoSourceSelect.options.length + 1}`;
164
- videoSourceSelect.appendChild(option);
165
- }
 
 
 
166
  });
167
  } catch (err) {
168
- statusElement.textContent = 'Error accessing video devices';
169
- console.error(err);
170
  }
171
  }
172
 
@@ -178,8 +183,9 @@
178
  }
179
  if (!deviceId) {
180
  noVideoElement.style.display = 'block';
 
181
  videoElement.style.display = 'none';
182
- canvasElement.style.display = 'none';
183
  return;
184
  }
185
  const stream = await navigator.mediaDevices.getUserMedia({
@@ -188,11 +194,13 @@
188
  videoElement.srcObject = stream;
189
  videoElement.play();
190
  noVideoElement.style.display = 'none';
 
191
  videoElement.style.display = enableBgRemoval.checked ? 'none' : 'block';
192
- canvasElement.style.display = enableBgRemoval.checked ? 'block' : 'none';
193
  } catch (err) {
194
- statusElement.textContent = 'Error starting video stream';
195
- console.error(err);
 
196
  }
197
  }
198
 
@@ -202,6 +210,16 @@
202
  canvasCtx.save();
203
  canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
204
 
 
 
 
 
 
 
 
 
 
 
205
  if (!enableBgRemoval.checked) {
206
  canvasCtx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
207
  canvasCtx.restore();
@@ -234,12 +252,10 @@
234
  canvasCtx.filter = 'none';
235
  }
236
 
237
- // Apply edge smoothness (simulated via alpha threshold)
238
  canvasCtx.globalCompositeOperation = 'destination-atop';
239
  canvasCtx.globalAlpha = parseFloat(edgeSmoothness.value);
240
  canvasCtx.drawImage(results.segmentationMask, 0, 0, canvasElement.width, canvasElement.height);
241
-
242
- // Draw foreground with brightness adjustment
243
  canvasCtx.globalCompositeOperation = 'source-over';
244
  canvasCtx.filter = `brightness(${fgBrightness.value})`;
245
  canvasCtx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
@@ -277,16 +293,18 @@
277
 
278
  enableBgRemoval.addEventListener('change', () => {
279
  videoElement.style.display = enableBgRemoval.checked ? 'none' : 'block';
280
- canvasElement.style.display = enableBgRemoval.checked ? 'block' : 'none';
281
  });
282
 
283
- showPreview.addEventListener('change', () => {
284
- controlPanel.style.display = showPreview.checked ? 'block' : 'none';
285
  });
286
 
287
  modelQuality.addEventListener('input', () => {
288
  updateSliderLabels();
289
- selfieSegmentation.setOptions({ modelSelection: parseInt(modelQuality.value) });
 
 
290
  });
291
 
292
  edgeSmoothness.addEventListener('input', updateSliderLabels);
@@ -306,7 +324,7 @@
306
  customVideo = document.createElement('video');
307
  customVideo.src = URL.createObjectURL(e.target.files[0]);
308
  customVideo.loop = true;
309
- customVideo.play();
310
  document.getElementById('bgCustomVideo').checked = true;
311
  }
312
  });
@@ -317,29 +335,50 @@
317
  alert('URL copied to clipboard!');
318
  }).catch(err => {
319
  console.error('Failed to copy URL:', err);
 
320
  });
321
  });
322
 
323
  // Process video frames
324
  async function processFrame() {
325
- if (videoElement.srcObject && enableBgRemoval.checked) {
326
- await selfieSegmentation.send({ image: videoElement });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  }
328
  requestAnimationFrame(processFrame);
329
  }
330
 
331
  // Initialize
332
  async function init() {
333
- await initModel();
334
- await populateVideoSources();
335
- updateSliderLabels();
336
- processFrame();
 
 
 
 
 
337
  }
338
 
339
- init().catch(err => {
340
- statusElement.textContent = 'Initialization failed';
341
- console.error(err);
342
- });
343
  </script>
344
  </body>
345
  </html>
 
8
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/selfie_segmentation.js" crossorigin="anonymous"></script>
9
  </head>
10
  <body>
11
+ <video id="videoPreview" autoplay playsinline style="display: none;"></video>
12
+ <canvas id="canvasOutput" width="1920" height="1080"></canvas>
13
+ <button id="previewToggle">Toggle Controls</button>
14
  <div class="card" id="controlPanel">
15
  <h1>OBS AI Background Remover</h1>
16
  <div>
17
  <h2>Live Preview</h2>
 
 
18
  <p id="status">Loading AI Model...</p>
19
+ <p id="noVideo" style="display: none;">No video source selected. Please select a video source or grant webcam access.</p>
20
  </div>
21
 
22
  <div>
 
65
  <input type="checkbox" id="enableBgRemoval" checked>
66
  <label for="enableBgRemoval">Enable Background Removal</label>
67
  </div>
 
 
 
 
68
  <div>
69
  <label for="modelQuality">AI Model Quality</label>
70
  <input type="range" id="modelQuality" min="0" max="1" value="1" step="1">
 
103
  </div>
104
  </div>
105
 
106
+ <p style="position: fixed; bottom: 10px; left: 10px; color: #6b7280;">Made with DeepSite - 🧬 Remix</p>
107
 
108
  <script>
109
  // Initialize elements
 
114
  const noVideoElement = document.getElementById('noVideo');
115
  const videoSourceSelect = document.getElementById('videoSource');
116
  const enableBgRemoval = document.getElementById('enableBgRemoval');
117
+ const previewToggle = document.getElementById('previewToggle');
118
  const controlPanel = document.getElementById('controlPanel');
119
  const processingTimeElement = document.getElementById('processingTime');
120
  const fpsElement = document.getElementById('fps');
 
136
 
137
  // Initialize MediaPipe Selfie Segmentation
138
  async function initModel() {
139
+ try {
140
+ selfieSegmentation = new SelfieSegmentation({
141
+ locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/${file}`
142
+ });
143
+ selfieSegmentation.setOptions({
144
+ modelSelection: parseInt(modelQuality.value),
145
+ selfieMode: true
146
+ });
147
+ selfieSegmentation.onResults(onResults);
148
+ await selfieSegmentation.initialize();
149
+ statusElement.textContent = 'AI Model Loaded';
150
+ } catch (err) {
151
+ statusElement.textContent = 'Failed to load AI model. Check internet connection.';
152
+ console.error('Model initialization error:', err);
153
+ }
154
  }
155
 
156
  // Populate video sources
 
158
  try {
159
  const devices = await navigator.mediaDevices.enumerateDevices();
160
  videoSourceSelect.innerHTML = '<option value="">Select a video source</option>';
161
+ const videoDevices = devices.filter(device => device.kind === 'videoinput');
162
+ if (videoDevices.length === 0) {
163
+ statusElement.textContent = 'No video devices found. Please connect a webcam.';
164
+ return;
165
+ }
166
+ videoDevices.forEach(device => {
167
+ const option = document.createElement('option');
168
+ option.value = device.deviceId;
169
+ option.text = device.label || `Camera ${videoSourceSelect.options.length + 1}`;
170
+ videoSourceSelect.appendChild(option);
171
  });
172
  } catch (err) {
173
+ statusElement.textContent = 'Error accessing video devices. Please grant webcam permissions.';
174
+ console.error('Device enumeration error:', err);
175
  }
176
  }
177
 
 
183
  }
184
  if (!deviceId) {
185
  noVideoElement.style.display = 'block';
186
+ canvasElement.style.display = 'block';
187
  videoElement.style.display = 'none';
188
+ statusElement.textContent = 'Please select a video source.';
189
  return;
190
  }
191
  const stream = await navigator.mediaDevices.getUserMedia({
 
194
  videoElement.srcObject = stream;
195
  videoElement.play();
196
  noVideoElement.style.display = 'none';
197
+ canvasElement.style.display = 'block';
198
  videoElement.style.display = enableBgRemoval.checked ? 'none' : 'block';
199
+ statusElement.textContent = 'AI Model Loaded';
200
  } catch (err) {
201
+ statusElement.textContent = 'Error starting video. Please grant webcam permissions.';
202
+ noVideoElement.style.display = 'block';
203
+ console.error('Video stream error:', err);
204
  }
205
  }
206
 
 
210
  canvasCtx.save();
211
  canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
212
 
213
+ if (!videoElement.srcObject) {
214
+ canvasCtx.fillStyle = '#000';
215
+ canvasCtx.fillRect(0, 0, canvasElement.width, canvasElement.height);
216
+ canvasCtx.fillStyle = '#fff';
217
+ canvasCtx.font = '24px Arial';
218
+ canvasCtx.fillText('No video source. Please select a camera.', 50, 50);
219
+ canvasCtx.restore();
220
+ return;
221
+ }
222
+
223
  if (!enableBgRemoval.checked) {
224
  canvasCtx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
225
  canvasCtx.restore();
 
252
  canvasCtx.filter = 'none';
253
  }
254
 
255
+ // Apply edge smoothness and draw foreground
256
  canvasCtx.globalCompositeOperation = 'destination-atop';
257
  canvasCtx.globalAlpha = parseFloat(edgeSmoothness.value);
258
  canvasCtx.drawImage(results.segmentationMask, 0, 0, canvasElement.width, canvasElement.height);
 
 
259
  canvasCtx.globalCompositeOperation = 'source-over';
260
  canvasCtx.filter = `brightness(${fgBrightness.value})`;
261
  canvasCtx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
 
293
 
294
  enableBgRemoval.addEventListener('change', () => {
295
  videoElement.style.display = enableBgRemoval.checked ? 'none' : 'block';
296
+ canvasElement.style.display = 'block';
297
  });
298
 
299
+ previewToggle.addEventListener('click', () => {
300
+ controlPanel.style.display = controlPanel.style.display === 'block' ? 'none' : 'block';
301
  });
302
 
303
  modelQuality.addEventListener('input', () => {
304
  updateSliderLabels();
305
+ if (selfieSegmentation) {
306
+ selfieSegmentation.setOptions({ modelSelection: parseInt(modelQuality.value) });
307
+ }
308
  });
309
 
310
  edgeSmoothness.addEventListener('input', updateSliderLabels);
 
324
  customVideo = document.createElement('video');
325
  customVideo.src = URL.createObjectURL(e.target.files[0]);
326
  customVideo.loop = true;
327
+ customVideo.play().catch(err => console.error('Custom video playback error:', err));
328
  document.getElementById('bgCustomVideo').checked = true;
329
  }
330
  });
 
335
  alert('URL copied to clipboard!');
336
  }).catch(err => {
337
  console.error('Failed to copy URL:', err);
338
+ statusElement.textContent = 'Failed to copy URL';
339
  });
340
  });
341
 
342
  // Process video frames
343
  async function processFrame() {
344
+ if (videoElement.srcObject && selfieSegmentation && enableBgRemoval.checked) {
345
+ await selfieSegmentation.send({ image: videoElement }).catch(err => {
346
+ console.error('Frame processing error:', err);
347
+ statusElement.textContent = 'Error processing video frame';
348
+ });
349
+ } else {
350
+ const now = performance.now();
351
+ canvasCtx.save();
352
+ canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
353
+ if (videoElement.srcObject) {
354
+ canvasCtx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
355
+ } else {
356
+ canvasCtx.fillStyle = '#000';
357
+ canvasCtx.fillRect(0, 0, canvasElement.width, canvasElement.height);
358
+ canvasCtx.fillStyle = '#fff';
359
+ canvasCtx.font = '24px Arial';
360
+ canvasCtx.fillText('No video source. Please select a camera.', 50, 50);
361
+ }
362
+ canvasCtx.restore();
363
+ updatePerformance(now);
364
  }
365
  requestAnimationFrame(processFrame);
366
  }
367
 
368
  // Initialize
369
  async function init() {
370
+ try {
371
+ await initModel();
372
+ await populateVideoSources();
373
+ updateSliderLabels();
374
+ processFrame();
375
+ } catch (err) {
376
+ statusElement.textContent = 'Initialization failed. Check console for details.';
377
+ console.error('Initialization error:', err);
378
+ }
379
  }
380
 
381
+ init();
 
 
 
382
  </script>
383
  </body>
384
  </html>