前期的文章,我们介绍了MediaPipe对象检测与对象分类任务,也分享了MediaPipe的人手手势识别。在进行人手手势识别前,MediaPipe首先需要进行人手的检测与人手坐标点的检测,经过以上的检测后,才能把人手的坐标点与手势结合起来,进行相关的手势识别。
MediaPipe人手坐标点检测模型可以根据用户输入的图片或者视频,进行人手21个关键点的检测,并输出相关的关键点的坐标。
MediaPipe人手坐标点检测模型可以识别人手的21个关键点。MediaPipe人手关键点检测模型共有三种输入模式:
- IMAGE:单图像输入模式。
- VIDEO:视频模式。
- LIVE_STREAM:输入数据实时流的模式,例如来自摄像机的输入数据。在这种模式下,必须调用resultListener来设置监听器以异步接收结果。
MediaPipe人手坐标点检测模型包含2个模型:
- 一个是人手检测模型,其模型需要检测出输入图像或者视频中人手的位置。
- 另外一个模型是人手关键点检测模型,当检测到人手后,启用此模型来进行人手关键点的预测。
当我们使用MediaPipe人手坐标点检测模型时,其模型后台是调用了以上2个模型。由于运行手掌检测模型比较耗时,因此在视频或直播运行模式下,Hand Landmarker人手检测使用一帧中手部位置模型定义的边界框来定位后续帧中的手部区域。仅当手部检测模型不再识别手的存在或无法跟踪帧内的手时,手部关键点检测模型才会重新触发手掌检测模型。这减少了 Hand Landmarker 触发手掌检测模型的次数,有效降低了运算量,提高了运行速度。(基于CPU延时17.12ms,而GPU模式延时12.27ms)
代码实现人手21个关键点检测
在运行本节代码前,首先需要安装python以及MediaPipe库。并下载人手关键点检测模型hand_landmarker.task。
!pip install -q mediapipe==0.10.0!wget -q https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task
然后准备一张需要检测的图片或者一段视频,并输入如下代码:
- 首先需要导入相关的包,这里需要确认一下是否已经安装了MediaPipe
- 然后创建人手坐标点检测器detector = vision.HandLandmarker.create_from_options(options)
- 加载图片或者视频,当然也可以加载视频流。
- 模型检测,输出相关的坐标点
- 可视化模型检测结果
# 导入相关的包import mediapipe as mpfrom mediapipe.tasks import pythonfrom mediapipe.tasks.python import vision# 创建 人手检测模型检测器base_options = python.BaseOptions(model_asset_path='hand_landmarker.task')options = vision.HandLandmarkerOptions(base_options=base_options, num_hands=2)detector = vision.HandLandmarker.create_from_options(options)# 加载图片image = mp.Image.create_from_file("image.jpg")# 人手坐标点检测detection_result = detector.detect(image)# 可视化人手检测annotated_image = draw_landmarks_on_image(image.numpy_view(), detection_result)cv2_imshow(cv2.cvtColor(annotated_image, cv2.COLOR_RGB2BGR))
HandLandmarkerResult包含三个组成部分。每个组件都是一个数组,其中每个元素包含单个检测到的手部结果:
- 惯用手:用手习惯表示检测到的手是左手还是右手。
- 坐标点:有 21 个手部坐标,每个坐标由x、y和z坐标组成。坐标z表示深度,以手腕处的深度为原点。值越小,表示距离相机越近。
- 世界坐标点:21 个手部坐标也以世界坐标呈现。每个坐标由x、y和z组成,代表以米为单位的真实世界 3D 坐标,原点位于手的几何中心。
#坐标点输出格式如下:HandLandmarkerResult: Handedness: Categories #0: index : 0 score : 0.98396 categoryName : Left Landmarks: Landmark #0: x : 0.638852 y : 0.671197 z : -3.41E-7 Landmark #1: x : 0.634599 y : 0.536441 z : -0.06984 ... (21 landmarks for a hand) WorldLandmarks: Landmark #0: x : 0.067485 y : 0.031084 z : 0.055223 Landmark #1: x : 0.063209 y : -0.00382 z : 0.020920 ... (21 world landmarks for a hand)
检测到人手后,就可以进行人手坐标的检测,当模型运行完人手坐标点检测后,输出相关的坐标点与惯用手标识。最后使用可视化函数,把模型检测到的坐标点进行可视化展示。
from mediapipe import solutionsfrom mediapipe.framework.formats import landmark_pb2import numpy as npMARGIN = 10 # pixelsFONT_SIZE = 1FONT_THICKNESS = 1HANDEDNESS_TEXT_COLOR = (88, 205, 54) # vibrant greendef draw_landmarks_on_image(rgb_image, detection_result): hand_landmarks_list = detection_result.hand_landmarks handedness_list = detection_result.handedness annotated_image = np.copy(rgb_image) for idx in range(len(hand_landmarks_list)): hand_landmarks = hand_landmarks_list[idx] handedness = handedness_list[idx] hand_landmarks_proto = landmark_pb2.NormalizedLandmarkList() hand_landmarks_proto.landmark.extend([landmark_pb2.NormalizedLandmark(x=landmark.x, y=landmark.y, z=landmark.z) for landmark in hand_landmarks ]) solutions.drawing_utils.draw_landmarks(annotated_image,hand_landmarks_proto,solutions.hands.HAND_CONNECTIONS,solutions.drawing_styles.get_default_hand_landmarks_style(),solutions.drawing_styles.get_default_hand_connections_style()) height, width, _ = annotated_image.shape x_coordinates = [landmark.x for landmark in hand_landmarks] y_coordinates = [landmark.y for landmark in hand_landmarks] text_x = int(min(x_coordinates) * width) text_y = int(min(y_coordinates) * height) - MARGIN cv2.putText(annotated_image, f"{handedness[0].category_name}",(text_x, text_y), cv2.FONT_HERSHEY_DUPLEX, FONT_SIZE, HANDEDNESS_TEXT_COLOR, FONT_THICKNESS, cv2.LINE_AA) return annotated_image
评论留言