计算机视觉进阶教学之Mediapipe库(一)
目录简介一、Mediapipe Python的安装和应用二、手部检测1. 导入必要的库2. 初始化 MediaPipe 组件3. 配置并创建手部检测模型实例4. 启动摄像头并进入主循环5. 绘制检测结果三、手势识别1. 手势识别核心逻辑a. 计算基准距离 (Base Distance)b. 计算各手指尖到手腕的距离c. 判断手指是否伸直并计数d. 处理双手情况简介Mediapipe是google的一个开源项目可以提供开源的、跨平台的常用机器学习(machine learning)方案。Mediapipe实际上是一个集成的机器学习视觉算法的工具库包含了人脸检测、人脸关键点、手势识别、头像分割和姿态识别等各种模型。Mediapipe具备的优点有1支持各种平台和语言包括IOSAndroidCPythonJAVAScriptCoral等2速度快各种模型基本上可以做到实时运行。Mediapipe在实际应用中的例子1人脸检测2FaceMesh从图像/视频中重建出人脸的3D Mesh可以用于AR渲染3人像分割从图像/视频中把人分割出来可用于视频会议如Zoom、钉钉4手势识别和跟踪可以识别标出手部21个关键点的3D坐标5人体姿态识别可以识别标出人体33个关键点的3D坐标。官网地址 https://mediapipe.dev/Github开源项目地址 https://github.com/google/mediapipe一、Mediapipe Python的安装和应用安装python 3.7以上版本下载地址 https://www.python.org/getit安装Mediapipe1)安装OpenCV,终端执行pip install opencv-contrib-python2)安装Mediapipe终端执行pip install mediapipe或者使用国内镜像 pip install mediapipe -i https://pypi.tuna.tsinghua.edu.cn/simple/br具体详细应用可以详细查看官网介绍Mediapipe二、手部检测这段代码实现了一个实时的手部关键点检测系统。它通过电脑的摄像头捕获视频流然后使用 Google 的 MediaPipe 库来识别画面中的人手并实时地在视频上绘制出 21 个手部关键点及其连接关系。1. 导入必要的库import cv2 import mediapipe as mpcv2: 这是 OpenCV 库一个强大的计算机视觉库。在这里它的主要作用是从摄像头捕获视频帧 (cv2.VideoCapture)。在视频帧上绘制文字和关键点 (cv2.putText,cv2.imshow)。处理图像颜色空间 (cv2.cvtColor)。显示视频窗口并等待用户按键 (cv2.imshow,cv2.waitKey)。mediapipe: 这是 Google 开发的一个开源机器学习库特别擅长处理实时感知任务如手部、面部、姿势识别等。2. 初始化 MediaPipe 组件mp_drawing mp.solutions.drawing_utils mp_hands mp.solutions.handsmp.solutions.drawing_utils: 这是 MediaPipe 提供的一个绘图工具包。它包含了方便的函数可以直接在图像上绘制出检测到的关键点landmarks和它们之间的连接connections。mp.solutions.hands: 这是 MediaPipe 的手部检测解决方案。它封装了预训练好的模型可以直接用于检测图像或视频中的人手3. 配置并创建手部检测模型实例hands mp_hands.Hands( static_image_modeFalse, max_num_hands2, min_detection_confidence0.75, min_tracking_confidence0.75) mp.solutions.drawing_utils是一个绘图模块将识别到的手部关键点信息绘制道cv2图像中mp.solutions.drawing_style定义了绘制的风格。 mp.solutions.hands是mediapipe中的手部识别模块可以通过它调用手部识别的api然后通过调用mp_hands.Hands初始化手部识别类。 mp_hands.Hands中的参数 1)static_image_modeTrue适用于静态图片的手势识别Flase适用于视频等动态识别比较明显的区别是若识别的手的数量超过了最大值 True时识别的手会在多个手之间不停闪烁而False时超出的手不会识别系统会自动跟踪之前已经识别过的手。默认值为False; 2)max_num_hands用于指定识别手的最大数量。默认值为2; 3)min_detection_confidence 表示最小检测信度取值为[0.0,1.0]这个值约小越容易识别出手用时越短但是识别的准确度就越差。越大识别的越精准 但是响应的时间也会增加。默认值为0.5; 4)min_tracking_confience 表示最小的追踪可信度越大手部追踪的越准确相应的响应时间也就越长。默认值为0.5。 这是代码中非常关键的一步我们创建了一个Hands类的实例。这个实例就是我们的手部检测器。它接受几个重要的参数来配置其行为static_image_modeFalse:False(动态模式): 适用于视频流。系统会首先尝试检测手如果成功就会切换到更快速的 “追踪” 模式。这大大提高了处理视频时的帧率。如果追踪失败它会自动重新开始检测。True(静态模式): 适用于单张图片。系统会对每一帧都进行完整的检测而不会追踪。这在视频中会非常慢但对于分析静态图片更准确。max_num_hands2: 指定最多可以同时检测的手的数量。这里设置为 2意味着可以同时识别两只手。min_detection_confidence0.75:最小检测置信度。只有当模型对检测结果的置信度概率高于这个值这里是 75%时才会认为成功检测到了一只手。这个值越高误检越少但可能会漏掉一些手势。min_tracking_confidence0.75:最小追踪置信度。在追踪模式下只有当模型对追踪结果的置信度高于这个值时才会继续追踪。如果低于这个值系统会认为追踪丢失并重新启动检测。4. 启动摄像头并进入主循环cap cv2.VideoCapture(0) while True: flag 0 ret, frame cap.read() h,wframe.shape[:2] frame cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 因为摄像头是镜像的所以将摄像头水平翻转 # 不是镜像的可以不翻转 frame cv2.flip(frame, 1) results hands.process(frame) frame cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)5. 绘制检测结果if results.multi_hand_landmarks: for hand_landmarks in results.multi_hand_landmarks: # print(hand_landmarks:, hand_landmarks) # 计算关键点的距离用于判断手指是否伸直 for i in range(len(hand_landmarks.landmark)): x hand_landmarks.landmark[i].x y hand_landmarks.landmark[i].y z hand_landmarks.landmark[i].z # print(x,y,z) cv2.putText(frame, str(i), (int(x*w),int(y*h)), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0),2) # 关键点可视化 mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS) cv2.imshow(MediaPipe Hands, frame) if cv2.waitKey(1) 0xFF 27: break cap.release() cv2.destroyAllWindows()最后我们实现了一个这样的功能三、手势识别这段代码实现了一个实时的手势识别系统能够通过摄像头识别出0 到 10的数字手势即伸出几个手指就识别为相应的数字。它通过分析手部关键点之间的距离来判断每个手指是否伸直然后根据伸直手指的数量来确定手势。import cv2 import mediapipe as mp gesture [none, one, two, three, four, five, six, seven, eight, nine, ten] flag 0 mp_drawing mp.solutions.drawing_utils mp_hands mp.solutions.hands hands mp_hands.Hands( static_image_modeFalse, max_num_hands2, min_detection_confidence0.75, min_tracking_confidence0.75) cap cv2.VideoCapture(0) while True: flag 0 ret, frame cap.read() frame cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 因为摄像头是镜像的所以将摄像头水平翻转 # 不是镜像的可以不翻转 frame cv2.flip(frame, 1) results hands.process(frame) frame cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) # if results.multi_handedness: # for hand_label in results.multi_handedness: # print(hand_label) if results.multi_hand_landmarks: for hand_landmarks in results.multi_hand_landmarks: # print(hand_landmarks:, hand_landmarks) # 计算关键点的距离用于判断手指是否伸直 p0_x hand_landmarks.landmark[0].x p0_y hand_landmarks.landmark[0].y p5_x hand_landmarks.landmark[5].x p5_y hand_landmarks.landmark[5].y distance_0_5 pow(p0_x - p5_x, 2) pow(p0_y - p5_y, 2) base distance_0_5 / 0.6 p4_x hand_landmarks.landmark[4].x p4_y hand_landmarks.landmark[4].y distance_5_4 pow(p5_x - p4_x, 2) pow(p5_y - p4_y, 2) p8_x hand_landmarks.landmark[8].x p8_y hand_landmarks.landmark[8].y distance_0_8 pow(p0_x - p8_x, 2) pow(p0_y - p8_y, 2) p12_x hand_landmarks.landmark[12].x p12_y hand_landmarks.landmark[12].y distance_0_12 pow(p0_x - p12_x, 2) pow(p0_y - p12_y, 2) p16_x hand_landmarks.landmark[16].x p16_y hand_landmarks.landmark[16].y distance_0_16 pow(p0_x - p16_x, 2) pow(p0_y - p16_y, 2) p20_x hand_landmarks.landmark[20].x p20_y hand_landmarks.landmark[20].y distance_0_20 pow(p0_x - p20_x, 2) pow(p0_y - p20_y, 2) if distance_0_8 base: flag 1 if distance_0_12 base: flag 1 if distance_0_16 base: flag 1 if distance_0_20 base: flag 1 if distance_5_4 base * 0.3: flag 1 if flag 10: flag 10 # 关键点可视化 mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS) cv2.putText(frame, gesture[flag], (50, 50), 0, 1.3, (0, 0, 255), 3) cv2.imshow(MediaPipe Hands, frame) if cv2.waitKey(1) 0xFF 27: break cap.release() cv2.destroyAllWindows()1. 手势识别核心逻辑这是本代码最核心、最复杂的部分。if results.multi_hand_landmarks: for hand_landmarks in results.multi_hand_landmarks: # ... 距离计算 ... # ... 手指判断 ...if results.multi_hand_landmarks:: 判断是否检测到了手。for hand_landmarks in results.multi_hand_landmarks:: 遍历每一只检测到的手。如果是双手这个循环会执行两次。a. 计算基准距离 (Base Distance)p0_x hand_landmarks.landmark[0].x p0_y hand_landmarks.landmark[0].y p5_x hand_landmarks.landmark[5].x p5_y hand_landmarks.landmark[5].y distance_0_5 pow(p0_x - p5_x, 2) pow(p0_y - p5_y, 2) base distance_0_5 / 0.6p0是手腕根部的关键点p5是拇指根部的关键点。distance_0_5: 计算p0和p5之间的平方距离注意这里用的是pow计算平方和没有开根号因为比较大小时平方距离和实际距离效果一样但计算更快。base distance_0_5 / 0.6:这是一个非常巧妙的归一化技巧。distance_0_5的值会随着手离摄像头的远近而变化手近则大手远则小。通过将这个距离除以一个常数0.6我们得到一个与手的大小相关的基准值base。后续所有的距离判断都将基于这个base值这样就可以消除手的远近对判断结果的影响使得在不同距离下的手势识别都能保持准确。b. 计算各手指尖到手腕的距离p4_x hand_landmarks.landmark[4].x p4_y hand_landmarks.landmark[4].y distance_5_4 pow(p5_x - p4_x, 2) pow(p5_y - p4_y, 2) p8_x hand_landmarks.landmark[8].x p8_y hand_landmarks.landmark[8].y distance_0_8 pow(p0_x - p8_x, 2) pow(p0_y - p8_y, 2) # ... 同样的方式计算 distance_0_12 (中指), distance_0_16 (无名指), distance_0_20 (小指)p4: 拇指指尖p8: 食指指尖p12: 中指指尖p16: 无名指指尖p20: 小指指尖distance_5_4: 计算拇指指尖p4到拇指根部p5的平方距离。distance_0_8,distance_0_12,distance_0_16,distance_0_20: 计算各个手指尖到手腕p0的平方距离。c. 判断手指是否伸直并计数if distance_0_8 base: flag 1 if distance_0_12 base: flag 1 if distance_0_16 base: flag 1 if distance_0_20 base: flag 1 if distance_5_4 base * 0.3: flag 1逻辑如果一个手指是伸直的那么指尖离手腕或指根的距离就会比较远。if distance_0_8 base:: 如果食指指尖p8到手腕p0的距离大于基准值base就认为食指是伸直的flag计数器加 1。这个判断逻辑同样适用于中指、无名指和小指。拇指的判断略有不同if distance_5_4 base * 0.3:拇指的运动方式和其他四指不同它是向外侧张开而不是向上伸直。所以这里比较的是拇指指尖p4和拇指根部p5的距离。阈值也更小 (base * 0.3)因为拇指张开的幅度通常没有其他手指伸得那么远。d. 处理双手情况if flag 10: flag 10这个判断是为了处理双手的情况。当两只手都被检测到时for循环会执行两次。第一次处理左手flag累加了左手伸直的手指数量比如 5。第二次处理右手flag在之前的基础上继续累加5 5 10。if flag 10: flag 10确保了当两只手都伸出所有手指时总共 10 个手指flag的值被限制在 10以对应gesture列表中的 ten。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2431731.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!