python - 使用 OpenPose 计算视频中身体骨骼的角度
问题描述
免责声明:这个问题是关于OpenPose但这里的关键实际上是弄清楚如何使用输出(存储在 JSON 中的坐标)而不是如何使用 OpenPose,所以请考虑将其阅读到最后。
我有一个骑自行车的人的视频(他坐着的侧面,所以我们看到右侧)。我使用 OpenPose 来提取骨架的坐标。OpenPose 在 JSON 文件中提供坐标,如下所示(请参阅文档以获取解释):
{
"version": 1.3,
"people": [
{
"person_id": [
-1
],
"pose_keypoints_2d": [
594.071,
214.017,
0.917187,
523.639,
216.025,
0.797579,
519.661,
212.063,
0.856948,
539.251,
294.394,
0.873084,
619.546,
304.215,
0.897219,
531.424,
221.854,
0.694434,
550.986,
310.036,
0.787151,
625.477,
339.436,
0.845077,
423.656,
319.878,
0.660646,
404.111,
321.807,
0.650697,
484.434,
437.41,
0.85125,
404.13,
556.854,
0.791542,
443.261,
319.801,
0.601241,
541.241,
370.793,
0.921286,
502.02,
494.141,
0.799306,
592.138,
198.429,
0.943879,
0,
0,
0,
562.742,
182.698,
0.914112,
0,
0,
0,
537.25,
504.024,
0.530087,
535.323,
500.073,
0.526998,
486.351,
500.042,
0.615485,
449.168,
594.093,
0.700363,
431.482,
594.156,
0.693443,
386.46,
560.803,
0.803862
],
"face_keypoints_2d": [],
"hand_left_keypoints_2d": [],
"hand_right_keypoints_2d": [],
"pose_keypoints_3d": [],
"face_keypoints_3d": [],
"hand_left_keypoints_3d": [],
"hand_right_keypoints_3d": []
}
]
}
据我了解,每个 JSON 都是视频的一帧。
我的目标是检测特定坐标的角度,如右膝、右臂等。例如:
openpose_angles = [(9, 10, 11, "right_knee"),
(2, 3, 4, "right_arm")]
这是基于以下 OpenPose 骨架虚拟模型:
我所做的是计算三个坐标之间的角度(使用Python):
temp_df = json.load(open(os.path.join(jsons_dir, file)))
listPoints = list(zip(*[iter(temp_df['people'][person_number]['pose_keypoints_2d'])] * 3))
count = 0
lmList2 = {}
for x,y,c in listPoints:
lmList2[count]=(x,y,c)
count+=1
p1=angle_cords[0]
p2=angle_cords[1]
p3=angle_cords[2]
x1, y1 ,c1= lmList2[p1]
x2, y2, c2 = lmList2[p2]
x3, y3, c3 = lmList2[p3]
# Calculate the angle
angle = math.degrees(math.atan2(y3 - y2, x3 - x2) -
math.atan2(y1 - y2, x1 - x2))
if angle < 0:
angle += 360
我在一些博客上看到的这种方法(我忘了在哪里),但与 OpenCV 而不是 OpenPose 相关(不确定是否有所不同),但看到的角度没有意义。我们向老师展示了它,他建议我们使用向量来计算角度,而不是使用math.atan2
. 但是我们对如何实现这一点感到困惑。
总而言之,这是一个问题 - 计算角度的最佳方法是什么?如何使用向量计算它们?
解决方案
你的老师是对的。我怀疑问题是 3 个点可以根据顺序组成 3 个不同的角度。只需考虑三角形中的角度。您似乎也忽略了第三个坐标。
重建骨架
在您的图片中,您指出骨骼的边缘/骨骼是
edges = {(0, 1), (0, 15), (0, 16), (1, 2), (1, 5), (1, 8), (2, 3), (3, 4), (5, 6), (6, 7), (8, 9), (8, 12), (9, 10), (10, 11), (11, 22), (11, 24), (12, 13), (13, 14), (14, 19), (14, 21), (15, 17), (16, 18), (19, 20), (22, 23)}
我从你的 json 文件中得到积分
np.array(pose['people'][0]['pose_keypoints_2d']).reshape(-1,3)
现在我绘制忽略第三个组件以了解我正在使用的内容。请注意,这并不会改变比例,因为第三个分量与其他分量相比非常小。
一个人肯定会认出一个颠倒的人。我注意到似乎有某种伪影,但我怀疑这只是识别错误,在其他框架中会更好。
计算角度
回想一下,点积除以范数的积给出了角度的余弦。请参阅关于点积的维基百科文章。我将包括那篇文章中的相关图片。所以现在我可以像这样得到两个连接边缘的角度。
def get_angle(edge1, edge2):
assert tuple(sorted(edge1)) in edges
assert tuple(sorted(edge2)) in edges
edge1 = set(edge1)
edge2 = set(edge2)
mid_point = edge1.intersection(edge2).pop()
a = (edge1-edge2).pop()
b = (edge2-edge1).pop()
v1 = points[mid_point]-points[a]
v2 = points[mid_point]-points[b]
angle = (math.degrees(np.arccos(np.dot(v1,v2)
/(np.linalg.norm(v1)*np.linalg.norm(v2)))))
return angle
例如,如果你想要肘角,你可以做
get_angle((3, 4), (2, 3))
get_angle((5, 6), (6, 7))
给你
110.35748420197164
124.04586139643376
看我的骨架照片时,这对我来说是有道理的。它比直角多一点。
如果我必须计算两个不共享一点的向量之间的角度怎么办?
在这种情况下,您必须更加小心,因为在这种情况下,向量方向很重要。首先这里是代码
def get_oriented_angle(edge1, edge2):
assert tuple(sorted(edge1)) in edges
assert tuple(sorted(edge2)) in edges
v1 = points[edge1[0]]-points[edge1[1]]
v2 = points[edge2[0]]-points[edge2[1]]
angle = (math.degrees(np.arccos(np.dot(v1,v2)
/(np.linalg.norm(v1)*np.linalg.norm(v2)))))
return angle
如您所见,代码要容易得多,因为我不为您订购积分。但这很危险,因为两个向量之间有两个角度(如果您不考虑它们的方向)。确保两个向量都指向您正在考虑角度的点的方向(也可以在相反的方向上工作)。
这是与上面相同的示例
get_oriented_angle((3, 4), (2, 3)) -> 69.64251579802836
如您所见,这不同意get_angle((3, 4), (2, 3))
!如果您想要相同的结果,则必须在两种情况下都将 3 放在第一个(或最后一个)。
如果你这样做
get_oriented_angle((3, 4), (3, 2)) -> 110.35748420197164
与上面的角度相同。
推荐阅读
- c++ - 为什么这个对象不必调用它的构造函数?
- ssl-certificate - Discord.py 证书验证失败:
- mysql - 当我在 Mysql 中尝试在我的表中进行部分搜索时,它给了我 Error Empty set (0.00 sec)
- python - 使用 pandas 从 datetime 对象转换从午夜开始的毫秒数
- c# - Unity 2D Trigger 只能由一个 Player Prefab 触发
- azure - Azure.Storage.Blobs.BlobServiceClient CopyFromUri() 在返回最新的 ETag 之前似乎没有完成复制
- javascript - JS:不确定为什么函数返回
- reactjs - 从域调用时,Firebase 函数不执行
- python - Python WebScraping FlashScore
- ios - 如何使用附加数据将 apns 令牌发送到服务器