|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Real-Time Object Detection</title> |
|
<style> |
|
body { |
|
margin: 0; |
|
padding: 0; |
|
display: flex; |
|
justify-content: center; |
|
align-items: center; |
|
height: 100vh; |
|
background-color: #000; |
|
} |
|
#video { |
|
width: 320px; |
|
height: 240px; |
|
display: block; |
|
background-color: #000; |
|
} |
|
#canvas { |
|
width: 320px; |
|
height: 240px; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
pointer-events: none; |
|
} |
|
.overlay { |
|
position: absolute; |
|
top: 10px; |
|
left: 10px; |
|
color: white; |
|
font-size: 16px; |
|
background-color: rgba(0, 0, 0, 0.5); |
|
padding: 10px; |
|
border-radius: 5px; |
|
pointer-events: none; |
|
} |
|
#loading { |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
color: white; |
|
font-size: 24px; |
|
background-color: rgba(0, 0, 0, 0.7); |
|
padding: 20px; |
|
border-radius: 5px; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
|
|
<video id="video" width="320" height="240" autoplay muted></video> |
|
<canvas id="canvas" width="320" height="240"></canvas> |
|
<div id="overlay" class="overlay"></div> |
|
<div id="loading" style="display: none;">Loading model...</div> |
|
|
|
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"></script> |
|
|
|
<script> |
|
const video = document.getElementById('video'); |
|
const canvas = document.getElementById('canvas'); |
|
const ctx = canvas.getContext('2d'); |
|
const overlay = document.getElementById('overlay'); |
|
const loading = document.getElementById('loading'); |
|
|
|
let model; |
|
let frameCount = 0; |
|
const detectionInterval = 2; |
|
|
|
|
|
navigator.mediaDevices.getUserMedia({ video: { width: 320, height: 240 } }) |
|
.then((stream) => { |
|
video.srcObject = stream; |
|
loadModel(); |
|
}) |
|
.catch((err) => { |
|
console.error('Error accessing webcam: ', err); |
|
}); |
|
|
|
|
|
async function loadModel() { |
|
try { |
|
loading.style.display = 'block'; |
|
model = await cocoSsd.load(); |
|
console.log('COCO-SSD model loaded!'); |
|
loading.style.display = 'none'; |
|
startDetection(); |
|
} catch (err) { |
|
console.error('Error loading model:', err); |
|
loading.innerHTML = 'Error loading model. Please try again.'; |
|
} |
|
} |
|
|
|
|
|
async function detectFrame() { |
|
if (!model) return; |
|
|
|
frameCount++; |
|
|
|
|
|
if (frameCount % detectionInterval !== 0) { |
|
requestAnimationFrame(detectFrame); |
|
return; |
|
} |
|
|
|
frameCount = 0; |
|
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
|
|
|
|
ctx.drawImage(video, 0, 0, canvas.width, canvas.height); |
|
|
|
|
|
const predictions = await model.detect(video); |
|
|
|
|
|
overlay.innerHTML = ''; |
|
|
|
predictions.forEach(prediction => { |
|
|
|
ctx.beginPath(); |
|
ctx.rect( |
|
prediction.bbox[0], |
|
prediction.bbox[1], |
|
prediction.bbox[2], |
|
prediction.bbox[3] |
|
); |
|
ctx.lineWidth = 2; |
|
ctx.strokeStyle = 'red'; |
|
ctx.fillStyle = 'red'; |
|
ctx.stroke(); |
|
|
|
|
|
ctx.fillText( |
|
`${prediction.class} (${Math.round(prediction.score * 100)}%)`, |
|
prediction.bbox[0], |
|
prediction.bbox[1] > 10 ? prediction.bbox[1] - 5 : 10 |
|
); |
|
|
|
|
|
overlay.innerHTML += `<p>${prediction.class} - ${Math.round(prediction.score * 100)}%</p>`; |
|
}); |
|
|
|
|
|
requestAnimationFrame(detectFrame); |
|
} |
|
|
|
|
|
function startDetection() { |
|
detectFrame(); |
|
} |
|
</script> |
|
|
|
</body> |
|
</html> |
|
|