Spaces:
Running
Running
Download movement-detection.html from YOUSEF2434/Computer-Vision-Lab: direct link, hf CLI and curl.
- Browser
- Download file 7.18 kB
-
https://huggingface.co/spaces/YOUSEF2434/Computer-Vision-Lab/resolve/main/movement-detection.html
- Command line
-
hf download hf://spaces/YOUSEF2434/Computer-Vision-Lab/movement-detection.html
-
curl -L -o movement-detection.html https://huggingface.co/spaces/YOUSEF2434/Computer-Vision-Lab/resolve/main/movement-detection.html
7.18 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>🕵️♂️ Secret Agent Motion Detector</title> | |
| <style> | |
| /* CSS: Making it look cool */ | |
| body { | |
| background-color: #1a1a1a; /* Dark spy background */ | |
| color: #00ff41; /* Hacker green text */ | |
| font-family: 'Courier New', Courier, monospace; /* Typewriter font */ | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| min-height: 100vh; | |
| margin: 0; | |
| padding: 20px; | |
| } | |
| h1 { | |
| text-shadow: 0 0 10px #00ff41; | |
| margin-bottom: 10px; | |
| } | |
| .instructions { | |
| background: #222; | |
| padding: 15px; | |
| border-radius: 10px; | |
| border: 1px solid #444; | |
| max-width: 600px; | |
| text-align: center; | |
| margin-bottom: 20px; | |
| color: #ddd; | |
| } | |
| /* The canvas where the magic happens */ | |
| #canvasFinal { | |
| border: 4px solid #00ff41; | |
| border-radius: 8px; | |
| box-shadow: 0 0 20px rgba(0, 255, 65, 0.3); | |
| background-color: #000; | |
| max-width: 100%; | |
| display: none; /* Hidden until camera starts */ | |
| } | |
| /* Hide the raw video stream and processing canvas */ | |
| #camStream, #canvasHidden { | |
| display: none; | |
| } | |
| button { | |
| background-color: #00ff41; | |
| color: #000; | |
| border: none; | |
| padding: 15px 30px; | |
| font-size: 1.2rem; | |
| font-weight: bold; | |
| font-family: inherit; | |
| cursor: pointer; | |
| border-radius: 5px; | |
| margin-bottom: 20px; | |
| transition: all 0.3s; | |
| } | |
| button:hover { | |
| background-color: #fff; | |
| box-shadow: 0 0 15px #fff; | |
| } | |
| .status { | |
| margin-top: 10px; | |
| font-size: 0.9rem; | |
| color: #888; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <button id="startBtn" onclick="startSpyCamera()">🚀 Activate Movement Detection Mode</button> | |
| <p class="status" id="statusText">Waiting for activation...</p> | |
| <!-- These are the HTML elements that handle the video --> | |
| <video id="camStream" playsinline autoplay></video> | |
| <canvas id="canvasHidden"></canvas> | |
| <canvas id="canvasFinal"></canvas> | |
| <script> | |
| // JAVASCRIPT: The Brains of the Operation | |
| // 1. Grab our HTML elements so we can control them | |
| const video = document.getElementById('camStream'); | |
| const hiddenCanvas = document.getElementById('canvasHidden'); | |
| const finalCanvas = document.getElementById('canvasFinal'); | |
| const startBtn = document.getElementById('startBtn'); | |
| const statusText = document.getElementById('statusText'); | |
| // Contexts are like the "paintbrushes" for the canvas | |
| const hiddenCtx = hiddenCanvas.getContext('2d'); | |
| const finalCtx = finalCanvas.getContext('2d'); | |
| // We need a place to store the "previous" frame to compare against | |
| let previousFrameData = null; | |
| async function startSpyCamera() { | |
| try { | |
| // 2. Ask the browser for permission to use the camera | |
| const stream = await navigator.mediaDevices.getUserMedia({ video: true }); | |
| // Connect the camera stream to our hidden video element | |
| video.srcObject = stream; | |
| // Update the UI | |
| statusText.innerText = "System Active. Scanning for movement..."; | |
| startBtn.style.display = "none"; // Hide button | |
| finalCanvas.style.display = "block"; // Show screen | |
| // Start the loop! | |
| requestAnimationFrame(processVideo); | |
| } catch (err) { | |
| // If they say no or don't have a camera | |
| statusText.innerText = "⚠️ Error: Could not access camera. Please allow permission."; | |
| console.error(err); | |
| } | |
| } | |
| function processVideo() { | |
| // Check if the video is ready and playing | |
| if (video.readyState === video.HAVE_ENOUGH_DATA) { | |
| // Set canvas sizes to match the video size | |
| const width = video.videoWidth; | |
| const height = video.videoHeight; | |
| hiddenCanvas.width = width; | |
| hiddenCanvas.height = height; | |
| finalCanvas.width = width; | |
| finalCanvas.height = height; | |
| // 3. Draw the current video frame onto the hidden canvas | |
| hiddenCtx.drawImage(video, 0, 0, width, height); | |
| // 4. Get the pixel data (the raw numbers for every color) | |
| const currentFrame = hiddenCtx.getImageData(0, 0, width, height); | |
| const currentData = currentFrame.data; | |
| // Create a new image for the result | |
| const outputImage = finalCtx.createImageData(width, height); | |
| const outputData = outputImage.data; | |
| // 5. THE ALGORITHM: Compare this frame to the previous one | |
| if (previousFrameData) { | |
| const prevData = previousFrameData.data; | |
| // Loop through every pixel (pixels are groups of 4: Red, Green, Blue, Alpha) | |
| for (let i = 0; i < currentData.length; i += 4) { | |
| // This math calculates the difference between old and new | |
| // If pixels are the same, it turns GREY. | |
| // If they are different, it creates high contrast colors. | |
| outputData[i] = 0.5 * (255 - currentData[i]) + 0.5 * prevData[i]; // Red | |
| outputData[i+1] = 0.5 * (255 - currentData[i+1]) + 0.5 * prevData[i+1]; // Green | |
| outputData[i+2] = 0.5 * (255 - currentData[i+2]) + 0.5 * prevData[i+2]; // Blue | |
| outputData[i+3] = 255; // Alpha (Opacity) is always 100% | |
| } | |
| // Draw the result to the main screen | |
| finalCtx.putImageData(outputImage, 0, 0); | |
| } | |
| // 6. Save the current frame to be the "previous" frame for next time | |
| // We clone it so we don't overwrite it immediately | |
| previousFrameData = new ImageData( | |
| new Uint8ClampedArray(currentFrame.data), | |
| currentFrame.width, | |
| currentFrame.height | |
| ); | |
| } | |
| // Repeat this function as fast as the screen can refresh | |
| requestAnimationFrame(processVideo); | |
| } | |
| </script> | |
| </body> | |
| </html> | |