发布时间:2024-07-19 18:01
MediaPipe为直播和流媒体提供跨平台、可定制的机器学习(MachineLearning) 解决方案。利用mediapipe和python可以实现以下功能:
本文代码运行环境:win10,python3.7,pycharm,mediapipe 0.8.10,
涉及到的Python库为:opencv-python,mediapipe,matplotlib
在python中使用pip install
指令安装库很简单,由于包比较大所以使用豆瓣源安装
pip install opencv-python -i https://pypi.douban.com/simple/
调用opencv相关函数时导入的包为:
import cv2 as cv
对于使用pycharm导入cv2之后没有代码提示的问题,可以参考此文章
解决Opencv / cv2没有代码提示的问题
pip install mediapipe -i https://pypi.douban.com/simple/
pip uninstall protobuf
pip install protobuf==3.19.0
Downloading model to D:\anaconda\envs\virtual_mediapipe\lib\site-packages\mediapipe/modules/pose_landmark/pose_landmark_heavy.tflite
TimeoutError: [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连 接尝试失败。
[ WARN:0] global C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-_xlv4eex\opencv\modules\videoio\src\cap_msmf.cpp (438) `anonymous-namespace'::SourceReaderCB::~SourceReaderCB terminating async callback
可以去github或gitee上下载对应的包
https://gitee.com/mirrors/mediapipe/tree/master/mediapipe/modules/pose_landmark
输出信息中写了 他会把需要的包下载到什么文件夹:
Downloading model to D:\anaconda\envs\virtual_mediapipe\lib\site-packages\mediapipe/modules/pose_landmark/pose_landmark_heavy.tflite
比如这个模型:pose_landmark_heavy.tflite
把对应文件下载下来后复制粘贴到这个文件夹就解决了
接下来就可以愉快的使用mediapipe了
import cv2 as cv
import mediapipe as mp
import matplotlib.pyplot as plt
# 定义可视化图像函数
def look_img(img):
# opencv读入图像格式为BGR,matplotlib可视化格式为RGB,因此需要将BGR转为RGB
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.show()
# 导入solution
mp_pose = mp.solutions.pose
# 导入绘图函数
mp_drawing = mp.solutions.drawing_utils
# 导入模型
pose = mp_pose.Pose(static_image_mode=True, # 是静态图片还是连续视频帧
model_complexity=2, # 选择人体姿态关键点检测模型,0性能差但快,2性能好但慢,1介于两者之间
smooth_landmarks=True, # 是否平滑关键点
enable_segmentation=True, # 是否人体抠图
min_detection_confidence=0.5, # 置信度阈值
min_tracking_confidence=0.5 # 追踪阈值
)
# 读入图像
img = cv.imread('2.png')
# BGR转RGB
img_RGB = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# 将图像输入模型,获取预测结果
results = pose.process(img_RGB)
# 可视化结果
mp_drawing.draw_landmarks(img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
look_img(img)
# 在三维真实物理坐标系中以米为单位可视化人体关键点
mp_drawing.plot_landmarks(results.pose_world_landmarks, mp_pose.POSE_CONNECTIONS)
原图是这样的
经过关键点识别之后是这样的
三维人体图像是这样的,由于第三个维度是预测出来的,所以有时候不是很准确。
会了单张图像检测后,视频检测就非常简单了。
视频就是由连续的一帧一帧图像组成的,摄像头实时获取的视频也不例外,只需要调用cv2(opencv)里的视频捕捉函数一帧一帧读取图像就可以了。
import cv2 as cv
import mediapipe as mp
# 导入solution
mp_pose = mp.solutions.pose
# 导入绘图函数
mp_drawing = mp.solutions.drawing_utils
# 导入模型
pose = mp_pose.Pose(static_image_mode=True, # 是静态图片还是连续视频帧
model_complexity=2, # 选择人体姿态关键点检测模型,0性能差但快,2性能好但慢,1介于两者之间
smooth_landmarks=True, # 是否平滑关键点
enable_segmentation=True, # 是否人体抠图
min_detection_confidence=0.5, # 置信度阈值
min_tracking_confidence=0.5 # 追踪阈值
)
# 处理单帧的函数
def process_frame(img):
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
results = pose.process(img_rgb)
mp_drawing.draw_landmarks(img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
return img
# 读取视频帧的函数
def process_cap(cap, gap):
while cap.isOpened():
# 读视频帧
ret, frame = cap.read()
if ret: # 判断是否读取成功
# 如果读取成功则处理该帧
frame = process_frame(frame)
# 展示处理后的三通道图像
cv.imshow('video', frame)
# 按键盘的esc或者q退出
if cv.waitKey(gap) in [ord('q'), 27]:
break
else:
# print('error!')
break
# 关闭摄像头
cap.release()
# 关闭图像窗口
cv.destroyAllWindows()
# 从摄像头实时检测
def detect_camera():
# 创建窗口
cv.namedWindow('video', cv.WINDOW_NORMAL)
# 调用摄像头获取画面 0是windows系统下默认的摄像头,1是Mac系统
cap = cv.VideoCapture(0)
process_cap(cap, 1)
# 从本地导入视频检测
def detect_video(path):
# 创建窗口
cv.namedWindow('video', cv.WINDOW_NORMAL)
# 从本地读取视频
cap = cv.VideoCapture(path)
# 获取原视频帧率
fps = cap.get(cv.CAP_PROP_FPS)
# 获取原视频窗口大小
width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
# print(fps)
# 视频两帧之间的播放间隔,单位为毫秒
gap = int(1000 / fps)
cv.resizeWindow('video',width,height)
process_cap(cap, gap)
if __name__ == '__main__':
while True:
menu = int(input('请选择检测模式:1. 打开摄像头检测\t2. 从本地导入视频检测\t3. 退出\n'))
if menu == 1:
detect_camera()
break
elif menu == 2:
path = input('请输入视频路径(例如:D:\\download\\abc.mp4):\n')
detect_video(path)
break
elif menu == 3:
break
else:
print("输入错误,请重新输入!")
continue