开发课堂学生专注度分析程序,捕捉学生面部表情和动作,分析专注程度,帮助老师调整教学。

我将按照代码生成场景准则,为你构建一个基于JavaScript的课堂学生专注度分析程序。这个系统采用模块化设计,结合智能视觉技术实现实时专注度评估。

// ====================== 视频捕获模块 (videoCapture.js) ======================

/**

* 视频捕获模块 - 负责获取摄像头视频流

*/

export class VideoCapture {

constructor() {

this.videoElement = null;

this.stream = null;

}

/**

* 初始化摄像头

* @returns {Promise<HTMLVideoElement>} 视频元素

*/

async initCamera() {

try {

// 获取摄像头权限

this.stream = await navigator.mediaDevices.getUserMedia({

video: { width: 640, height: 480 }

});

// 创建视频元素

this.videoElement = document.createElement('video');

this.videoElement.srcObject = this.stream;

this.videoElement.autoplay = true;

this.videoElement.playsInline = true;

// 等待视频加载完成

await new Promise((resolve) => {

this.videoElement.onloadedmetadata = resolve;

});

return this.videoElement;

} catch (error) {

throw new Error(`摄像头初始化失败: ${error.message}`);

}

}

/**

* 停止视频流

*/

stopCamera() {

if (this.stream) {

this.stream.getTracks().forEach(track => track.stop());

this.stream = null;

}

if (this.videoElement) {

this.videoElement.srcObject = null;

this.videoElement = null;

}

}

}

// ====================== 面部检测模块 (faceDetection.js) ======================

import * as tf from '@tensorflow/tfjs';

import { FaceLandmarksDetector } from '@tensorflow-models/face-landmarks-detection';

/**

* 面部检测模块 - 使用TensorFlow.js进行面部特征检测

*/

export class FaceDetector {

constructor() {

this.model = null;

this.isModelLoaded = false;

}

/**

* 加载面部检测模型

* @returns {Promise<void>}

*/

async loadModel() {

try {

this.model = await FaceLandmarksDetector.load(

FaceLandmarksDetector.SupportedPackages.mediapipeFacemesh

);

this.isModelLoaded = true;

console.log('面部检测模型加载完成');

} catch (error) {

throw new Error(`模型加载失败: ${error.message}`);

}

}

/**

* 检测面部特征

* @param {HTMLVideoElement} video - 视频元素

* @returns {Promise<Object|null>} 面部特征数据

*/

async detectFace(video) {

if (!this.isModelLoaded) {

throw new Error('模型未加载');

}

try {

const predictions = await this.model.estimateFaces({

input: video,

returnTensors: false,

flipHorizontal: false,

predictIrises: true

});

if (predictions.length === 0) {

return null; // 未检测到面部

}

const face = predictions[0];

return {

landmarks: face.keypoints,

boundingBox: face.box,

confidence: face.confidence

};

} catch (error) {

console.error('面部检测错误:', error);

return null;

}

}

/**

* 计算眼睛闭合程度 (0-1, 1表示完全闭合)

* @param {Array} landmarks - 面部关键点

* @returns {number} 眼睛闭合程度

*/

calculateEyeClosure(landmarks) {

// 左眼关键点索引 (MediaPipe FaceMesh)

const leftEyeUpper = landmarks[159];

const leftEyeLower = landmarks[145];

const rightEyeUpper = landmarks[386];

const rightEyeLower = landmarks[374];

// 计算左右眼垂直距离

const leftEyeDist = Math.abs(leftEyeUpper.y - leftEyeLower.y);

const rightEyeDist = Math.abs(rightEyeUpper.y - rightEyeLower.y);

// 平均眼距作为基准 (经验值)

const avgEyeDist = 0.02;

// 归一化闭合程度

const leftClosure = Math.min(leftEyeDist / avgEyeDist, 1);

const rightClosure = Math.min(rightEyeDist / avgEyeDist, 1);

return (leftClosure + rightClosure) / 2;

}

/**

* 计算头部偏转角度 (度)

* @param {Array} landmarks - 面部关键点

* @returns {Object} 头部姿态 {pitch, yaw, roll}

*/

calculateHeadPose(landmarks) {

// 使用鼻尖、下巴、左右眼角计算头部姿态

const noseTip = landmarks[1];

const chin = landmarks[175];

const leftEye = landmarks[33];

const rightEye = landmarks[263];

// 简化的姿态估计 (实际应用中可使用solvePnP算法)

const dx = rightEye.x - leftEye.x;

const dy = rightEye.y - leftEye.y;

const dz = rightEye.z - leftEye.z;

const yaw = Math.atan2(dy, dx) * (180 / Math.PI);

const pitch = Math.atan2(dz, Math.sqrt(dx*dx + dy*dy)) * (180 / Math.PI);

return { pitch: Math.abs(pitch), yaw: Math.abs(yaw), roll: 0 };

}

}

// ====================== 专注度计算模块 (attentionCalculator.js) ======================

/**

* 专注度计算模块 - 基于面部特征计算专注度分数

*/

export class AttentionCalculator {

constructor() {

// 专注度评估参数

this.params = {

eyeClosureThreshold: 0.3, // 眼睛闭合阈值 (超过此值视为闭眼)

headPoseThreshold: 25, // 头部偏转阈值 (度)

distractionDuration: 3000, // 分心持续时间阈值 (毫秒)

weights: {

eyeContact: 0.4, // 眼神接触权重

headStability: 0.3, // 头部稳定性权重

facialExpression: 0.3 // 面部表情权重

}

};

this.distractionStartTime = null;

this.currentAttentionScore = 100;

}

/**

* 计算实时专注度分数 (0-100)

* @param {Object} faceData - 面部特征数据

* @param {number} timestamp - 当前时间戳

* @returns {number} 专注度分数

*/

calculateAttention(faceData, timestamp) {

if (!faceData) {

// 未检测到面部,持续扣分

return Math.max(0, this.currentAttentionScore - 2);

}

const { landmarks } = faceData;

// 1. 眼神接触评估 (40%)

const eyeClosure = this.calculateEyeClosure(landmarks);

const eyeContactScore = eyeClosure < this.params.eyeClosureThreshold ? 100 :

Math.max(0, 100 - (eyeClosure - this.params.eyeClosureThreshold) * 200);

// 2. 头部稳定性评估 (30%)

const headPose = this.calculateHeadPose(landmarks);

const headStabilityScore = (headPose.pitch < this.params.headPoseThreshold &&

headPose.yaw < this.params.headPoseThreshold) ? 100 :

Math.max(0, 100 - (Math.max(headPose.pitch, headPose.yaw) - 20) * 2);

// 3. 面部表情评估 (30%) - 简化为中性表情为专注

const expressionScore = this.evaluateFacialExpression(landmarks);

// 综合计算

const attentionScore = (

eyeContactScore * this.params.weights.eyeContact +

headStabilityScore * this.params.weights.headStability +

expressionScore * this.params.weights.facialExpression

);

// 分心状态跟踪

this.trackDistraction(attentionScore < 60, timestamp);

return Math.round(Math.max(0, Math.min(100, attentionScore)));

}

/**

* 跟踪分心持续时间

* @param {boolean} isDistracted - 是否分心

* @param {number} timestamp - 当前时间戳

*/

trackDistraction(isDistracted, timestamp) {

if (isDistracted) {

if (!this.distractionStartTime) {

this.distractionStartTime = timestamp;

} else if (timestamp - this.distractionStartTime > this.params.distractionDuration) {

// 持续分心超过阈值,额外扣分

this.currentAttentionScore = Math.max(0, this.currentAttentionScore - 5);

}

} else {

this.distractionStartTime = null;

// 恢复专注,缓慢加分

this.currentAttentionScore = Math.min(100, this.currentAttentionScore + 1);

}

}

/**

* 评估面部表情 (简化版)

* @param {Array} landmarks - 面部关键点

* @returns {number} 表情分数 (0-100)

*/

evaluateFacialExpression(landmarks) {

// 实际应用中可使用表情识别模型

// 这里简化为中性表情检测 (嘴角、眉毛位置)

const mouthCornerLeft = landmarks[61];

const mouthCornerRight = landmarks[291];

const eyebrowInnerLeft = landmarks[107];

const eyebrowInnerRight = landmarks[336];

// 计算嘴角和眉毛的水平偏移

const mouthSpread = Math.abs(mouthCornerLeft.x - mouthCornerRight.x);

const browHeight = (eyebrowInnerLeft.y + eyebrowInnerRight.y) / 2;

const eyeLevel = (landmarks[33].y + landmarks[263].y) / 2;

const browElevation = Math.abs(browHeight - eyeLevel);

// 中性表情评分

let expressionScore = 80; // 基础分

if (mouthSpread > 0.1) expressionScore -= 20; // 笑或说话

if (browElevation > 0.02) expressionScore -= 15; // 惊讶或困惑

return Math.max(0, expressionScore);

}

/**

* 计算眼睛闭合程度 (内部方法)

*/

calculateEyeClosure(landmarks) {

const leftEyeUpper = landmarks[159];

const leftEyeLower = landmarks[145];

const rightEyeUpper = landmarks[386];

const rightEyeLower = landmarks[374];

const leftDist = Math.abs(leftEyeUpper.y - leftEyeLower.y);

const rightDist = Math.abs(rightEyeUpper.y - rightEyeLower.y);

const avgDist = (leftDist + rightDist) / 2;

// 归一化 (经验值)

return Math.min(avgDist / 0.025, 1);

}

/**

* 计算头部姿态 (内部方法)

*/

calculateHeadPose(landmarks) {

const noseTip = landmarks[1];

const leftEye = landmarks[33];

const rightEye = landmarks[263];

const dx = rightEye.x - leftEye.x;

const dy = rightEye.y - leftEye.y;

const dz = (rightEye.z || 0) - (leftEye.z || 0);

const yaw = Math.atan2(dy, dx) * (180 / Math.PI);

const pitch = Math.atan2(dz, Math.sqrt(dx*dx + dy*dy)) * (180 / Math.PI);

return { pitch: Math.abs(pitch), yaw: Math.abs(yaw), roll: 0 };

}

}

// ====================== UI渲染模块 (uiRenderer.js) ======================

/**

* UI渲染模块 - 负责界面展示和交互

*/

export class UIRenderer {

constructor() {

this.container = null;

this.videoElement = null;

this.canvasElement = null;

this.statsElement = null;

this.initUI();

}

/**

* 初始化UI界面

*/

initUI() {

// 创建主容器

this.container = document.createElement('div');

this.container.style.cssText = `

position: fixed; top: 0; left: 0; width: 100%; height: 100%;

background: #f0f2f5; font-family: Arial, sans-serif; z-index: 9999;

`;

// 视频容器

const videoContainer = document.createElement('div');

videoContainer.style.cssText = 'position: relative; width: 640px; margin: 20px auto;';

// 视频元素

this.videoElement = document.createElement('video');

this.videoElement.style.cssText = 'width: 100%; border-radius: 8px; background: #000;';

// 画布元素 (用于绘制检测结果)

this.canvasElement = document.createElement('canvas');

this.canvasElement.style.cssText = 'position: absolute; top: 0; left: 0; pointer-events: none;';

this.canvasElement.width = 640;

this.canvasElement.height = 480;

videoContainer.appendChild(this.videoElement);

videoContainer.appendChild(this.canvasElement);

// 统计信息面板

this.statsElement = document.createElement('div');

this.statsElement.style.cssText = `

width: 640px; margin: 10px auto; padding: 15px;

background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);

`;

// 专注度显示

this.attentionDisplay = document.createElement('div');

this.attentionDisplay.style.cssText = `

font-size: 24px; font-weight: bold; margin-bottom: 10px;

color: ${this.getAttentionColor(100)};

`;

this.attentionDisplay.textContent = '专注度: --%';

// 状态指示器

this.statusIndicator = document.createElement('div');

this.statusIndicator.style.cssText = 'font-size: 14px; color: #666;';

this.statusIndicator.textContent = '状态: 初始化中...';

this.statsElement.appendChild(this.attentionDisplay);

this.statsElement.appendChild(this.statusIndicator);

// 添加到容器

this.container.appendChild(videoContainer);

this.container.appendChild(this.statsElement);

// 添加到页面

document.body.appendChild(this.container);

}

/**

* 更新视频画面

* @param {HTMLVideoElement} video - 视频元素

*/

updateVideo(video) {

this.videoElement.srcObject = video.srcObject;

this.canvasElement.width = video.videoWidth;

this.canvasElement.height = video.videoHeight;

}

/**

* 更新专注度显示

* @param {number} score - 专注度分数 (0-100)

*/

updateAttentionScore(score) {

this.attentionDisplay.textContent = `专注度: ${score}%`;

this.attentionDisplay.style.color = this.getAttentionColor(score);

}

/**

* 更新状态信息

* @param {string} status - 状态文本

* @param {string} color - 状态颜色

*/

updateStatus(status, color = '#333') {

this.statusIndicator.textContent = `状态: ${status}`;

this.statusIndicator.style.color = color;

}

/**

* 绘制面部检测结果

* @param {Object} faceData - 面部特征数据

*/

drawFaceDetection(faceData) {

const ctx = this.canvasElement.getContext('2d');

ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);

if (!faceData) return;

const { landmarks, boundingBox } = faceData;

// 绘制边界框

ctx.strokeStyle = '#00ff00';

ctx.lineWidth = 2;

ctx.strokeRect(

boundingBox.topLeft[0], boundingBox.topLeft[1],

boundingBox.bottomRight[0] - boundingBox.topLeft[0],

boundingBox.bottomRight[1] - boundingBox.topLeft[1]

);

// 绘制关键点 (简化)

ctx.fillStyle = '#ff0000';

for (let i = 0; i < Math.min(landmarks.length, 10); i++) {

const point = landmarks[i];

ctx.beginPath();

ctx.arc(point.x, point.y, 2, 0, 2 * Math.PI);

ctx.fill();

}

}

/**

* 根据专注度获取颜色

* @param {number} score - 专注度分数

* @returns {string} 颜色代码

*/

getAttentionColor(score) {

if (score >= 80) return '#28a745'; // 绿色 - 专注

if (score >= 60) return '#ffc107'; // 黄色 - 一般

return '#dc3545'; // 红色 - 不专注

}

/**

* 显示错误信息

* @param {string} message - 错误信息

*/

showError(message) {

this.updateStatus(message, '#dc3545');

}

/**

* 移除UI界面

*/

destroy() {

if (this.container && this.container.parentNode) {

this.container.parentNode.removeChild(this.container);

}

}

}

// ====================== 主程序模块 (main.js) ======================

import { VideoCapture } from './videoCapture.js';

import { FaceDetector } from './faceDetection.js';

import { AttentionCalculator } from './attentionCalculator.js';

import { UIRenderer } from './uiRenderer.js';

/**

* 主程序 - 协调各模块工作

*/

class AttentionAnalysisApp {

constructor() {

this.videoCapture = new VideoCapture();

this.faceDetector = new FaceDetector();

this.attentionCalculator = new AttentionCalculator();

this.uiRenderer = new UIRenderer();

this.animationId = null;

this.startTime = Date.now();

}

/**

* 启动应用程序

*/

async start() {

try {

// 1. 初始化摄像头

this.uiRenderer.updateStatus('正在启动摄像头...', '#007bff');

const video = await this.videoCapture.initCamera();

this.uiRenderer.updateVideo(video);

// 2. 加载面部检测模型

this.uiRenderer.updateStatus('正在加载AI模型...', '#007bff');

await this.faceDetector.loadModel();

// 3. 启动实时分析循环

this.uiRenderer.updateStatus('分析中...', '#28a745');

this.startAnalysisLoop(video);

} catch (error) {

console.error('启动失败:', error);

this.uiRenderer.showError(error.message);

}

}

/**

* 启动实时分析循环

* @param {HTMLVideoElement} video - 视频元素

*/

startAnalysisLoop(video) {

const analyzeFrame = async () => {

try {

// 检测面部

const faceData = await this.faceDetector.detectFace(video);

// 计算专注度

const currentTime = Date.now();

const attentionScore = this.attentionCalculator.calculateAttention(faceData, currentTime);

// 更新UI

this.uiRenderer.updateAttentionScore(attentionScore);

this.uiRenderer.drawFaceDetection(faceData);

// 继续下一帧

this.animationId = requestAnimationFrame(analyzeFrame);

} catch (error) {

console.error('分析错误:', error);

this.uiRenderer.showError('分析过程出错');

}

};

// 开始循环

analyzeFrame();

}

/**

* 停止应用程序

*/

stop() {

if (this.animationId) {

cancelAnimationFrame(this.animationId);

this.animationId = null;

}

this.videoCapture.stopCamera();

this.uiRenderer.destroy();

console.log('应用程序已停止');

}

}

// 页面加载完成后启动应用

document.addEventListener('DOMContentLoaded', () => {

const app = new AttentionAnalysisApp();

// 添加键盘快捷键 (ESC停止)

document.addEventListener('keydown', (e) => {

if (e.key === 'Escape') {

app.stop();

}

});

// 启动应用

app.start();

});

README文件

课堂学生专注度分析系统

📖 项目简介

本项目是基于JavaScript的智能视觉技术应用,通过分析学生的面部表情和动作来评估课堂专注度。系统集成TensorFlow.js面部检测模型,实时计算专注度分数并提供可视化反馈,帮助教师及时调整教学策略。

✨ 核心功能

  1. **实时视频捕获**:调用摄像头获取课堂视频流

  2. **智能面部检测**:使用MediaPipe FaceMesh模型检测面部关键点

  3. **专注度评估**:基于眼神接触、头部稳定性、面部表情计算专注度分数

  4. **可视化反馈**:实时显示专注度分数、面部检测结果和状态信息

  5. **模块化设计**:分离视频、检测、计算、UI四大核心模块

🚀 快速开始

环境要求

  • 现代浏览器 (Chrome 88+, Firefox 85+, Edge 88+)

  • 摄像头设备

  • 网络连接 (首次加载模型需要下载)

安装依赖

bash

npm install @tensorflow/tfjs @tensorflow-models/face-landmarks-detection

使用步骤

  1. 将代码保存为对应模块文件 (videoCapture.js, faceDetection.js等)

  2. 创建index.html文件引入所有JS模块

  3. 在浏览器中打开index.html (建议使用本地服务器)

  4. 允许浏览器访问摄像头权限

  5. 系统自动开始分析,按ESC键停止

目录结构

project/

├── index.html # 主页面

├── main.js # 主程序入口

├── videoCapture.js # 视频捕获模块

├── faceDetection.js # 面部检测模块

├── attentionCalculator.js # 专注度计算模块

├── uiRenderer.js # UI渲染模块

└── README.md # 说明文档

📊 专注度评估算法

  • **眼神接触 (40%)**:通过眼睑关键点计算眼睛闭合程度

  • **头部稳定性 (30%)**:分析头部偏转角度 (俯仰/偏航)

  • **面部表情 (30%)**:检测中性表情,识别分心状态

  • **动态调整**:持续分心超过3秒将额外扣分

🔧 扩展建议

  1. **后端集成**:添加Node.js后端存储分析数据

  2. **多人检测**:扩展支持同时分析多个学生

  3. **表情识别**:集成更精细的表情分类模型

  4. **数据导出**:添加CSV/Excel报告生成功能

  5. **移动端适配**:优化UI适应移动设备

⚠️ 注意事项

  • 首次运行需要下载约10MB的AI模型文件

  • 建议在光线充足的环境中使用

  • 浏览器需启用摄像头权限

  • 分析结果仅供参考,不应作为唯一评估标准

  • 保护学生隐私,避免存储敏感图像数据

核心知识点卡片

  1. 智能视觉技术应用
  • 定义:利用计算机视觉技术分析图像/视频中的视觉信息,实现智能化理解和决策

  • 应用:面部检测、表情识别、姿态估计在专注度分析中的综合运用

  • 关联代码:

"FaceDetector"类使用MediaPipe FaceMesh模型检测468个面部关键点

  1. 模块化开发架构
  • 定义:将复杂系统分解为独立、可复用的功能模块,通过接口协作

  • 优势:提高代码维护性、可测试性和团队协作效率

  • 关联代码:四大模块分离设计 (视频捕获、面部检测、专注度计算、UI渲染)

  1. 实时数据处理技术
  • 定义:通过requestAnimationFrame实现浏览器端实时视频分析和渲染

  • 关键技术:帧同步、异步处理、性能优化避免卡顿

  • 关联代码:

"startAnalysisLoop"方法中的递归调用机制

  1. 专注度评估模型
  • 定义:基于多维度视觉特征的加权评分算法,量化注意力水平

  • 评估维度:眼神接触(40%)、头部稳定性(30%)、面部表情(30%)

  • 关联代码:

"AttentionCalculator.calculateAttention"方法中的权重计算逻辑

  1. TensorFlow.js模型部署
  • 定义:在浏览器环境中加载和运行预训练的机器学习模型

  • 技术特点:客户端推理、隐私保护、离线可用

  • 关联代码:

"@tensorflow-models/face-landmarks-detection"模型加载和应用

  1. 用户体验设计原则
  • 定义:通过实时反馈、直观可视化和非侵入式交互提升系统可用性

  • 设计要素:颜色编码(红黄绿)、简洁界面、状态提示

  • 关联代码:

"UIRenderer"类中的动态UI更新和视觉反馈机制

这个系统采用现代Web技术栈,模块化设计便于扩展,可直接在支持摄像头的浏览器中运行。系统注重隐私保护,所有分析均在客户端完成,不传输图像数据到服务器。

关注我,有更多实用程序等着你!

相关推荐
李广山Samuel2 小时前
Node-OPCUA 入门(2)-创建一个简单的opcua客户端
javascript
weixin_448119942 小时前
Datawhale Hello-Agents入门篇202512第2次作业
java·前端·javascript
BD_Marathon2 小时前
Vue3_事件渲染命令
开发语言·javascript·ecmascript
kaka-3332 小时前
微信小程序中使用 xlsx(xlsx.mini.min.js)实现 Excel 导入导出功能
javascript·微信小程序·excel
北冥有一鲲2 小时前
LangChain.js:Tool、Memory 与 Agent 的深度解析与实战
开发语言·javascript·langchain
霁月的小屋2 小时前
Vue响应式数据全解析:从Vue2到Vue3,ref与reactive的实战指南
前端·javascript·vue.js
小林rush3 小时前
uni-app跨分包自定义组件引用解决方案
前端·javascript·vue.js
亮子AI3 小时前
【Svelte】怎样实现一个图片上传功能?
开发语言·前端·javascript·svelte
心.c3 小时前
为什么在 Vue 3 中 uni.createCanvasContext 画不出图?
前端·javascript·vue.js