102 lines
6.2 KiB
Markdown
102 lines
6.2 KiB
Markdown
# Web-Based Real-Time Pose Classifier
|
||
|
||
这是一个功能强大的、完全在浏览器中运行的实时姿态识别与训练工具。它利用 TensorFlow.js 和姿态检测模型 (MoveNet),允许用户通过摄像头实时定义、训练和识别自定义的身体姿态,而无需任何服务器端处理。
|
||
|
||
## ✨ 功能亮点
|
||
|
||
- **实时姿态检测**: 使用高效的 **MoveNet** 模型在视频流中实时捕捉人体的17个关键点。
|
||
- **在线模型训练**: 通过 **K-近邻 (KNN)** 算法,用户可以直接在浏览器中为不同的姿态(例如“站立”、“举手”、“深蹲”)采集样本并训练分类模型。
|
||
- **实时姿态预测**: 训练完成后,应用可以立即对摄像头前的姿态进行分类,并显示预测结果及置信度。
|
||
- **精准视觉反馈**: 实时在用户画面上绘制姿态骨架,确保关键点被正确识别,实现了视频与Canvas的完美对齐与重叠。
|
||
- **模型持久化**:
|
||
- **导出模型**: 用户可以将训练好的模型一键导出为 `.json` 文件,方便保存和备份。
|
||
- **导入模型**: 用户可以随时将之前导出的模型文件导入应用,瞬间恢复训练状态,无需重新采集样本。
|
||
- **纯前端实现**: 所有计算(包括模型推理和训练)都在客户端浏览器中完成,保护用户隐私且无需服务器成本。
|
||
|
||
## 🚀 如何使用
|
||
|
||
1. **打开页面**: 用支持现代JavaScript的浏览器(如Chrome, Firefox)打开 `index.html`。
|
||
2. **授予权限**: 浏览器会请求摄像头访问权限,请点击“允许”。应用会自动加载模型并启动摄像头。
|
||
3. **采集样本 (训练)**:
|
||
- 面对摄像头,摆出你想定义的第一个姿态(例如“姿态A”)。
|
||
- 多次点击“采集样本”按钮,建议从不同角度采集至少20个样本以保证准确性。
|
||
- 对其他姿态(“姿态B”、“姿态C”)重复此过程。样本数量会实时更新。
|
||
4. **模型管理 (可选)**:
|
||
- **导出**: 训练完成后,点击“导出模型”按钮,会将当前训练好的模型保存为一个`pose-knn-model.json`文件。
|
||
- **导入**: 在新的会话或新设备上,点击“导入模型”,选择之前导出的`.json`文件,即可恢复模型。
|
||
5. **开始预测 (推理)**:
|
||
- 点击“开始预测”按钮。
|
||
- 应用将开始实时分析你的姿态,并在下方显示预测结果。
|
||
- 再次点击“停止预测”可暂停。
|
||
|
||
## 📁 项目结构
|
||
|
||
```
|
||
/
|
||
├── 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模型和分类器占用的内存,防止内存泄漏。
|