Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>MediaPipe Face Mesh</title> | |
<style> | |
body { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
height: 100vh; | |
margin: 0; | |
background-color: #000; | |
} | |
video { | |
display: none; | |
} | |
canvas { | |
position: absolute; | |
top: 0; | |
left: 0; | |
z-index: 1; | |
} | |
</style> | |
</head> | |
<body> | |
<video id="video" autoplay playsinline></video> | |
<canvas id="canvas"></canvas> | |
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/face_mesh.js"></script> | |
<script> | |
const videoElement = document.getElementById('video'); | |
const canvasElement = document.getElementById('canvas'); | |
const canvasCtx = canvasElement.getContext('2d'); | |
// Create a FaceMesh instance | |
const faceMesh = new FaceMesh({ | |
locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${file}` | |
}); | |
faceMesh.onResults(onFaceMeshResults); | |
// Initialize camera | |
async function initCamera() { | |
try { | |
const stream = await navigator.mediaDevices.getUserMedia({ | |
video: true | |
}); | |
videoElement.srcObject = stream; | |
const camera = new Camera(videoElement, { | |
onFrame: async () => { | |
await faceMesh.send({ image: videoElement }); | |
}, | |
width: 640, | |
height: 480 | |
}); | |
camera.start(); | |
} catch (error) { | |
console.error('Error accessing the camera:', error); | |
} | |
} | |
initCamera(); | |
function onFaceMeshResults(results) { | |
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height); | |
canvasElement.width = videoElement.videoWidth; | |
canvasElement.height = videoElement.videoHeight; | |
// Draw the video | |
canvasCtx.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height); | |
// Draw face mesh | |
if (results.multiFaceLandmarks) { | |
results.multiFaceLandmarks.forEach(landmarks => { | |
const keypoints = landmarks.map(landmark => ({ | |
x: landmark.x * canvasElement.width, | |
y: landmark.y * canvasElement.height | |
})); | |
// Draw keypoints | |
canvasCtx.fillStyle = 'red'; | |
keypoints.forEach(point => { | |
canvasCtx.beginPath(); | |
canvasCtx.arc(point.x, point.y, 1, 0, 2 * Math.PI); | |
canvasCtx.fill(); | |
}); | |
}); | |
} | |
} | |
</script> | |
</body> | |
</html> | |