OpenPose(二):PAF理解(Part Affinity Fields for Part Association)

读了Openpose的论文,可以清楚,Openpose的GT由两部分组成

  • 关键点的标注,采用高斯Map,博主在OpenPose(一):根据关键点生成置信图(Confidence Map)做过解释
    在这里插入图片描述

  • PAF(Part Affinity Fields),部件关联场,这是一个新的名称,由Openpose首次提出(是不是首次我也不知道,姑且认为是首次吧)。这么高大上的名字,一下子就懵了,博主这里简单暴力理解为,就是对肢体进行标注(肢体分割),目的是通过肢体找关键点直接的连接。



一、什么是PAF(Part Affinity Fields)?

paf就是对肢体进行标注,是身体每个肢体的2D向量,同时保持了肢体区域之间的位置信息和方向信息。
在这里插入图片描述
以论文中的公式来解答上图

  • x j 1 , k x_{j1,k} xj1,k x j 2 , k x_{j2,k} xj2,k 表示个体 k k k 的肢体 c c c 的部位 j 1 和 j 2 j1和j2 j1j2 的肢体坐标。如果一个点 p p p 落在肢体上,则 L c , k ∗ ( p ) L^∗_{c,k}(p) Lc,k(p) 的值是一个从 j 1 j1 j1指向 j 2 j2 j2 的单位向量;对于其它点,向量的值为0。

  • 训练的时候,生成GT时,PAF在点 p p p 的GT值为
    在这里插入图片描述
    其中, v = ( x j 2 , k − x j 1 , k ) / ∥ x j 2 , k − x j 1 , k ∥ v=(x_{j2,k}−x_{j1,k})/∥x_{j2,k}−x_{j1,k}∥ v=(xj2,kxj1,k)/∥xj2,kxj1,k 是肢体的单位向量。
    p p p 的范围如下:
    在这里插入图片描述
    其中,肢体宽度 σ l σ_l σl 是像素级上的距离,肢体长度 l c , k = ∥ x j 2 , k − x j 1 , k ∥ 2 l_{c,k}=∥x_{j2,k}−x_{j1,k}∥_2 lc,k=xj2,kxj1,k2,并且 v ⊥ v_⊥ v是正交于 v v v 的向量。

上面公式中的点乘即 A ⋅ B A ·B AB,为 B B B 向量在 A A A 向量方向上的投影距离,
v ⊥ v_⊥ v v v v则是两个单位垂直向量。
以上就是为了得出肢体方向上的宽高,形成一个范围,这样只要任意一点落在这个肢体区域内,那就都赋值为 L c , k ∗ ( p ) L^∗_{c,k}(p) Lc,k(p)即单位向量,如果没有落在这个区域内,则赋值为0;

  • 一个肢体,对应两个map,其中一个Map是单位向量中的 x x x,一个Map是单位向量中的 y y y

  • 因为可能出现多个肢体重合,还需要取重合肢体的平均值
    在这里插入图片描述

二、PAF的生成代码

以一个肢体为例,不考虑重合肢体取平均值

  • 第一步、定义点和图像
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""                  
*  * *** *  * *  *      
*  *  *   **  *  *             
****  *   **  *  *                 
*  *  *   **  *  *         
*  * **  *  * ****  

@File     :Openpose/3-showPafForJoint 
@Date     :2020/12/7 下午2:07  
@Require  : matplotlib, numpy
@Author   :hjxu2016, https://blog.csdn.net/hjxu2016/
@Funtion  :OpenPose中的 paf
"""
import numpy as np
import matplotlib.pyplot as plt

paf_sigma = 8         # 肢体宽度
shape = (425, 640, 3) # 图像大小
joint_from = np.array([378, 118]) # 肢体的两个点
joint_to = np.array([393,  214])

plt.xlim((0,shape[1]))
plt.ylim((0,shape[0]))
plt.scatter([joint_from[0], joint_to[0]], [joint_from[1], joint_to[1]], color='b')
plt.gca().invert_yaxis() # 将plt的原点由坐下设置为左上

在这里插入图片描述

第二步、得到躯干平行方向区域

相当于遍历图上的每一个点,从这个点到joint_from的向量与unit_vector点乘
两个向量点乘相当于取一个向量在另一个向量方向上的投影
如果点乘大于0,那就可以判断这个点在不在这个躯干的方向上了,
(0 <= horizontal_inner_product) & (horizontal_inner_product <= joint_distance)
这个限制条件是保证在与躯干水平的方向上,找出所有落在躯干范围内的点
然而还要判断这个点离躯干的距离有多远


joint_distance = np.linalg.norm(joint_to - joint_from)
unit_vector = (joint_to - joint_from) / joint_distance
rad = np.pi / 2
rot_matrix = np.array([[np.cos(rad), np.sin(rad)], [-np.sin(rad), np.cos(rad)]])
# print("垂直分量 = ", np.dot(rot_matrix,(joint_to - joint_from) ))
vertical_unit_vector = np.dot(rot_matrix, unit_vector)  # 垂直分量
print("vertical_unit_vector = ", vertical_unit_vector)
grid_x = np.tile(np.arange(shape[1]), (shape[0], 1))
grid_y = np.tile(np.arange(shape[0]), (shape[1], 1)).transpose()  # grid_x, grid_y用来遍历图上的每一个点

horizontal_inner_product = unit_vector[0] * (grid_x - joint_from[0]) + unit_vector[1] * (grid_y - joint_from[1])
horizontal_paf_flag = (0 <= horizontal_inner_product) & (horizontal_inner_product <= joint_distance)
plt.imshow(horizontal_paf_flag)

在这里插入图片描述
第三步、得出肢体区域
要判断这个点离躯干的距离有多远,只要拿与起始点的向量点乘垂直分量就可以了,
所以这里的限制条件是paf_width, 不然一个手臂就无限粗了
vertical_paf_flag = np.abs(vertical_inner_product) <= paf_width
这个限制条件是保证在与躯干垂直的方向上,找出所有落在躯干范围内的点(这个躯干范围看来是手工定义的)

vectemp = vertical_unit_vector # 垂直分量
# 求图像上点到线之间的距离 = 图像上的向量与垂直向量的点乘

vertical_inner_product = vectemp[0] * (grid_x - joint_from[0]) + vectemp[1] * (grid_y - joint_from[1])
vertical_paf_flag = np.abs(vertical_inner_product) <= paf_sigma  # paf_width : 8
paf_flag = horizontal_paf_flag & vertical_paf_flag  # 合并两个限制条件
plt.imshow(paf_flag)

在这里插入图片描述
第四步、给肢体区域赋值为单位向量的大小,得到一个肢体的paf

# constant_paf.shape : (2, 368, 368), 上面这一步就是把2维的unit_vector broadcast到所有paf_flag为true的点上去
# constant_paf里面有368*368个点,每个点上有两个值,代表一个矢量
# constant_paf里的这些矢量只会取两种值,要么是(0,0),要么是unit_vector的值
print(unit_vector)
np.broadcast_to(unit_vector , shape[:-1] + (2,))
print(np.broadcast_to(unit_vector , shape[:-1] + (2,)).shape)
paf_flag = paf_flag + 0
constant_paf = np.stack((paf_flag, paf_flag)) * np.broadcast_to(unit_vector, shape[:-1] + (2,)).transpose(2, 0, 1)
# plt.show(constant_paf[0])
print(constant_paf.shape)
print(constant_paf[0].shape)
print(constant_paf[0][119, 379]) # 得到单位向量X=0.1543768802736096
print(constant_paf[1][119, 379]) # 得到单位向量y=0.9880120337511015

把这个肢体显示在原图上

import cv2
bgr_image = cv2.imread("./000000000785.jpg")
rgb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
heatmap = constant_paf[0]
heatmap = cv2.normalize(heatmap, heatmap, 0, 255, cv2.NORM_MINMAX)
heatmap = np.uint8(heatmap)
jetmap = cv2.applyColorMap(255-heatmap, cv2.COLORMAP_PINK)

alpha = 0.5
out = cv2.addWeighted(rgb_image, alpha, jetmap, 1 - alpha, 0, jetmap)
plt.imshow(out)

在这里插入图片描述

三、预测部分

四、多人解析PAFS

参考资料整理在

OpenPose相关资料整理

  • 21
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Part Affinity Fields(PAF)是一种用于人体姿势估计的神经网络技术,它可以检测出人体各个关节之间的连接关系和方向,从而实现对人体姿势的准确识别和跟踪。PAF技术在计算机视觉、机器人、虚拟现实等领域具有广泛的应用前景。 ### 回答2: Part Affinity Fields (PAF)是一种用于姿态估计的技术,可以检测人体的关键点,并将它们连接在一起。它由Zhe Cao等人在2017年的Essential part-based pose estimation paper中提出。 在PAF中,探测器主要分为两部分:一个关节探测器和一个部分相关场(PAF)探测器。关节探测器检测每个人体关键点的位置,并生成一个heatmap。在PAF探测器中,我们检测人体关键点之间的连接,并生成一组PAF heatmap,代表连接的概率。这意味着我们可以将两个关键点之间的概率用向量场的形式表示出来。 在训练过程中,PAF使用带有关键点注释的大量图像进行训练。在测试时,PAF通过这些向量场在两个关键点之间进行插值来确定连接。 PAF有助于提高关键点检测精度。因为它可以解决某些关键点重叠或部分遮挡的问题。此外,PAF还涵盖了肢体姿态与关键点之间的相关性,有助于更准确地表示姿态。 在实践中,PAF已经被用于人体动作识别,人体跟踪和人体姿态估计等应用中。 ### 回答3: Part Affinity Fields(PAFs)又被称作部分关联场,在计算机视觉和深度学习领域的人体姿态估计问题中起着至关重要的作用。 PAFs是一种基于卷积神经网络的算法,旨在对图像中的人体姿态关节建模。其主要的思想是将身体部位之间的关联关系建模出来,从而更准确地估计每个部位的位置。这种方法通过在卷积神经网络中建立结构化的特征图来进行,其中每个像素都代表身体上某个关键部位(比如鼻子、肘部、膝盖等)。在这些像素之间,PAFs可以计算出表示不同身体部位之间联系的向量场,通过这些向量场的核心特征来检测身体部位的变化情况以及它们之间的联结。这样就可以形成一个全局的人体关键点分布,以帮助机器更好地分析和理解人体姿态。 与传统的人体姿态估计算法相比,PAFs的优势在于它可以在具有更高的准确性和速度的同时,通过自动化的人体关节检测、跟踪及姿态估计来帮助计算机更好地理解人体动作。这使得PAFs成为了许多实际应用中的主要算法之一,例如人体动作跟踪、动作识别、游戏、虚拟现实等等。 综上所述,PAFs是一种重要的人体姿态估计算法,它通过卷积神经网络中的结构化特征图来建模身体部位之间的相互联系,以达到更准确和快速的人体姿态估计效果。它在许多实际应用中都具有广泛的应用前景。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值