face-pose-detect / index.html
ginipick's picture
Update index.html
51584a9 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced Facial Emotion Analysis System</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/face-detection"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
:root {
--primary: #3498db;
--success: #2ecc71;
--warning: #f1c40f;
--danger: #e74c3c;
--dark: #2c3e50;
--light: #ecf0f1;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', system-ui, sans-serif;
}
body {
background: var(--dark);
color: var(--light);
line-height: 1.6;
}
.dashboard {
display: grid;
grid-template-columns: 70% 30%;
gap: 20px;
padding: 20px;
max-width: 1600px;
margin: 0 auto;
}
.main-panel {
background: rgba(255,255,255,0.1);
border-radius: 15px;
padding: 20px;
}
.controls-panel {
background: rgba(255,255,255,0.1);
border-radius: 15px;
padding: 20px;
}
.video-container {
position: relative;
width: 100%;
border-radius: 10px;
overflow: hidden;
background: #000;
}
#video, #canvas {
width: 100%;
transform: scaleX(-1);
}
#canvas {
position: absolute;
top: 0;
left: 0;
}
.settings-group {
margin: 15px 0;
padding: 15px;
background: rgba(255,255,255,0.05);
border-radius: 8px;
}
.settings-group h3 {
color: var(--primary);
margin-bottom: 10px;
}
.control-button {
padding: 10px 20px;
border: none;
border-radius: 5px;
background: var(--primary);
color: white;
cursor: pointer;
transition: all 0.3s ease;
margin: 5px;
width: 100%;
}
.control-button:hover {
opacity: 0.9;
transform: translateY(-2px);
}
.emotion-indicator {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
margin-top: 10px;
}
.emotion-item {
padding: 10px;
background: rgba(255,255,255,0.05);
border-radius: 5px;
text-align: center;
transition: all 0.3s ease;
}
.emotion-item.active {
background: var(--success);
transform: scale(1.05);
}
.stats-container {
margin-top: 20px;
}
.meter {
height: 20px;
background: rgba(255,255,255,0.1);
border-radius: 10px;
overflow: hidden;
margin: 10px 0;
}
.meter-fill {
height: 100%;
background: var(--primary);
transition: width 0.3s ease;
}
.privacy-toggle {
margin: 10px 0;
}
#emotionChart {
margin-top: 20px;
background: rgba(255,255,255,0.05);
border-radius: 8px;
padding: 10px;
}
.fps-counter {
position: absolute;
top: 10px;
right: 10px;
background: rgba(0,0,0,0.7);
padding: 5px 10px;
border-radius: 5px;
font-size: 14px;
}
.detection-settings {
display: grid;
gap: 10px;
margin: 10px 0;
}
.slider-control {
display: flex;
flex-direction: column;
gap: 5px;
}
input[type="range"] {
width: 100%;
background: var(--primary);
}
.face-count {
font-size: 1.2em;
text-align: center;
margin: 10px 0;
color: var(--success);
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.detecting {
animation: pulse 2s infinite;
}
</style>
</head>
<body>
<div class="dashboard">
<div class="main-panel">
<div class="video-container">
<video id="video" playsinline></video>
<canvas id="canvas"></canvas>
<div class="fps-counter">FPS: <span id="fpsCounter">0</span></div>
</div>
<canvas id="emotionChart"></canvas>
</div>
<div class="controls-panel">
<div class="settings-group">
<h3>Detection Controls</h3>
<button id="toggleDetection" class="control-button">Start Detection</button>
<button id="togglePrivacy" class="control-button">Toggle Face Blur</button>
<div class="detection-settings">
<div class="slider-control">
<label>Detection Sensitivity</label>
<input type="range" id="sensitivity" min="0" max="100" value="50">
</div>
<div class="slider-control">
<label>Minimum Face Size</label>
<input type="range" id="minFaceSize" min="20" max="200" value="50">
</div>
</div>
</div>
<div class="settings-group">
<h3>Current Analysis</h3>
<div class="face-count">Detected Faces: <span id="faceCount">0</span></div>
<div class="emotion-indicator">
<div class="emotion-item" data-emotion="happy">😊 Happy</div>
<div class="emotion-item" data-emotion="sad">😢 Sad</div>
<div class="emotion-item" data-emotion="angry">😠 Angry</div>
<div class="emotion-item" data-emotion="neutral">😐 Neutral</div>
<div class="emotion-item" data-emotion="surprised">😲 Surprised</div>
<div class="emotion-item" data-emotion="fearful">😨 Fearful</div>
</div>
</div>
<div class="settings-group">
<h3>Confidence Level</h3>
<div class="meter">
<div id="confidenceMeter" class="meter-fill" style="width: 0%"></div>
</div>
</div>
</div>
</div>
<script>
let model;
let isDetecting = false;
let blurFaces = false;
let lastFrameTime = 0;
let smoothedEmotions = {};
const emotions = ['happy', 'sad', 'angry', 'neutral', 'surprised', 'fearful'];
emotions.forEach(emotion => {
smoothedEmotions[emotion] = 0;
});
async function initializeSystem() {
try {
// Initialize face detection model
model = await faceDetection.createDetector(
faceDetection.SupportedModels.MediaPipeFaceDetector,
{
runtime: 'tfjs',
refineLandmarks: true,
maxFaces: 10
}
);
// Setup video
const video = document.getElementById('video');
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: 640,
height: 480,
facingMode: 'user'
}
});
video.srcObject = stream;
await video.play();
// Setup canvas
const canvas = document.getElementById('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// Initialize emotion chart
initializeEmotionChart();
// Add event listeners
setupEventListeners();
} catch (error) {
console.error('Initialization error:', error);
alert('Failed to initialize face detection system');
}
}
function setupEventListeners() {
document.getElementById('toggleDetection').addEventListener('click', toggleDetection);
document.getElementById('togglePrivacy').addEventListener('click', () => blurFaces = !blurFaces);
document.getElementById('sensitivity').addEventListener('input', updateDetectionSettings);
document.getElementById('minFaceSize').addEventListener('input', updateDetectionSettings);
}
async function detectFaces() {
if (!isDetecting) return;
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Calculate FPS
const now = performance.now();
const fps = 1000 / (now - lastFrameTime);
lastFrameTime = now;
document.getElementById('fpsCounter').textContent = Math.round(fps);
try {
const faces = await model.estimateFaces(video, {
flipHorizontal: false
});
ctx.clearRect(0, 0, canvas.width, canvas.height);
faces.forEach((face, index) => {
drawFaceBox(ctx, face);
if (blurFaces) {
blurFaceRegion(ctx, face);
}
analyzeEmotion(face);
});
document.getElementById('faceCount').textContent = faces.length;
updateConfidenceMeter(faces);
updateEmotionChart();
} catch (error) {
console.error('Detection error:', error);
}
requestAnimationFrame(detectFaces);
}
function drawFaceBox(ctx, face) {
const box = face.box;
ctx.strokeStyle = '#3498db';
ctx.lineWidth = 2;
ctx.strokeRect(box.xMin, box.yMin, box.width, box.height);
// Draw landmarks
if (face.keypoints) {
ctx.fillStyle = '#2ecc71';
face.keypoints.forEach(keypoint => {
ctx.beginPath();
ctx.arc(keypoint.x, keypoint.y, 2, 0, 2 * Math.PI);
ctx.fill();
});
}
}
function blurFaceRegion(ctx, face) {
const box = face.box;
ctx.filter = 'blur(10px)';
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(box.xMin, box.yMin, box.width, box.height);
ctx.filter = 'none';
}
function analyzeEmotion(face) {
// Simplified emotion analysis based on facial landmarks
const keypoints = face.keypoints;
if (!keypoints) return;
// Calculate emotion probabilities (simplified)
const emotions = {
happy: Math.random(),
sad: Math.random(),
angry: Math.random(),
neutral: Math.random(),
surprised: Math.random(),
fearful: Math.random()
};
// Apply smoothing
Object.keys(emotions).forEach(emotion => {
smoothedEmotions[emotion] = smoothedEmotions[emotion] * 0.8 + emotions[emotion] * 0.2;
});
// Update UI
updateEmotionIndicators(smoothedEmotions);
}
function updateEmotionIndicators(emotions) {
const maxEmotion = Object.entries(emotions).reduce((a, b) => a[1] > b[1] ? a : b)[0];
document.querySelectorAll('.emotion-item').forEach(item => {
item.classList.remove('active');
if (item.dataset.emotion === maxEmotion) {
item.classList.add('active');
}
});
}
function updateConfidenceMeter(faces) {
if (faces.length === 0) return;
const avgConfidence = faces.reduce((sum, face) => sum + face.box.score, 0) / faces.length;
document.getElementById('confidenceMeter').style.width = `${avgConfidence * 100}%`;
}
function toggleDetection() {
isDetecting = !isDetecting;
const button = document.getElementById('toggleDetection');
button.textContent = isDetecting ? 'Stop Detection' : 'Start Detection';
button.style.background = isDetecting ? '#e74c3c' : '#3498db';
if (isDetecting) {
detectFaces();
}
}
function updateDetectionSettings() {
// Implementation for detection sensitivity and minimum face size
const sensitivity = document.getElementById('sensitivity').value;
const minFaceSize = document.getElementById('minFaceSize').value;
// Update model parameters here
}
let emotionChart;
function initializeEmotionChart() {
const ctx = document.getElementById('emotionChart').getContext('2d');
emotionChart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: emotions.map(emotion => ({
label: emotion,
data: [],
borderColor: getEmotionColor(emotion),
fill: false
}))
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
max: 1
}
}
}
});
}
function updateEmotionChart() {
const timestamp = new Date().toLocaleTimeString();
emotionChart.data.labels.push(timestamp);
emotions.forEach((emotion, index) => {
emotionChart.data.datasets[index].data.push(smoothedEmotions[emotion]);
});
if (emotionChart.data.labels.length > 30) {
emotionChart.data.labels.shift();
emotionChart.data.datasets.forEach(dataset => dataset.data.shift());
}
emotionChart.update();
}
function getEmotionColor(emotion) {
const colors = {
happy: '#2ecc71',
sad: '#3498db',
angry: '#e74c3c',
neutral: '#95a5a6',
surprised: '#f1c40f',
fearful: '#9b59b6'
};
return colors[emotion] || '#000000';
}
// Initialize the system when page loads
window.onload = initializeSystem;
</script>
</body>
</html>