Files
opendance-android/tasks/004-keypoint-serializer.md

75 lines
2.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# T-AND-004 33 点 -> 239 字节帧
- **状态**:done
- **依赖**:T-AND-003(数据结构)、T-AND-001
## 目标
把 33 点关键点按冻结契约序列化为 239 字节二进制帧。
## load
```
DSH.md
contracts/websocket-keypoints.md # 锚点:2 二进制帧(冻结)
contracts/skeleton-topology.md # 锚点:1 33 点、4 坐标系
app/src/main/java/com/opendance/studio/model/KeypointFrame.kt
app/src/main/java/com/opendance/studio/model/SkeletonTopology.kt
```
## 帧布局(契约冻结)
```
偏移 长度 字段
0 2 magic u16 = 0x4F44 ('OD'),小端序 -> 字节序为 44 4F
2 1 version u8 = 1
3 1 flags u8 bit0 镜像 | bit1 低置信度 | bit2 上半身
4 4 frame_id u32 LE
8 231 keypoints 33 x 7B:s16 x, s16 y, s16 z, u8 conf
合计 239
```
## ★ 金标准字节向量测试
本任务的核心验收不是「函数跑通了」,而是**与另两端逐位一致**。
测试 `KeypointFrameTest.goldenVectorMatchesWebImplementation` 使用由
`opendance-web` 已通过验收的 TypeScript 实现产出的 239 字节金标准向量:
```bash
# 重新生成金标准向量(在 opendance-web 仓库内)
cd opendance-web/web-server && npm run build
node -e "
const { encodeBinaryFrame } = require('./dist/preprocess/keypoint-codec.js');
const points = [], conf = [];
for (let i = 0; i < 33; i++) {
points.push([(i%33)/32, 1-(i%33)/32, ((i%7)-3)/10]);
conf.push(i%2===0? 1.0: 0.5);
}
const buf = encodeBinaryFrame(42, points.map((p,i)=>[...p,conf[i]]), 0b101);
console.log(buf.toString('hex'));
"
```
固定输入:`xs = (i%33)/32`、`ys = 1-(i%33)/32`、`zs = ((i%7)-3)/10`、
`confidence = i%2==0? 1.0: 0.5`、`frameId = 42`、`flags = 0b101`。
## 关键实现
- `ByteBuffer.order(LITTLE_ENDIAN)`,避免手动移位出错
- 定点换算 `round(v x 32767)` 并 `coerceIn(-32768, 32767)`
- 置信度 `round(v x 255)`,阈值 0.5 含端点(`>=`)
- 输入超范围时裁剪而非抛异常(相机抖动可能产生轻微越界值)
- 并行 FloatArray 存储,30 FPS 循环内零对象分配
## 验收
```bash
./gradlew testDebugUnitTest
```
19 项单元测试全部通过,含:
常量与契约一致、金标准向量逐位一致、编解码往返精度、错误长度/magic/版本拒绝、
极值不溢出、超范围裁剪、低置信度标志计算、镜像 x 还原、拓扑父链表无环、
骨架连线索引合法。