目录
引言
这份代码使用了 MediaPipe 库中的 Pose 模型和 Hands 模型,以及 OpenCV 库,用于实时监测摄像头捕捉到的视频中的姿势和手部动作。主要功能包括标记关键点、绘制姿势连接线以及通过手部与鼻子、嘴的相对位置判定实现了简单的动作监测。
1.过程简介
这段代码实现了使用MediaPipe库进行人体姿势和手部动作检测,并在摄像头视频流上展示检测结果和实时FPS。
首先,导入了需要的库,包括cv2和mediapipe。然后,通过mp_pose.Pose()和mp_hands.Hands()初始化了MediaPipe的Pose和Hands模型。
接下来,通过cap = cv2.VideoCapture(0)打开了摄像头,获取视频流。然后,通过循环读取每一帧的图像,直到视频结束。
在循环中,首先将BGR图像转换为RGB图像,然后分别使用pose.process()和hands.process()运行姿势和手部检测模型,获得检测结果。
接着,通过mp.solutions.drawing_utils.draw_landmarks()方法绘制姿势关键点和连接线。如果检测到手部关键点,遍历每个手部关键点,将关键点绘制为圆点。
在手部检测的过程中,同样检测了鼻尖和嘴巴的位置,判断手部和鼻尖、嘴巴的距离是否小于一定阈值,如果满足条件,则认为在摸鼻子或摸嘴巴。
在最后,计算FPS并显示在图像上,然后通过cv2.imshow()显示图像。同时,通过cv2.waitKey(1)判断是否按下ESC键,如果是则退出循环。
最后,释放摄像头资源并关闭所有窗口。
2. 代码结构
2.1 导入库
import cv2 import mediapipe as mp import time
导入 OpenCV 和 MediaPipe 库。
2.2 初始化模型
mp_pose = mp.solutions.pose mp_hands = mp.solutions.hands pose = mp_pose.Pose() hands = mp_hands.Hands()
初始化姿势检测模型和手部检测模型。
2.3 读取视频流或摄像头
cap = cv2.VideoCapture(0)
打开默认摄像头,获取视频流。
2.4 初始化FPS计算
fps_start_time = time.time() fps_frame_count = 0 fps = 0
记录开始时间和帧数,计算每秒帧数(FPS)。
2.5 主循环
while cap.isOpened(): ret, frame = cap.read() if not ret: break
主循环用于读取视频流的每一帧。
2.6 转换BGR图像为RGB图像
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
将每一帧从 BGR 转换为 RGB,以适应 MediaPipe 模型。
2.7 运行姿势检测模型和手部检测模型
pose_results = pose.process(rgb_frame) hand_results = hands.process(rgb_frame)
运行姿势检测模型和手部检测模型,获取检测结果。
2.8 绘制姿势关键点及连接线
if pose_results.pose_landmarks: mp.solutions.drawing_utils.draw_landmarks(frame, pose_results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
通过 mp.solutions.drawing_utils.draw_landmarks
绘制姿势关键点及连接线。
2.9 检测手部关键点
if hand_results.multi_hand_landmarks: for landmarks in hand_results.multi_hand_landmarks: # 处理手部关键点
对检测到的手部关键点进行处理。
2.10 判断手部与鼻子、嘴的相对位置
# 判断手是否接近鼻子
distance_to_nose = cv2.norm((nose_x, nose_y), (hand_x, hand_y))
if distance_to_nose < 10: # 调整阈值以适应你的实际情况
cv2.putText(frame, "Touching Nose", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 155, 155), 2,cv2.LINE_AA)
# 判断手是否接近嘴巴
distance_to_mouth = cv2.norm((mouth_x, mouth_y), (hand_x, hand_y))
if distance_to_mouth < 20: # 调整阈值以适应你的实际情况
cv2.putText(frame, "Touching Mouth", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 155, 155), 2,cv2.LINE_AA)
# 判断手部和鼻尖位置关系 # 判断手部和嘴巴位置关系
通过相对位置判定手部与鼻子、嘴的关系。
2.11 计算并显示FPS
# 计算FPS
fps_frame_count += 1
if fps_frame_count >= 15:
fps_end_time = time.time()
fps = round(fps_frame_count / (fps_end_time - fps_start_time), 2)
fps_frame_count = 0
fps_start_time = time.time()
# 显示FPS
cv2.putText(frame, f"FPS: {fps}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
# 计算并显示FPS
计算帧率,并在视频窗口上方显示。
2.12 显示结果
cv2.imshow('Pose and Hand Detection', frame)
使用 cv2.imshow
显示最终结果。
2.13 退出程序
if cv2.waitKey(1) & 0xFF == 27: # 按ESC键退出 break
通过按下 ESC 键退出程序。
2.14 释放资源
cap.release() cv2.destroyAllWindows()
释放摄像头资源,关闭所有窗口。
3. 实现思路
该代码首先通过 MediaPipe 库提供的 Pose 和 Hands 模型,获取姿势和手部的关键点。然后,通过 OpenCV 绘制姿势关键点和连接线,并在每一帧中检测手部的相对位置,判断是否进行了摸鼻子和摸嘴的动作。
4. 注意事项
- 使用 MediaPipe 提供的模型进行姿势和手部检测。
- 通过 OpenCV 绘制姿势关键点和连接线,提高可视化效果。
- 通过相对位置判定手部与鼻子、嘴的关系,实现了动作监测。
5. 总结
这份代码展示了如何结合 MediaPipe 和 OpenCV 库,实现实时的姿势和手部检测,并通过相对位置的判定,实现了简单的动作监测。代码结构清晰,易于理解和扩展。
行业应用
此模块可以用作汽车内部摄像头的部署,来实时检测驾驶员的驾驶专注度以达到警示驾驶员的目的。
代码实现
import cv2
import mediapipe as mp
import time
# 初始化MediaPipe Pose模型和Hand模型
mp_pose = mp.solutions.pose
mp_hands = mp.solutions.hands
pose = mp_pose.Pose()
hands = mp_hands.Hands()
# 读取视频流或摄像头
cap = cv2.VideoCapture(0) # 0表示默认摄像头
# 初始化FPS计算
fps_start_time = time.time()
fps_frame_count = 0
fps = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 转换BGR图像为RGB图像
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 运行姿势估计模型
pose_results = pose.process(rgb_frame)
# 运行手部估计模型
hand_results = hands.process(rgb_frame)
# 绘制姿势关键点及连接线
if pose_results.pose_landmarks:
mp.solutions.drawing_utils.draw_landmarks(frame, pose_results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
# 检测手部关键点
if hand_results.multi_hand_landmarks:
for landmarks in hand_results.multi_hand_landmarks:
for point in landmarks.landmark:
x, y, _ = int(point.x * frame.shape[1]), int(point.y * frame.shape[0]), int(
point.z * frame.shape[1] * 5)
cv2.circle(frame, (x, y), 5, (155, 155, 0), -1)
# 获取鼻尖位置
if pose_results.pose_landmarks:
nose_landmark = pose_results.pose_landmarks.landmark[mp_pose.PoseLandmark.NOSE]
nose_x, nose_y = int(nose_landmark.x * frame.shape[1]), int(nose_landmark.y * frame.shape[0])
# 获取嘴巴位置
mouth_landmark = pose_results.pose_landmarks.landmark[
int((mp_pose.PoseLandmark.MOUTH_LEFT + mp_pose.PoseLandmark.MOUTH_RIGHT) / 2)]
mouth_x, mouth_y = int(mouth_landmark.x * frame.shape[1]), int(mouth_landmark.y * frame.shape[0])
# 判断手部和鼻尖位置关系,如果距离小于一定阈值,则判定为摸鼻子
for landmarks in hand_results.multi_hand_landmarks:
for point in landmarks.landmark:
hand_x, hand_y, _ = int(point.x * frame.shape[1]), int(point.y * frame.shape[0]), int(
point.z * frame.shape[1] * 5)
# 判断手是否接近鼻子
distance_to_nose = cv2.norm((nose_x, nose_y), (hand_x, hand_y))
if distance_to_nose < 10: # 调整阈值以适应你的实际情况
cv2.putText(frame, "Touching Nose", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 155, 155), 2,
cv2.LINE_AA)
# 判断手是否接近嘴巴
distance_to_mouth = cv2.norm((mouth_x, mouth_y), (hand_x, hand_y))
if distance_to_mouth < 20: # 调整阈值以适应你的实际情况
cv2.putText(frame, "Touching Mouth", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 155, 155), 2,
cv2.LINE_AA)
# 计算FPS
fps_frame_count += 1
if fps_frame_count >= 15:
fps_end_time = time.time()
fps = round(fps_frame_count / (fps_end_time - fps_start_time), 2)
fps_frame_count = 0
fps_start_time = time.time()
# 显示FPS
cv2.putText(frame, f"FPS: {fps}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA)
# 显示结果
cv2.imshow('Pose and Hand Detection', frame)
# 退出程序
if cv2.waitKey(1) & 0xFF == 27: # 按ESC键退出
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
其实我还想要加入眼睛的部分,但是我写的眼睛部分检测的代码有BUG,所以我就暂时没有加上去,等我研究研究啦~~~~
效果展示
ヾ( ̄▽ ̄)Bye~Bye~