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

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +59 -355
index.html CHANGED
@@ -5,380 +5,84 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>OBS AI Background Remover</title>
7
  <link rel="stylesheet" href="style.css">
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>
23
- <h2>Background Replacement</h2>
24
- <div>
25
- <input type="radio" name="bgType" id="bgTransparent" value="transparent" checked>
26
- <label for="bgTransparent">Transparent</label>
27
- </div>
28
- <div>
29
- <input type="radio" name="bgType" id="bgBlack" value="black">
30
- <label for="bgBlack">Solid Black</label>
31
- </div>
32
- <div>
33
- <input type="radio" name="bgType" id="bgGray" value="gray">
34
- <label for="bgGray">Solid Gray</label>
35
- </div>
36
- <div>
37
- <input type="radio" name="bgType" id="bgGreen" value="green">
38
- <label for="bgGreen">Solid Green</label>
39
- </div>
40
- <div>
41
- <input type="radio" name="bgType" id="bgCustomImage" value="customImage">
42
- <label for="bgCustomImage">Custom Image</label>
43
- <input type="file" id="customImageInput" accept="image/*">
44
- </div>
45
- <div>
46
- <input type="radio" name="bgType" id="bgCustomVideo" value="customVideo">
47
- <label for="bgCustomVideo">Custom Video</label>
48
- <input type="file" id="customVideoInput" accept="video/*">
49
- </div>
50
- <div>
51
- <input type="radio" name="bgType" id="bgBlur" value="blur">
52
- <label for="bgBlur">Blurred</label>
53
- </div>
54
  </div>
55
 
 
56
  <div>
57
- <h2>Controls</h2>
58
- <div>
59
- <label for="videoSource">Video Source</label>
60
- <select id="videoSource">
61
- <option value="">Select a video source</option>
62
- </select>
63
- </div>
64
- <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">
71
- <span id="modelQualityLabel">High Quality (Slow)</span>
72
- </div>
73
- <div>
74
- <label for="edgeSmoothness">Edge Smoothness</label>
75
- <input type="range" id="edgeSmoothness" min="0" max="1" value="0.5" step="0.1">
76
- <span id="edgeSmoothnessLabel">Medium</span>
77
- </div>
78
- <div>
79
- <label for="bgBlur">Background Blur</label>
80
- <input type="range" id="bgBlur" min="0" max="20" value="0" step="1">
81
- <span id="bgBlurLabel">Off</span>
82
- </div>
83
- <div>
84
- <label for="fgBrightness">Foreground Brightness</label>
85
- <input type="range" id="fgBrightness" min="0.5" max="1.5" value="1" step="0.1">
86
- <span id="fgBrightnessLabel">Normal</span>
87
- </div>
88
  </div>
89
 
 
90
  <div>
91
- <h2>Performance</h2>
92
- <p>Processing Time: <span id="processingTime">0</span> ms</p>
93
  <p>FPS: <span id="fps">0</span></p>
94
  </div>
95
 
 
 
96
  <div>
97
- <h2>OBS Integration</h2>
98
- <p>Add this as a Browser Source in OBS with these settings:</p>
99
- <p>Width: 1920</p>
100
- <p>Height: 1080</p>
101
- <p>Custom CSS: None</p>
102
- <button id="copyUrl">Copy OBS Browser Source URL</button>
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
110
- const videoElement = document.getElementById('videoPreview');
111
- const canvasElement = document.getElementById('canvasOutput');
112
- const canvasCtx = canvasElement.getContext('2d');
113
- const statusElement = document.getElementById('status');
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');
121
- const copyUrlButton = document.getElementById('copyUrl');
122
- const modelQuality = document.getElementById('modelQuality');
123
- const edgeSmoothness = document.getElementById('edgeSmoothness');
124
- const bgBlur = document.getElementById('bgBlur');
125
- const fgBrightness = document.getElementById('fgBrightness');
126
- const modelQualityLabel = document.getElementById('modelQualityLabel');
127
- const edgeSmoothnessLabel = document.getElementById('edgeSmoothnessLabel');
128
- const bgBlurLabel = document.getElementById('bgBlurLabel');
129
- const fgBrightnessLabel = document.getElementById('fgBrightnessLabel');
130
- let selfieSegmentation;
131
- let customImage = null;
132
- let customVideo = null;
133
- let lastFrameTime = performance.now();
134
- let frameCount = 0;
135
- let lastFpsUpdate = performance.now();
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
157
- async function populateVideoSources() {
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
-
178
- // Start video stream
179
- async function startVideo(deviceId) {
180
- try {
181
- if (videoElement.srcObject) {
182
- videoElement.srcObject.getTracks().forEach(track => track.stop());
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({
192
- video: { deviceId: deviceId ? { exact: deviceId } : undefined }
193
- });
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
-
207
- // Process video frames
208
- function onResults(results) {
209
- const now = performance.now();
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();
226
- updatePerformance(now);
227
- return;
228
- }
229
-
230
- // Draw background
231
- const bgType = document.querySelector('input[name="bgType"]:checked').value;
232
- canvasCtx.globalCompositeOperation = 'destination-over';
233
- if (bgType === 'transparent') {
234
- canvasCtx.fillStyle = 'rgba(0, 0, 0, 0)';
235
- canvasCtx.fillRect(0, 0, canvasElement.width, canvasElement.height);
236
- } else if (bgType === 'black') {
237
- canvasCtx.fillStyle = 'black';
238
- canvasCtx.fillRect(0, 0, canvasElement.width, canvasElement.height);
239
- } else if (bgType === 'gray') {
240
- canvasCtx.fillStyle = 'gray';
241
- canvasCtx.fillRect(0, 0, canvasElement.width, canvasElement.height);
242
- } else if (bgType === 'green') {
243
- canvasCtx.fillStyle = 'green';
244
- canvasCtx.fillRect(0, 0, canvasElement.width, canvasElement.height);
245
- } else if (bgType === 'customImage' && customImage) {
246
- canvasCtx.drawImage(customImage, 0, 0, canvasElement.width, canvasElement.height);
247
- } else if (bgType === 'customVideo' && customVideo) {
248
- canvasCtx.drawImage(customVideo, 0, 0, canvasElement.width, canvasElement.height);
249
- } else if (bgType === 'blur') {
250
- canvasCtx.filter = `blur(${bgBlur.value}px)`;
251
- canvasCtx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
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);
262
- canvasCtx.filter = 'none';
263
- canvasCtx.restore();
264
-
265
- updatePerformance(now);
266
- }
267
-
268
- // Update performance metrics
269
- function updatePerformance(now) {
270
- frameCount++;
271
- if (now - lastFpsUpdate > 1000) {
272
- const fps = frameCount / ((now - lastFpsUpdate) / 1000);
273
- fpsElement.textContent = fps.toFixed(1);
274
- frameCount = 0;
275
- lastFpsUpdate = now;
276
- }
277
- processingTimeElement.textContent = (now - lastFrameTime).toFixed(1);
278
- lastFrameTime = now;
279
- }
280
-
281
- // Update slider labels
282
- function updateSliderLabels() {
283
- modelQualityLabel.textContent = modelQuality.value === '0' ? 'Fast (Low Quality)' : 'High Quality (Slow)';
284
- edgeSmoothnessLabel.textContent = edgeSmoothness.value <= 0.3 ? 'Low' : edgeSmoothness.value <= 0.7 ? 'Medium' : 'High';
285
- bgBlurLabel.textContent = bgBlur.value === '0' ? 'Off' : `${bgBlur.value}px`;
286
- fgBrightnessLabel.textContent = fgBrightness.value < 1 ? 'Darker' : fgBrightness.value > 1 ? 'Brighter' : 'Normal';
287
- }
288
-
289
- // Event listeners
290
- videoSourceSelect.addEventListener('change', () => {
291
- startVideo(videoSourceSelect.value);
292
- });
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);
311
- bgBlur.addEventListener('input', updateSliderLabels);
312
- fgBrightness.addEventListener('input', updateSliderLabels);
313
-
314
- document.getElementById('customImageInput').addEventListener('change', (e) => {
315
- if (e.target.files[0]) {
316
- customImage = new Image();
317
- customImage.src = URL.createObjectURL(e.target.files[0]);
318
- document.getElementById('bgCustomImage').checked = true;
319
- }
320
- });
321
-
322
- document.getElementById('customVideoInput').addEventListener('change', (e) => {
323
- if (e.target.files[0]) {
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
- });
331
-
332
- copyUrlButton.addEventListener('click', () => {
333
- const url = window.location.href;
334
- navigator.clipboard.writeText(url).then(() => {
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>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>OBS AI Background Remover</title>
7
  <link rel="stylesheet" href="style.css">
 
8
  </head>
9
  <body>
10
+ <div class="card">
 
 
 
11
  <h1>OBS AI Background Remover</h1>
12
+ <p>Live Preview</p>
13
  <div>
14
+ <video id="live-preview" autoplay style="width: 100%; border-radius: 8px;"></video>
15
+ <canvas id="output-canvas" style="display: none;"></canvas>
16
+ <p id="video-status">No video source selected</p>
17
  </div>
18
 
19
+ <h1>Background Replacement</h1>
20
  <div>
21
+ <label><input type="radio" name="background" value="transparent" checked> Transparent</label>
22
+ <label><input type="radio" name="background" value="solid-black"> Solid Black</label>
23
+ <label><input type="radio" name="background" value="solid-gray"> Solid Gray</label>
24
+ <label><input type="radio" name="background" value="solid-green"> Solid Green</label>
25
+ <label><input type="radio" name="background" value="custom-image"> Custom Image
26
+ <input type="file" id="custom-image-input" accept="image/*">
27
+ </label>
28
+ <label><input type="radio" name="background" value="custom-video"> Custom Video
29
+ <input type="file" id="custom-video-input" accept="video/*">
30
+ </label>
31
+ <label><input type="radio" name="background" value="blurred"> Blurred</label>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  </div>
33
 
34
+ <h1>Controls</h1>
35
  <div>
36
+ <label>Video Source</label>
37
+ <select id="video-source">
38
+ <option value="">Select a video source</option>
39
+ </select>
40
+ </div>
41
+ <div>
42
+ <label><input type="checkbox" id="enable-bg-removal"> Enable Background Removal</label>
43
+ <label><input type="checkbox" id="show-preview" checked> Show Preview</label>
44
+ </div>
45
+
46
+ <h1>Settings</h1>
47
+ <div>
48
+ <label>AI Model Quality</label>
49
+ <select id="model-quality">
50
+ <option value="fast">Fast (Low Quality)</option>
51
+ <option value="balanced" selected>Balanced</option>
52
+ <option value="high">High Quality (Slow)</option>
53
+ </select>
54
+ </div>
55
+ <div>
56
+ <label>Edge Smoothness</label>
57
+ <input type="range" id="edge-smoothness" min="0" max="10" value="5">
58
+ </div>
59
+ <div>
60
+ <label>Background Blur</label>
61
+ <input type="range" id="background-blur" min="0" max="20" value="0">
62
+ </div>
63
+ <div>
64
+ <label>Foreground Brightness</label>
65
+ <input type="range" id="foreground-brightness" min="0.5" max="1.5" step="0.1" value="1">
 
66
  </div>
67
 
68
+ <h1>Performance</h1>
69
  <div>
70
+ <p>Processing Time: <span id="processing-time">0 ms</span></p>
 
71
  <p>FPS: <span id="fps">0</span></p>
72
  </div>
73
 
74
+ <h1>OBS Integration</h1>
75
+ <p>Add this as a Browser Source in OBS with these settings:</p>
76
  <div>
77
+ <p>Width: <span>1920</span></p>
78
+ <p>Height: <span>1080</span></p>
79
+ <p>Custom CSS: <span>None</span></p>
80
+ </div>
81
+ <div>
82
+ <button id="copy-url">Copy OBS Browser Source URL</button>
83
  </div>
84
  </div>
85
 
86
+ <script src="script.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  </body>
88
  </html>