8 个姿态、每个 17 个关键点,减髋中心、除以躯干长度做归一化之后, 带噪的「叉腰」查询距离第一位 0.2603,第二位「立正」1.9598——差了 7.5 倍。 归一化是这一步的全部关键。
上一节重建三维形状,这一节做姿态检索。同样是关键点,但这次不反解,直接把坐标当特征算距离。
一、关键点当坐标用时,先要归一化
17 个关键点是 34 个数。直接把 34 个数当向量算距离,会出大问题。 同一个动作,人在画面中间和边上,坐标差一截;站得近和站得远,坐标差一倍。 这些差别和「姿态像不像」毫无关系。 所以要归一化:先减掉髋部中心,把人挪到原点;再除以颈部到髋的距离,把人缩放到统一大小。 这两步做完,剩下的差别才是姿态本身的差别。 这一步做完,「尺度不变」和「平移不变」两个词才算落到实处。
二、距离拉得很开,是好事
归一化之后,带噪的「叉腰」查询到原型的距离是 0.2603,第二名「立正」是 1.9598, 差 7.5 倍。 差距这么大,说明这套特征把姿态之间的差别保留得很好——「手往哪边伸」是几倍的差别, 不是百分之几的差别。 这也意味着阈值很好定。 取 1.0 作阈值,所有不相似的都会被拒掉,不会出现上一章客服机器人那种「答不答都纠结」的局面。 但差距大也说明数据太干净:8 个姿态是我手工摆的,彼此差别刻意拉开。 真人的姿态是连续的,差异会小得多。
三、姿态检索能干什么
动作识别:把一段视频切成若干帧,每帧检索最像的姿态,连起来就是动作序列。 健身纠错:把用户动作和标准动作比对,找出哪个关节偏得最多。 这个用法要求关节级定位,不只是整体相似度。 动画检索:从动作库里找一段相似的,拿来做动作重定向。 三种用法里,健身纠错对精度要求最高,因为它要指出「哪里错了」,不只要「像不像」。 做法是逐关节算偏差,再排序。这一步在 Demo 里没做,因为 Demo 只有 8 个原型。
四、界面上的清单(我没有跑)
书里用 VGG 的点标注功能来标 17 个骨架点。沙箱没有浏览器,这一步没跑。 1. 把人物图片导入 VIA。 2. 建一个点属性集,按固定顺序定义 17 个点(头、颈、左右肩肘腕、髋、膝、踝)。 3. 逐张点完,注意左右不要标反——这是最容易出的错。 4. 导出 JSON,把坐标抽成 17 行 2 列的数组。 5. 归一化后入库,算距离检索。 第 3 步的左右问题值得单说:镜像的人物图如果没做处理,左右肩的坐标会互换,归一化之后距离依然很大, 检索直接错。
五、动手 Demo:姿态检索:归一到身体尺度再算距离
手工摆 8 个姿态,每个 17 个关键点(头、颈、肩肘腕、髋膝踝); 统一减髋中心、除以颈到髋的距离做归一化; 给「叉腰」加 σ=0.04 的噪声当查询,算与 8 个原型的欧氏距离并排序。
def norm(p):
c = (p[8] + p[9]) / 2.0 # 髋中心
q = p - c # 平移不变
s = float(np.linalg.norm(p[1] - c)) # 颈到髋的距离
return q / s # 尺度不变
实跑输出:
--------------------------------------------------------------------
姿态检索:把骨架坐标归一化后算距离
--------------------------------------------------------------------
姿态数 8,每个 17 个关键点
归一化 减髋中心、除以颈到髋的距离
姿态 到查询的欧氏距离
--------------------------
叉腰 0.2603
立正 1.9598
跨步 2.2504
前倾 2.5512
单手举 2.8523
下蹲 3.0871
举手 3.1779
张开双臂 4.0505
检索结果 叉腰
是否正确 是(查询是叉腰加噪声)
第 1 名「叉腰」距离 0.2603,第 2 名「立正」1.9598——差了 7.5 倍,说明归一化之后「手往哪边伸」这个差别被保留得很干净。
这一步归一化是关键。不归一化的话,同一个人站远一点、或者个子高一点,距离就会变,检索全乱。姿态识别里说「尺度不变」,指的就是这一步。
距离表拉得很开:0.2603 到 4.0505,跨度 15 倍。 这种分布下排序几乎不会错,但也不说明特征有多强——数据太干净。 第二名是「立正」而不是「单手举」,有点意外。 因为「单手举」只抬了一边,另一边还是垂着的,和「叉腰」两边都弯的差别反而大。 最后一名「张开双臂」距离 4.05, 几乎是查询到原点距离的两倍——归一化之后手臂张开会让整体尺度变化很大,这一点在真实数据上要留意。 我没有做左右镜像的增强。真实系统一般会把每个姿态复制一份镜像入库,否则同一动作照镜子就检索不到。
30 秒实验
- 把归一化去掉(直接算原始坐标距离),看排序会不会乱。
- 把查询换成「单手举」加噪声,看它和「举手」的距离差多少。
- 想一想:为什么左右镜像会让检索失效?该怎么处理?
常见误区
- 「坐标直接算距离就行」——不归一化,位置和大小会盖过姿态差别。
- 「距离小就一定是同类」——数据干净时是这样,真人数据不一定。
- 「不用管左右」——镜像人物会让左右点互换,检索直接失效。
自测三问(点开对答案)
1. 姿态检索前为什么要归一化? —— 去掉平移和尺度的影响,只留下姿态本身的差别。 2. 归一化用哪两步? —— 减髋中心做平移不变,除以颈到髋距离做尺度不变。 3. 为什么真实系统要做左右镜像增强? —— 同一动作照镜子后关键点左右互换,不做增强库里的原型匹配不上。单帧姿态能检索了,下一节把时间拉长:从一段视频里找内容。
- ☐ (本节完,下一节 7.2.3 实例3:检索视频内容)