在做 MediaPipe 项目的时候,经常需要唤醒摄像头进行视频采集,学习的时候可以使用视频替换摄像头采集动作,这就是本篇博客的的由来。
MediaPipe 入门案例
为了便于学习,我们先直接展示入门案例,然后查看从代码角度进行讲解。
import cv2
import mediapipe as mp
# 创建VideoCapture对象,读取视频
cap = cv2.VideoCapture('./demo.mp4')
# 初始化mediapipe
mp_hands = mp.solutions.hands.Hands()
while cap.isOpened():
# 读取视频帧
success, image = cap.read()
if not success:
print("读取失败")
continue
# 将图像转换为RGB格式
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 处理图像
results = mp_hands.process(image)
# 将图像转换回BGR格式
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
# 显示结果
cv2.imshow('MediaPipe Hands', image)
if cv2.waitKey(5) & 0xFF == 27:
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
为了让代码跑起来,需要提前安装 opencv-python
库和 mediapipe
库,直接使用 pip
命令安装即可。
视频我们使用了 B 站 @蜜加原创手指舞 的视频,只做学习演示 Demo。
上述代码运行结果如下所示。
接下来我们逐行解释一下代码。
读取视频文件
# 创建VideoCapture对象,读取视频
cap = cv2.VideoCapture('./demo.mp4')
上述代码初始化了一个名为 cap
的 VideoCapture
对象,用于从当前目录中名为 'demo.mp4'
的视频文件中读取帧。
cv2.VideoCapture()
函数接受一个参数,即视频文件的路径。
VideoCapture
对象可以用于从视频文件中读取帧,也可以用于从摄像头中读取帧。如果要从摄像头中读取帧,则可以将参数设置为摄像头的索引,例如cap = cv2.VideoCapture(0)
,其中 0 表示默认摄像头的索引。
如果只是单纯查看视频,可以使用下述代码:
import cv2
# 初始化对象
cap = cv2.VideoCapture('./demo.mp4')
# 检查视频是否打开
if not cap.isOpened():
print("视频文件打开失败")
# 读取视频
while cap.isOpened():
# 逐帧读取
ret, frame = cap.read()
if ret:
# 展示读取结果
cv2.imshow('帧', frame)
# 按 Q 退出
if cv2.waitKey(25) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
初始化 Hands 对象
mp_hands = mp.solutions.hands.Hands()
mp.solutions.hands.Hands()
函数创建 Hands 类的一个新实例,该类是 MediaPipe Hands 解决方案的一部分。
该类提供了检测图像或视频帧中手部的方法,并返回有关检测到的手部的信息,例如它们的关键点和左右手性。
接下来可以在循环中读取视频的每一帧,然后使用 mp_hands.process(imgRGB)
获取【手位置】。
import cv2
import mediapipe as mp
cap = cv2.VideoCapture('./demo.mp4')
# 定义并引用mediapipe中的hands模块
mp_hands = mp.solutions.hands.Hands()
while True:
success, img = cap.read()
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # cv2图像初始化
results = mp_hands.process(imgRGB)
print(results.multi_hand_landmarks)
cv2.imshow("HandsImage", img) # CV2窗体
cv2.waitKey(1) # 关闭窗体
代码运行得到如下结果。
landmark {
x: 0.18026168644428253
y: 0.4238351583480835
z: -0.0214223675429821
}
landmark {
x: 0.45827752351760864
y: 0.39915671944618225
z: 0.011419275775551796
}
mp_hands.process(imgRGB)
是 MediaPipe Hands 解决方案的一部分,用于在 RGB 图像中检测手部。
它接受一个 RGB 图像作为输入,并返回一个 SolutionOutputs 对象,其中包含有关检测到的手部的信息。
results.multi_hand_landmarks
是 SolutionOutputs 对象的一个属性,它包含一个列表,其中每个元素都是一个 HandLandmark 对象,表示检测到的一个手部的关键点。如果没有检测到手部,则 results.multi_hand_landmarks
为 None。
每个 HandLandmark 对象包含一个 landmark
属性,它是一个列表,其中每个元素都是一个 NormalizedLandmark 对象,表示手部的一个关键点。
NormalizedLandmark 对象包含 x
、y
和 z
属性,表示关键点在图像坐标系中的归一化坐标。x
和 y
属性的值在 [0, 1]
范围内,表示关键点在图像中的位置。
z
属性的值表示关键点的深度,但在 MediaPipe Hands 解决方案中未使用。
在关键位置绘制图形
前文已经读取到手部识别的关键节点,接下来在读取到的位置处绘制图形。
if results.multi_hand_landmarks:
for handLms in results.multi_hand_landmarks:
for index, x_y in enumerate(handLms.landmark):
h, w, c = img.shape
# 获取节点关键坐标
cx, cy = int(x_y.x * w), int(x_y.y * h)
# 绘制一个圆形
cv2.circle(img, (cx, cy), 7, (4, 255, 255), cv2.FILLED)
接下来我们实现连接手指骨架,在上述代码中输入如下代码。
mp_draw = mp.solutions.drawing_utils
mp.solutions
提供了使用 MediaPipe 解决方案在图像或视频帧上绘制关键点和连接的实用函数。
该模块包含几个函数,可用于在图像或视频帧上绘制关键点和连接,包括 draw_landmarks()
、draw_connections()
和 draw_landmarks_on_image()
。这些函数的输入参数包括要绘制的图像或帧,以及要绘制的关键点或连接。
下面演示如何使用 mp.solutions.drawing_utils
在图像上绘制关键点和连接的示例代码:
# 绘制手部特征点:
mp_draw.draw_landmarks(img, handLms, mp.solutions.hands.HAND_CONNECTIONS)
运行代码得到如下效果。
在上述代码中用到了 draw_landmarks()
函数。
该函数用于在图像中绘制手部关键点和连接。它接受三个参数:
-
img
:要在其上绘制手部关键点和连接的图像。 -
handLms
:一个 HandLandmark 对象,表示要绘制的手部的关键点。可以从 SolutionOutputs 对象的multi_hand_landmarks
属性中获取 HandLandmark 对象。 -
mp.solutions.hands.HAND_CONNECTIONS
:一个常量,表示要绘制的手部关键点之间的连接。
mp_draw.draw_landmarks() 函数原型说明
该函数还可以接受其他参数,用来控制绘制的手部关键点和连接的外观,其原型如下所示:
mp_draw.draw_landmarks(
image: np.ndarray,
landmark_list: Union[mp_hands.HandLandmarkList, mp_pose.PoseLandmarkList],
connections: Optional[mp_drawing.DrawingSpec] = None,
landmark_drawing_spec: Optional[mp_drawing.DrawingSpec] = None,
connection_drawing_spec: Optional[mp_drawing.DrawingSpec] = None
) -> None
-
landmark_list
参数是一个 HandLandmarkList 或 PoseLandmarkList 对象,表示要绘制的手部或姿势的关键点。 -
connections
参数是一个 DrawingSpec 对象,表示要绘制的关键点之间的连接。 -
landmark_drawing_spec
和connection_drawing_spec
参数分别是 DrawingSpec 对象,表示要用于绘制关键点和连接的颜色、线宽和半径。
以下是 DrawingSpec
类的构造函数:
mp_drawing.DrawingSpec(
color: Tuple[int, int, int],
thickness: int = 1,
circle_radius: Optional[int] = None
)
-
color
参数是一个 RGB 元组,表示要用于绘制关键点和连接的颜色。 -
thickness
参数是一个整数,表示要用于绘制连接的线宽。 -
circle_radius
参数是一个整数,表示要用于绘制关键点的半径。
完善一下代码,添加关键点颜色。文章来源:https://www.toymoban.com/news/detail-416534.html
# 连接线样式
lineStyle = mp_draw.DrawingSpec()
lineStyle.color = (0, 0, 255)
lineStyle.thickness = 1
# 绘制手部特征点:
mp_draw.draw_landmarks(img, handLms, mp.solutions.hands.HAND_CONNECTIONS, landmark_drawing_spec=lineStyle)
文章来源地址https://www.toymoban.com/news/detail-416534.html
到了这里,关于MediaPipe上手案例,手部骨架识别,用视频替换代码摄像头采集的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!