OpenPose模型的理解

网络结构

​如下图所示为OpenPose的网络结构:

首先由主干网络VGG19提取图片的特征,然后进入到stage模块,stage是一些串行的模块,每个模块的结构和功能都是一样的。分成两个branch,一个branch生成pcm,一个branch生成paf。并且每个stage的pcm和paf都会进行loss求解。最后总的loss是所有loss的和。​这里考虑一下为什么需要多个stage呢?理论上第一个stage已经可以输出完整的信息了,为什么还需要后面重复的stages呢。这是因为关键点之间有相互的语义信息,例如在stage1中,可能只检测出了眼睛,但是没有检测出鼻子,在stage2中,由于输入中带有satge1的输出,那么stage2就更有更可能根据眼睛再推测出鼻子的位置,因此后面的stage可以利用前面stage提取的信息,进一步优化检测结果,对于一些比较难检测的关键点很有作用。更直白一点的解释就是所有关键点的检测难易程度是不一样的,有一些眼睛,鼻子等视觉特征非常明显,而有一些关键点可能会随着衣着,遮挡,首饰等有非常大的变化,因此前面的stage检测一些简单的关键点,后面的stage再根据前面检测出的关键点检测更复杂一些的关键点,这是一个渐进优化的过程。

PCM

PCM其实就是关键点的热力图。Part confidence map。用来表征关键点的位置。假设需要输出18个人体关键点信息,那么PCM会输出19个通道,最后一个通道作为背景。理论上不输出背景也没有什么关系,但是输出背景有两个好处,一是增加了一个监督信息,有利于网络的学习,二是背景输出继续作为下一个stage的输入,有利于下一个stage获得更好的语义信息。下图是输入一张图片,输出19个PCM的示意图。

虽然说一个关键点对应的是一个pcm中的一个像素,但是一般不这么做,一般会用高斯核来创建PCM的GroundTruth。如果没有高斯核,那么gt附件的点被强制当做负样本来学习,但是实际上该点对应的感受域(黄色虚线框)其实与gt点对应的感受域(红色虚线框)非常接近,导致神经网络很迷惑,这到底是有还是没有关键点?甚至有的时候由于标注存在误差,可能标注的gt点反而没有旁边的负样本点准确,那么神经网络就更迷惑了,学个XX啊。一会跟我说圆的是苹果,一会有跟我说圆的是梨,让我怎么个学呢?因此用高斯核的PCM ground truth能够非常好的缓解这个问题。因为标签点附件的点已经不是简单的当做负样本,还是根据高斯分布同样作为正样本,只是置信度稍低一点,这更符合逻辑。

PAF

PCM是大部分的关键点检测网络里面都会用到的技术,相信很多朋友都已经有所了解,而PAF则是openpose的核心,是openpose区别于其他关键点检测框架的最大特性。中文可以翻译为关键点的亲和力场,用来描述不同关键点之间的亲和力属于同一个人的不同关节,亲和力大,不同人之间的关节,亲和力小。由于openpose是一个bottom-up的姿态估计网络,也就是先不管关节是谁的,先一股脑的检测出来,然后接下来再确定哪些关节的亲和力大,那么把它们划分为同一个人。如下图所示,由于图片中有两个人的实例,检测出了两个左眼与两个左耳,那么如何进行配对呢?此时就是PAF的作用了,PAF会描述任意两个关节之间的亲和力(例如检测出2个左眼与2个左耳,那么每个左眼都能得到和所有左耳的亲和力,也就是一共有4个亲和力),如下图所示,颜色越黄,表示两个关键点之间的亲和力越强,左耳的1点与左眼的1点亲和力明显大于左眼1与左耳2,因此将左眼1与左耳1进行配对。同样的左耳2与左眼2的亲和力更大,因此将左耳2与左眼2进行配对。

以上是关于PAF作用的描述,那么究竟PAF是如何实现的呢?实际上并不复杂。为了描述方便(接地气),我这里不使用论文中的描述符号和公式,用最直白,接地气的大白话来描述。openpose首先把各个关节进行了人为的配对,如下图所示,一共19对。可以理解成19根骨骼,每一根骨骼连接了两个关节。一个PAF热图对应一根骨骼。

刚开始的时候我怎么也不明白,18个关节直接怎么会连出19根骨骼,最后把所有骨骼画出来才明白。原来有的关节可以在多根骨骼上面,而且openpose增加了耳朵和肩膀之间的虚拟骨骼。如下图红色连接所表示的虚拟骨骼,所以一共是19根骨骼,也就是19个PAF场。由于PAF是用向量来表示的,因此PAF的输出通道是19*2=38,因为一个向量需要由x和y两个标量表示,因此PAF输出通道是19的2倍。

PAF具体是怎么表达的呢?来看一根左胯到左膝盖的连接骨骼对应的PAF场,首先我们知道骨骼在真实世界中是有长度和宽度的。长度就是骨骼两端的两个关节之间的距离,那么骨骼的宽度呢?可以通过超参来设置,例如假设该骨骼的宽度为α,那么我们可以定义在骨骼内的点亲和力向量不为0,在骨骼外面的点的亲和力向量为0。

如上图所示,红色的点在骨骼内,所以在PAF场中就是非零向量,绿色的点在骨骼外面,所以在PAF场中用0向量表示。那么有意义的红色点的向量是多少呢?openpose使用了从一个关节指向另一个关节的单位向量来表示,即图中黄色向量的单位长度向量来表示。因此最终的PAF场如下图所示(蓝色部分为0向量区域):

如果某一个像素点在多个骨骼内部,那么该像素点的PAF向量取所有向量的均值向量。

参考:

[多图/秒懂]白话OpenPose,最受欢迎的姿态估计网络-CSDN博客

  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
# 导入所需的库 import cv2 import time import numpy as np # 加载OpenPose模型 net = cv2.dnn.readNetFromTensorflow("C:\Users\1\Desktop\onem.jpg") # 配置OpenCV窗口 cv2.namedWindow("OpenPose Demo", cv2.WINDOW_NORMAL) # 加载要测试的像 image = cv2.imread("C:\Users\1\Desktop\onem.jpg") # 获取像的宽和高 width = image.shape[1] height = image.shape[0] # 创建一个4D blob,将像传递给OpenPose模型 blob = cv2.dnn.blobFromImage(image, 1.0 / 255, (368, 368), (0, 0, 0), swapRB=False, crop=False) # 设置输入blob net.setInput(blob) # 运行前向传递,获取OpenPose模型的输出 start = time.time() output = net.forward() end = time.time() # 输出运行时间 print("OpenPose took {:.2f} seconds".format(end - start)) # 获取输出blob的大小 H = output.shape[2] W = output.shape[3] # 创建一个空列表,用于存储检测到的人体姿态 points = [] # 遍历检测到的人体关键点 for i in range(18): # 提取x和y坐标 probMap = output[0, i, :, :] minVal, prob, minLoc, point = cv2.minMaxLoc(probMap) # 如果概率大于阈值,则将其添加到列表中 if prob > 0.1: x = int((width * point[0]) / W) y = int((height * point[1]) / H) points.append((x, y)) # 绘制检测到的人体姿态 for i, point in enumerate(points): cv2.circle(image, point, 5, (0, 255, 255), thickness=-1, lineType=cv2.FILLED) cv2.putText(image, "{}".format(i), point, cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, lineType=cv2.LINE_AA) # 显示结果 cv2.imshow("OpenPose Demo", image) cv2.waitKey(0) cv2.destroyAllWindows()
06-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值