Web-Based Real-Time Pose Classifier
这是一个功能强大的、完全在浏览器中运行的实时姿态识别与训练工具。它利用 TensorFlow.js 和姿态检测模型 (MoveNet),允许用户通过摄像头实时定义、训练和识别自定义的身体姿态,而无需任何服务器端处理。
✨ 功能亮点
- 实时姿态检测: 使用高效的 MoveNet 模型在视频流中实时捕捉人体的17个关键点。
- 在线模型训练: 通过 K-近邻 (KNN) 算法,用户可以直接在浏览器中为不同的姿态(例如“站立”、“举手”、“深蹲”)采集样本并训练分类模型。
- 实时姿态预测: 训练完成后,应用可以立即对摄像头前的姿态进行分类,并显示预测结果及置信度。
- 精准视觉反馈: 实时在用户画面上绘制姿态骨架,确保关键点被正确识别,实现了视频与Canvas的完美对齐与重叠。
- 模型持久化:
- 导出模型: 用户可以将训练好的模型一键导出为
.json
文件,方便保存和备份。 - 导入模型: 用户可以随时将之前导出的模型文件导入应用,瞬间恢复训练状态,无需重新采集样本。
- 导出模型: 用户可以将训练好的模型一键导出为
- 纯前端实现: 所有计算(包括模型推理和训练)都在客户端浏览器中完成,保护用户隐私且无需服务器成本。
🚀 如何使用
- 打开页面: 用支持现代JavaScript的浏览器(如Chrome, Firefox)打开
index.html
。 - 授予权限: 浏览器会请求摄像头访问权限,请点击“允许”。应用会自动加载模型并启动摄像头。
- 采集样本 (训练):
- 面对摄像头,摆出你想定义的第一个姿态(例如“姿态A”)。
- 多次点击“采集样本”按钮,建议从不同角度采集至少20个样本以保证准确性。
- 对其他姿态(“姿态B”、“姿态C”)重复此过程。样本数量会实时更新。
- 模型管理 (可选):
- 导出: 训练完成后,点击“导出模型”按钮,会将当前训练好的模型保存为一个
pose-knn-model.json
文件。 - 导入: 在新的会话或新设备上,点击“导入模型”,选择之前导出的
.json
文件,即可恢复模型。
- 导出: 训练完成后,点击“导出模型”按钮,会将当前训练好的模型保存为一个
- 开始预测 (推理):
- 点击“开始预测”按钮。
- 应用将开始实时分析你的姿态,并在下方显示预测结果。
- 再次点击“停止预测”可暂停。
建议使用live server插件开启本地服务器,并访问index.html文件。
存在问题
css样式中描绘关节骨架与实际对比偏小,现在使用的方法是模型输出关节后与视频大小一起缩放。暂时不清楚是缩放导致还是模型输出。
📁 项目结构
/
├── poseClassifier.js # 核心逻辑脚本,包含所有功能实现
├── index.html # 应用主页面,包含所有UI元素
├── style.css # 页面样式文件
└── script.js # 核心逻辑脚本,包含所有功能实现
🤖 技术栈
- TensorFlow.js: 核心机器学习库,用于在浏览器中运行模型和处理张量(Tensors)。
- Pose Detection API (
@tensorflow-models/pose-detection
): 用于运行姿态检测模型。- MoveNet.SinglePose.Lightning: 我们选择的具体模型,它在速度和精度之间取得了极佳的平衡。
- KNN Classifier (
@tensorflow-models/knn-classifier
): 一个基于TensorFlow.js实现的K-近邻分类器,用于在线学习。 - 原生 HTML5 / CSS3 / JavaScript (ES6+): 构建用户界面和实现应用逻辑。
📜 script.js
核心函数解析
主应用逻辑
async function init()
- 职责: 应用的入口函数。负责初始化KNN分类器、加载MoveNet姿态检测模型、设置摄像头、绑定所有事件监听器,并启动主循环。
async function setupCamera()
- 职责: 请求并获取用户摄像头的视频流。成功后,将视频流赋给
<video>
元素,并设置<canvas>
的绘图分辨率与视频的原始分辨率(videoWidth
/videoHeight
)完全一致,这是解决坐标偏移的关键。
function setupEventListeners()
- 职责: 为所有UI元素(如“采集样本”、“开始预测”、“导入/导出模型”按钮)绑定
click
或change
事件,将用户交互与业务逻辑连接起来。
async function mainLoop()
- 职责: 这是应用的核心循环,通过
requestAnimationFrame
实现。在每一帧中,它会从视频中获取当前姿态,清空并重绘Canvas,如果处于预测状态,则进行姿态分类并更新结果。
async function addExample(classId)
- 职责: 当用户点击“采集样本”时调用。它获取当前帧的姿态,将其转换为用于分类的特征张量,并添加到KNN分类器中,与指定的
classId
关联。
function togglePrediction()
- 职责: 控制预测状态的开关。它会检查模型是否已训练,然后切换
isPredicting
标志位,并更新UI。
模型管理函数
function exportModel()
- 职责: 将训练好的模型导出。它通过
classifier.getClassifierDataset()
获取内部数据,将Tensor对象转换为可序列化的普通数组,最后生成一个JSON字符串并触发浏览器下载。
function importModel(event)
- 职责: 从用户选择的
.json
文件导入模型。它使用FileReader
读取文件内容,将JSON字符串解析回对象,再将普通数组转换回Tensor对象,最终通过classifier.setClassifierDataset()
加载到分类器中。
辅助与UI更新函数
function flattenPose(pose)
- 职责: 数据预处理函数。它提取姿态中的所有关键点坐标,进行归一化(除以视频宽高),并“扁平化”为一个一维的Tensor。这是KNN分类器需要的输入格式。
function drawPose(pose)
- 职责: 视觉反馈函数。它在Canvas上绘制姿态的关键点(圆点)和骨骼连接线,让用户能直观地看到模型识别出的姿态。
function updateSampleCounts()
- 职责: 更新界面上显示的每个姿态类别的样本数量。
function updatePredictionUI()
- 职责: 根据当前是否正在预测,动态地启用/禁用相关按钮(如“采集样本”按钮在预测时应被禁用),并更新按钮文本。
function enableControls()
- 职责: 在应用成功初始化后,启用所有交互按钮。
function cleanup()
- 职责: 在页面关闭或刷新前释放资源,主要是清理TensorFlow.js模型和分类器占用的内存,防止内存泄漏。