OpenPifPafdecode源码解析

更新时间:2023-07-14 22:22:12 阅读: 评论:0

OpenPifPafdecode源码解析
openpifpaf 的decode过程:
⽹络的输出:
1. pif, 原始的输出共有4个, 分别为:
1. joint_intensity_fields, shape 为 [17, output_h, output_w]. 其实就是输出的每个位置上的confidence map, 17表⽰
channel数, 在po检测⾥⾯表⽰总共有多少个关键点需要检测.
2. joint_offt_fields, shape 为[17, 2, output_h, output_w]. 为对应位置上的离其最近的关节点位置的偏移量. 这个是学习得到
的, 2表⽰是两个⽅向(x, y)的偏移量. 所以关节点的真正位置需要把该位置的(x, y)和其两个⽅向的(x_offt, y_offt)相加起来得到.
3. joint_b, shape为[17, output_h, output_w]. 论⽂⾥提到的spread b,是⾃适应并且经过⽹络学习得到的, ⽤来参与loss计算, 在
单身女
decode的时候并没有⽤到.
4. joint_scale_fields. shape为[17, output_h, output_w]. ⾃适应的scale值, ⽤来表明该关键点的scale⼤⼩.不确定是否有⽤在
loss计算⾥. decode的时候则是作为类似gaussian的sigma值参与decode过程.
杜鹃苗2. paf, 原始的输出共有5个, 按照顺序为: (⾸先说明下, 论⽂提出的paf和之前OpenPo及PersonLab提出的连接⽅式都不⼀样. 该论⽂
提出的paf连接为, 每个位置预测出哪两个点需要连接在⼀起, 因此不是单纯的两个关节点之间的直接连接, ⽽是经过了另外⼀个位置进⾏第三⽅连接)
1. joint_intensity_fields, shape为[19, output_h, output_w]. 19表明共有多少个连接需要学习, 对应的是每个输出位置上的paf
的confidence值
2. joint1_fields, shape为[19, 2, output_h, output_w]. 这个位置表明的两个可以连接在⼀起的点中的第⼀个点的信息, 其实就是
偏移值, (x_offt, y_offt).
3. joint2_fields, shape为[19, 2, output_h, output_w]. 同上, 表⽰的是⼀条线段上的第⼆个点的偏移值.
4. joint1_fields_logb, shape为[19, output_h, output_w]. 论⽂⾥提到的spread b,是joint1的, ⽤来参与loss计算和decode. 根
据decode的过程来看, ⽹络输出的这个值是经过log计算后的, 所以叫做logb,在decode的时候需要先exp还原.
5. joint2_fields_logb, shape为[19, output_h, output_w]. 同上, 只不过变成是第⼆个点的b了.
decode过程:
1. normalize_pif. 就是把⽹络的pif 4个输出整合在⼀起, ⾸先是对joint_intensity_fields和joint_scale_fields进⾏扩维, 把shape从[17,
output_h, output_w]变成[17, 1, output_h, output_w]. 接着是根据joint_offt_fields对[output_h, output_w]这么⼤的矩阵上, 对应的位置(x, y) + offt. 举例来说, 原来的joint_offt_fields, 其中[1, :, 4, 5] 这个位置表⽰的offt值为(1, 2), 那么意思就是在(4, 5)这个位置坐标(4, 5)上, 需要加上偏移(1, 2)才
是真正的这个位置所表⽰的关键点坐标值, 也即是(5, 7), 因此最后[1, :, 4, 5] == [5, 7]. 最后把更新后的这三个矩阵concatenate⼀起, 变成[17, 4, output_h, output_w]的pif信息, 4表⽰每个位置上都有四个值, 分别是[confidence, x, y, scale]. 这个时候的[x, y]就是真正的这个点表⽰的关键点的坐标值.
2. normalize_paf. 同pif⼀样, 也是把⽹络的paf 5个输出整合在⼀起. 除了对joint1_fields和joint2_fields进⾏同样的offt相加外(和pif的锡兰山
描写草原的诗句操作⼀样), 还对两个logb进⾏了exp操作, 然后对joint_intensity_fields和两个b进⾏扩维成[19, 1, output_h, output_w]. 最后对更新后的joint_intensity_fields, joint1_fields, joint1_logb进⾏concatenate⼀起, 得到[19, 4, output_h, output_w]⼤⼩的矩阵, 这个存储的全是有关joint1的, 同理, 对joint2做同样的操作, 同样得到[19, 4, output_h, output_w]⼤⼩的矩阵. 4表⽰[confidence, x, y, b]. 需要注意的是joint1和joint2共享同样的confidence值. 最后, 对这两个矩阵进⾏stack⼀起,得到最终的[19, 2, 4, output_h, output_w]输出.
3. _target_intensities: 根据上⾯得到的新的pif信息, 利⽤⽂章提出的公式1, 得到在⾼维空间(也就是⽹络的输⼊分辨率下)的pif_hr,
海苔饼pifhr_scales信息. hr表⽰的就是high resolution的意思. ⽅法就是⾸先找到pif⾥所有confidence > v_th的值, 先把(x, y, s) 都乘上⽹络的scale值, 然后针对这些位置, 以这些位置为中⼼, 位置对应的scale值为施工应急预案
gaussian的sigma, 范围为当前位置对应的
confidence/16(不是很理解为什么是这个值), 接着对这个范围内的值做⾼斯变换, 和pif⾥原来的位置信息相加, 使得本来confidence 就很⾼的位置值更⾼, confidence值低的位置值更低. (具体图⽰可以参考⽂章图3). 源码⾥的scalar_square_add_gaussian函数就是这个作⽤, 这样就得到了pif_hr. cumulative_average函数的作⽤好像是对这个区域的scale求个平均? 没有很理解这个函数的作⽤, 但结果是
作⽤, 这样就得到了pif_hr. cumulative_average函数的作⽤好像是对这个区域的scale求个平均? 没有很理解这个函数的作⽤, 但结果是得到对应的scale值.
4. _score_paf_target: 这个函数的作⽤就是根据上⾯得到的paf信息, 得出哪些点是连在⼀起的. 因为paf的shape是[19, 2, 4,小班区域活动反思
output_h, output_w], 因此对于每个连接, 其对应的paf field shape均为[2, 4, output_h, output_w]. ⾸先, 对于单个线段的信息, 假设为第⼀条线段的信息, 为fourds, shape = [2, 4, output_h, output_w]. ⾸先, 找到fourds⾥每个位置上的confidence值最⼩的那个(源码是scores = np.min(fourds[:, 0], axis=0), 但我感觉因为对于同⼀个feature map上的位置⽽⾔, joint1 和 joint2的confidence是⼀致的, 因此其实就是把feature map上对应位置的score值去出来). 然后, 找到满⾜scores > score_th条件的位置, 把这些位
置取出来,组成个新的fourds. 同理, scores也取出来, 组成个新的scores. 这时fourds的维度就是[2, 4, n], scores的维度是[n, ], n为满⾜前⾯score条件的点的个数. 然后, 找到第⼀条线段对应的pif的channel位置, 例如第⼀条线段在coco是[15, 13], 那么就把pif_hr[15]当作是这个线段的joint1所在的featuremap, pif_hr[13]就是这个线段的joint2所在的featuremap. 因为此时fourds的shape为[2, 4, n],那么fourds[0]就是所有满⾜刚才那个条件的joint1集合, fourds[1]就是joint2集合. 地⼀个函数scalar_values的意思, 就是找到在pif_hr[15]上, 位置为(fourds[0, 1] * lf.stride, fourds[0, 2]*lf.sride)的confidence值,(注意这个confidence是指在pif_hr上的
confidence, 不知道为啥程序⾥变量名起做pifhr_b.) 此时得到的pifhr_b就是joint1对应的在pifhr上的confidence值, 接着执⾏代码scores_b = scores * (pifhr_floor + (1.0 - pifhr_floor) * pifhr_b), 我的理解是这⾏代码的作⽤就是根据confidence对scores进⾏更新, pifhr_floor是0.1, 如果本⾝的pifhr_b值很⼤, 那么其对应的在paf的score就还是很⼤, 如果⼩, 相应的也缩⼩了其对应的paf的score 值. 更新完后得到scores_b, 再根据这个值进⼀步过滤找到符合条件的joint1, joint2点, 最后把符合条件的点集合, 得
到scored_backward⾥的⼀个元素. 因为paf总共有19个channel, 所以scored_backward总共有19个元素, 每个元素都是[7, m]⼤⼩的矩阵, 存储的信息分别是[score_b, joint2_x, joint2_y, joint2_b, joint1_x, joint1_y, joint1_b]. m是scores_b中符合条件的点的个数. 因为元素是先joint2元素信息再是joint1信息, 所以叫做scored_backward. 下⾯还会有在**_pifhr[j2i] (_pifhr[13])**搜索符合条件的joint2的信息, 仿照
上⾯的步骤, 同样得到⼀个[7, n]的矩阵, 信息为[score_b, joint1_x, joint1_y, joint1_b, joint2_x, joint2_y, joint2_b], 因为这个是先jioint1的信息再是joint2的信息, 因此其组成的列表⼜叫做scored_forward, 其实就是看是以joint1为出发点还是终⽌点表⽰的这个线段信息.
5. 总结下先, 3执⾏完之后, 得到了⼀个在⾼分辨率下的pifhr信息和pif_scales信息, shape均为[17, hr_h, hr_w]. 4执⾏完后, 得到了两
个均含有19个元素的列表, 分别叫做scored_forward 和 scored_backward. 列表⾥的每个元素, 都是满⾜⼀系列条件的点的信息, 例如对于scored_forward[0]来说, shape⼤⼩为[7, m], m为点的个数, 7表⽰[score_b, joint1_x, joint1_y, joint1_b, joint2_x, joint2_y, joint2_b], 形象话说, 就是对于7*m的矩阵, 每⼀列都能找到两个点⽤来表⽰线段0. 需要明确的⼀点, 这⾥⾯的两个点, 都还是通过paf 信息得到的点的位置, 并不是在pif信息上的点的位置
6. 接着就是根据3和4得到的结果, ⽤来连线, 判断哪些线段应该连起来组成⼀个⼈**.**
7. _pif_eds函数: pif_eds函数⽤来在lf.pif上找到confidence符合阈值的点的信息, , 然后再在pifhr上找到该点对应的
confidence值, 接着把(v, field_i, xx, yy, ss)组成⼀个ed放⼊eds中, v是在pifhr上的confidence, field
_i是⽤来表明这个点在第⼏个channel上, (xx, yy, ss)都是在pif上的位置和scale信息. 最后, 对eds按照v的值降序排列, 越靠近前⾯的ed, confidence值更⼤.(⽐较奇怪的是为什么confidence是在pifhr找, 但(xx, yy, ss)都是在pif上⾯找)
8. ⾸先根据3得到的pifhr_scales⽣成同样⼤⼩的矩阵occupied, 找到了pif_eds之后, 按照排过序的eds序号, 先从confidence值最
⼤的ed进⾏寻找. ⾸先判断当前ed的(x, y)是否超过了occupied的范围, 如果超过就寻找下⼀个ed, 没有就返回当前
occupied[y, x]的值. (这边同样有个问题, occupied初始化为0, 那寻找第⼀个ed的时候, ⽆论是否超出范围, 返回的值都为0, 也就是说按照源码来说, 第⼀个ed是没有⽤的?我尝试了把第⼀个ed当作正常运⾏放进去, 发现结果没有太⼤差别, 就是最后的anno score值变⼤了⼀些. 不过python格式的程序速度慢了将近⼀倍.) 然后会执⾏函数scalar_square_add_single, 这个函数的作⽤就是让occupied矩阵在(x*stride, y*stride) 为中⼼, 范围为max(4, s*stride)的范围内加1. 这样就相当于更新了以(x, y)为中⼼的occupied值. 接着, 根据ed的(x, y, v) 和 当前所处的channel编号f, 构建Annotation类. ann.data是⼀个[17, 3]的矩阵, 存储的就是⼀个完整的⼈体po应该有的关节点个数. ann.skeleton_m1就是下标从0开始的[19, 3]的skeleton连接编号. 初始化ann的时候, 会根据f的值把传⼊的(x, y, v) 放进去ann.data
[f]上. 接着, 就会以当前ann为已有的skeleton信息, 以前⾯得到的_paf_forward, _paf_backward连接信息进⾏_grow操作.
9. _grow函数: 在进⾏从_paf_forward, _paf_backward抽取信息前, 会先对当前的ann执⾏ann.frontier_iter()函数. ann.frontier_iter()函数的
意思就是找到当前ann.data⾥, 应该和ann.data⾥已有值的点相连的点, 但是却没有在ann.data⾥⾯的点. 然后, 根据这个点是在已有点的后⾯(即已有点是joint1, 未找到点是joint2)还是在前⾯, 判断该点是处于forward状态还是backward状态. 接着, 对这些所有点进⾏按照已有值的点的confidence值降序排列. (函数最终会得到⼀个列表的集合, 每个列表的元素都是[confidence, connection_i, True/Fal, j1i, j2i], confidence是已有点的confidence, connection_i是这个点应在的线段连接编号, True表明已有点是joint1, 放进去的这个点是joint2, j1i 和 j2i就是这个connection连接的两个点的channel编号). 最后, 从这个列表frontier⾥取出第⼀个值, 表明是当前已有的ann.data⾥, confidence值最⾼的那个点应该连接的点的信息. 取出的值就是上⾯所讲的列表的元素值信息, 如果是True(表明为forward), 则xyv = ann.data[j1i], directed_paf_field = paf_forward[i], directed_paf_field_rever = paf_backward[i], 否则的话, xyv = ann.data[j2i], directed_paf_field = paf_forward[i], directed_paf_field_rever = paf_backward[i]. xyv是从ann.data⾥取出的⽬前confidence 值最⾼且需要额外的⼀个点和它连接的点(new_xyv), directed_paf_field就是new_xyv所在的paf_field,
directed_paf_field_rever就是刚好xyv所在的paf_field. (刚好⼀个是paf_forward, ⼀个是paf_backward). 然后, 根据得到的directed_paf_field, 执⾏_grow_connection函数.
萝卜大骨汤
10. **_grow_connection**函数. 这个函数⽐较简单, ⾸先是在paf_field上, 以(x,y)为中⼼, 找到在paf_field⾥的所有点符合条件的点, 拿出来
构成新的paf_field, 然后, 在这个新的paf_field⾥⾯, 计算这些点和xy这个点的距离, 并根据距离更新⾥⾯点的score值, 最后选择score值最⼤的那个点作为返回值. 为了保证找的这个点是正确的, 会根据找到的这个点进⾏rever match, 步骤和前⾯的⼀致, 判断通过rever找到点是否和(x,y)满⾜距离阈值条件. 如果是, 就把找打的这个点当作新的⼀个点放进ann.data⾥⾯. 这样循环遍历, 就能把ann给尽量的填充满.
11. 当对当前的ed点进⾏grow_connection之后, 会根据之前得到的pifhr_scales对ann.data的每个点加上对应的scale值, 然后根据⽬前
已有的ann.data值, 再更新⼀遍每个ann.data⾥的点对应的occupied矩阵, 就是执⾏函数scalar_square_add_single函数. 最后选择下⼀个ed点进⾏grow, 直到所有的ed点都遍历过⼀次. 最后再对所有的anns执⾏complete_annotations操作, 就是寻找对于每个ann上额外的空置的点(应该有点和它连接的实际上没有)是否还有可能有其它点和它连在⼀起, 就是再执⾏⼀边_grow操作.
12. **soft_nms**函数: 对11得到的annos执⾏nms操作, 过滤掉⼀些有可能不符合要求的ann. ann.score值是其中ann.data中每个点的
score值的加权平均.

本文发布于:2023-07-14 22:22:12,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1081645.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:信息   位置   连接   需要   对应   得到   线段
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图