原文: OpenPose 基于OpenCV DNN 的多人姿态估计 - AIUAI
OpenPose 可以对图片中单个人体目标的姿态估计,也可以处理图片中多人的姿态估计.
这里主要记录基于 OpenCV 4.x DNN 模块和 OpenPose 开源模型的多人人体姿态估计 的实现.
采用的模型的基于 COCO 数据集训练的人体关键点模型.
OpenPose 的多人人体姿态估计的模型结构如图:
网络输入为 hxwx3 的图片,并输出包含关键点(Keypoints)的置信图(confidence maps) 和每个关键点对(keypoint pair) 的 Part Affinity Heatmaps 的两个输出数组.
[1] - Stage 0:
采用 VGGNet 的前 10 层,提取输入图片的特征图(feature maps).
[2] - Stage 1:
采用 2-分支的 multi-stage CNN 网络结构:
(1) - 分支一:
网络分支一预测人体关键点位置的 2D Confidence Maps ,如 elbow, knee, etc. 每个 Confidence Map 是一个灰度图(grayscale image),其最大值的位置坐标即为对应人体某个关键点的概率最高. 如图:
(2) - 分支二:
网络分支二预测 Part Affinities (PAF) 的2D 向量场(L, vector fields),其表示了两个关键点之间关联度(degree of association). 例如,关键点 Neck 和 Left Shoulder 之间的 Part Affinity, 如下图,属于同一个人体的关键点之间的 Affinity 值比较大.
总体来说,Confidence Maps 用于检测关键点位置;而 Affinity Maps 用于检测关键点之间的有效连接.
根据检测过程,主要涉及的函数有:getKeyponts() 、 getValidPairs() 和 getPersonwiseKeypoints() .
**getKeyponts( )函数功能:**对 Confidence Map 采用 NMS(Non Maximum Suppression) 来检测关键点.
**getValidPairs()函数功能:**检测所有人体之间不同关键点之间的有效连接.
有效的关键点对(joint pair) 是指两个关键点的连接,属于相同的人体.
最简单的方式是,计算一个关键点与其它所有可能的关键点之间的最小距离,来判断关键点对的有效性.
例如下图,可以计算 Nose 关键点与其它所有 Necks 关键点之间的距离,最小距离的 Neck 关键点,则对应于同一个人体.
但是,这种方法不是对所有的关键点对都是有效的,尤其是对与图像中包含很多人体,或者有关键点缺失的时候.
例如下图,对于关键点对, Left-Elbow -> Left Wrist,第三个人体的 wrist 关键点与第二个人体的 elbow 关键点的距离,比与其同一人体的 elbow 关键点的距离更小. 但该关键点对并不是有效的.
而 Part Affinity Maps 的作用是,给定沿着两个关键点对的仿射(affinity)的方向. 因此,有效的关键点对不仅具有最小的距离,其方向也应该顺着 PAF Heatmaps 方向.
例如,Left-Elbow -> Left Wrist 连接的 Heatmap,如下图,即使最小距离的关键点是错误的,但,由于 PAF 只能顺着 Elbow 和 Wrist 的单位向量,所以能正确检测有效的关键点对:
OpenPose 中采用的方法为:
[1] - 将关键点对的两个点之间的连线进行划分,得到该连线上的 n
个点(Divide the line joining the two points comprising the pair. Find n
points on this line.);
[2] - 判断这些点上的 PAF 是否与连接该关键点的线的方向相同(Check if the PAF on these points have the same direction as that of the line joining the points for this pair);
[3] - 如果方向满足特定程度,则为有效的关键点对(If the direction matches to a certain extent, then it is valid pair.)
代码实现与分析:
对于每个关键点对(body part pair, keypoints pair),
[1] - 选择属于同一个关键点对的关键点. 并分别存放在两个列表: candA
和 candB
. candA
列表中的每个关键点可以与 candB
中的某些关键点相连接. 如下图,给出了 candA
和 candB
中的 Neck -> Right-Shoulder 关键点对的所有关键点:
对应 Python 实现:
[2] - 计算两个关键点之间的单位向量,其给定了关节点之间连线的方向.
[3] - 计算两个关键点之间连线的 10 个插值点.
[4] - 计算插值点的 PAF 与单位向量 d_ij 之间的点积(dot product).
[5] - 如果这些插值点的 70% 的都满足判定标准,则该关键点对是有效的.
**getPersonwiseKeypoints()函数功能:**计算得到属于每个人体的关键点集合.
对于每个检测到的有效 joint pair,分配属于一个人体的 joints.
计算得到所有关键点之间的关键点对后,可以将具有相同关键点检测候选值的关键点对,组合为多人的姿态估计.
代码实现具体分析
[1] - 首先创建保存每个人体的所有关键点的空列表.
然后对每个关键点对,判断 partA 是否已经在列表里, 如果已经在列表里,则表示该关键点对属于该列表,且 partB 也属于同一人体. 因此,添加该关键点对的 partB 到 partA 所在的列表.
[2] - 如果 partA 不在任一人体列表里,则表示该关键点对属于一个新出现的人体,故创建新的列表.
如:
模型下载:
COCO: http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/coco/pose_iter_440000.caffemodel
如:
[1] - Multi-Person Pose Estimation in OpenCV using OpenPose - 2018.09.11