Spaces:
Sleeping
Sleeping
File size: 4,242 Bytes
0930008 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MicroMind Vision Sentinel</title>
<style>
body { font-family: sans-serif; background: #111; color: white; text-align: center; }
#container { position: relative; display: inline-block; margin-top: 20px; }
video { border: 2px solid #333; border-radius: 8px; }
canvas { position: absolute; top: 0; left: 0; pointer-events: none; }
#status { margin: 10px; font-weight: bold; color: #0f0; }
#config { color: #888; font-size: 0.9em; }
</style>
</head>
<body>
<h1>👁️ MicroMind Vision Sentinel</h1>
<div id="status">System Status: CONNECTING...</div>
<div id="config">Target: Unknown | Conf: 0.0</div>
<div id="container">
<video id="video" width="640" height="480" autoplay playsinline></video>
<canvas id="canvas" width="640" height="480"></canvas>
</div>
<script>
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const statusEl = document.getElementById('status');
const configEl = document.getElementById('config');
// 1. Start Webcam
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => { video.srcObject = stream; })
.catch(err => { console.error("Camera Error:", err); statusEl.innerText = "CAMERA ERROR"; statusEl.style.color = "red"; });
// 2. Processing Loop
setInterval(() => {
if (video.readyState === video.HAVE_ENOUGH_DATA) {
// Draw video frame to hidden canvas to convert to blob
const tempCanvas = document.createElement('canvas');
tempCanvas.width = video.videoWidth;
tempCanvas.height = video.videoHeight;
tempCanvas.getContext('2d').drawImage(video, 0, 0);
tempCanvas.toBlob(blob => {
const formData = new FormData();
formData.append('image', blob);
// Send to Python Backend
fetch('/process_frame', { method: 'POST', body: formData })
.then(res => res.json())
.then(data => {
// Update UI
statusEl.innerText = `STATUS: ${data.status}`;
statusEl.style.color = data.status === "ARMED" ? "#0f0" : "#fa0";
if (data.target) {
configEl.innerText = `Target: ${data.target.toUpperCase()}`;
}
// Clear previous drawings
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw detections
if (data.detections) {
data.detections.forEach(det => {
const [x1, y1, x2, y2] = det.bbox;
// Scale coordinates if video size differs from canvas
const scaleX = canvas.width / video.videoWidth;
const scaleY = canvas.height / video.videoHeight;
ctx.strokeStyle = '#00FF00';
ctx.lineWidth = 3;
ctx.strokeRect(x1 * scaleX, y1 * scaleY, (x2-x1) * scaleX, (y2-y1) * scaleY);
ctx.fillStyle = '#00FF00';
ctx.font = '16px Arial';
ctx.fillText(`${det.label} (${det.confidence})`, x1 * scaleX, (y1 * scaleY) - 5);
});
}
})
.catch(err => console.error("API Error", err));
}, 'image/jpeg');
}
}, 500); // Process every 500ms (2 FPS)
</script>
</body>
</html> |