Skip to content

OpenCV OpenPose 手部关键点识别

HuggingFace 下载模型文件 models_hand_pose_deploy.prototxtpose_iter_102000.caffemodel,然后放到同一目录下。

可参考官方 GitHub 来安装 OpenPose。本示例未使用 OpenPose 库,仅使用 OpenCV 和 OpenPose 官方提供的模型文件。

py
import time

import cv2
import numpy as np

proto_file = "models_hand_pose_deploy.prototxt"
weights_file = "pose_iter_102000.caffemodel"
n_points = 22
POSE_PAIRS = [
    [0, 1],
    [1, 2],
    [2, 3],
    [3, 4],
    [0, 5],
    [5, 6],
    [6, 7],
    [7, 8],
    [0, 9],
    [9, 10],
    [10, 11],
    [11, 12],
    [0, 13],
    [13, 14],
    [14, 15],
    [15, 16],
    [0, 17],
    [17, 18],
    [18, 19],
    [19, 20],
]

threshold = 0.2

cap = cv2.VideoCapture(0)
has_frame, frame = cap.read()

frame_width = frame.shape[1]
frame_height = frame.shape[0]

aspect_ratio = frame_width / frame_height

in_height = 368
in_width = int(((aspect_ratio * in_height) * 8) // 8)

net = cv2.dnn.readNetFromCaffe(proto_file, weights_file)
k = 0

while cap.isOpened():
    k += 1
    t = time.time()
    has_frame, frame = cap.read()
    frame_copy = np.copy(frame)
    if not has_frame:
        cv2.waitKey()
        break
    inp_blob = cv2.dnn.blobFromImage(
        frame, 1.0 / 255, (in_width, in_height), (0, 0, 0), swapRB=False, crop=False
    )
    net.setInput(inp_blob)
    output = net.forward()
    print("forward = {}".format(time.time() - t), end=", ")

    points = []

    for i in range(n_points):
        prob_map = output[0, i, :, :]
        prob_map = cv2.resize(prob_map, (frame_width, frame_height))
        min_val, prob, min_loc, point = cv2.minMaxLoc(prob_map)

        if prob > threshold:
            cv2.circle(
                frame_copy,
                (int(point[0]), int(point[1])),
                6,
                (0, 255, 255),
                thickness=-1,
                lineType=cv2.FILLED,
            )
            cv2.putText(
                frame_copy,
                "{}".format(i),
                (int(point[0]), int(point[1])),
                cv2.FONT_HERSHEY_SIMPLEX,
                0.8,
                (0, 0, 255),
                2,
                lineType=cv2.LINE_AA,
            )
            points.append((int(point[0]), int(point[1])))
        else:
            points.append(None)

    for pair in POSE_PAIRS:
        part_a = pair[0]
        part_b = pair[1]
        if points[part_a] and points[part_b]:
            cv2.line(
                frame,
                points[part_a],
                points[part_b],
                (0, 255, 255),
                2,
                lineType=cv2.LINE_AA,
            )
            cv2.circle(
                frame, points[part_a], 5, (0, 0, 255), thickness=-1, lineType=cv2.FILLED
            )
            cv2.circle(
                frame, points[part_b], 5, (0, 0, 255), thickness=-1, lineType=cv2.FILLED
            )
    cv2.imshow("webcam", frame)
    print("total = {}".format(time.time() - t))

    key = cv2.waitKey(1)
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()