### 使用 OpenCV 实现类似 OpenPose 的人体姿态估计并获取关键点 ID
为了使用 OpenCV 实现类似 OpenPose 的人体姿态估计,可以按照以下方法操作:
#### 准备工作
确保安装了必要的库和依赖项。可以通过 pip 安装 opencv-python 和其他所需的 Python 库。
```bash
pip install opencv-python numpy
```
#### 加载预训练模型
加载由 OpenPose 提供的预训练模型权重文件,并设置网络参数。这一步骤对于后续的关键点检测至关重要[^1]。
```python
import cv2
import numpy as np
protoFile = "path/to/pose_deploy_linevec.prototxt"
weightsFile = "path/to/pose_iter_440000.caffemodel"
net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)
frameWidth = 640
frameHeight = 480
inWidth = 368
inHeight = 368
thr = 0.1
```
#### 图像预处理
读入待分析的图像或视频帧,并调整其大小以适应输入到神经网络的要求。
```python
def preprocess_frame(frame):
inpBlob = cv2.dnn.blobFromImage(
frame,
1.0 / 255,
(inWidth, inHeight),
(0, 0, 0),
swapRB=False,
crop=False
)
net.setInput(inpBlob)
output = net.forward()
return output
```
#### 解析输出数据
解析来自 CNN 输出的数据来提取各个关节的位置信息以及它们之间的连接关系。这里会涉及到 PAFs(Part Affinity Fields),即部件亲缘场,用来关联不同部分之间可能存在的联系[^3]。
```python
nPoints = 18 # POSE_PAIRS 中定义的数量加一
keypointsMapping = ['Nose', 'Neck', ... , 'R_Eye'] # 这里省略了一些中间元素
POSE_PAIRS = [[1,2], [1,5], [2,3], [3,4], [5,6], [6,7],
[1,8], [8,9], [9,10], [1,11], [11,12], [12,13],
[1,0], [0,14], [14,16], [0,15], [15,17]]
detected_keypoints = []
for i in range(nPoints):
probMap = output[0, i, :, :]
minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)
if prob > thr :
detected_keypoints.append((int(point[0]), int(point[1])))
else :
detected_keypoints.append(None)
```
上述代码片段展示了如何通过遍历 `output` 数组中的每一个通道(对应于不同的身体部位)来进行阈值判断,从而决定哪些位置被认为是有效的人体关键点[^4]。
#### 绘制结果
最后,在原始图像上绘制出识别出来的骨架结构及其对应的编号标签。
```python
for pair in POSE_PAIRS:
partA = keypointsMapping[pair[0]]
partB = keypointsMapping[pair[1]]
if None not in (detected_keypoints[pair[0]], detected_keypoints[pair[1]]):
A = tuple(detected_keypoints[pair[0]])
B = tuple(detected_keypoints[pair[1]])
cv2.line(frame, A, B, (0, 255, 255), 2)
text_position = ((A[0]+B[0])//2, (A[1]+B[1])//2)
cv2.putText(frame, f"{pair}", text_position, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255))
cv2.imshow('Output-Keypoints', frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
```
这段脚本会在每一对相连的身体部位间画线,并标注这对连线所代表的具体部位对索引号。