# 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.  **开始预测 (推理)**:
    - 点击“开始预测”按钮。
    - 应用将开始实时分析你的姿态，并在下方显示预测结果。
    - 再次点击“停止预测”可暂停。


建议使用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模型和分类器占用的内存，防止内存泄漏。
