【Opencv+MediaPipe】使用Opencv实现手部追踪

2022年1月10日,看到相关教程跟做

代码存在C:\Users\10133\PycharmProjects\Project_PictureProcessing

目录

一、调研

Opencv

MediaPipe

二、大概步骤

安装MediaPipe

导入opencv、MediaPipe和time库(其中time库是自带的,不用下载)

创建手部检测模型

 结果输出

画图样式

三、代码段


一、调研

  • Opencv

OpenCV 是一个基于 Apache2.0 许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。

它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了 Python、Ruby、MATLAB 等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

  • MediaPipe

MediaPipe 是一款由 Google Research 开发并开源的多媒体机器学习模型应用框架,可以直接调用其 API 完成目标检测、人脸检测以及关键点检测等。

MediaPipe官网:

Home - mediapipe (google.github.io)icon-default.png?t=LBL2https://google.github.io/mediapipe/

手势说明文档:

Hands - mediapipe (google.github.io)icon-default.png?t=LBL2https://google.github.io/mediapipe/solutions/hands.html#static_image_mode

二、大概步骤

  • 安装MediaPipe

pip install mediapipe
  • 导入opencv、MediaPipe和time库(其中time库是自带的,不用下载)

import cv2
import mediapipe as mp
import time
  • 创建手部检测模型

# 从摄像头捕获视频
# 参数为0表示打开计算机内置摄像头(我的电脑有点带不动,很卡) 也可以用视频的路径
cap = cv2.VideoCapture(0)
mpHands = mp.solutions.hands
hands = mpHands.Hands()   

其中 cv2.VideoCapture() 内的参数,0表示打开计算机内置摄像头,1表示导入已拍摄好的视频

hands是检测手部关键点的函数,其中有4个输入参数量可以选择(如下):

【Opencv+MediaPipe】使用Opencv实现手部追踪_第1张图片

  •  结果输出

while True:
    # 会返回两个值ret和img
    ret,img = cap.read()
    if ret:     # 这表示如果ret没有问题,也就是ret = true
        imgRGB = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)        #将BGR格式的图片转换成RGB的格式
        result = hands.process(imgRGB)
        print(result.multi_hand_landmarks)      #映射出手上的21个点的坐标
        # 把每一帧显示出来
        cv2.imshow('img',img)
    # 卡1ms跳出
    if cv2.waitKey(0) == ord('q'):
        break

result.multi_hand_landmarks: 手部21个点的坐标,其中 x,y,z 是归一化后的坐标(后面会对窗长进行计算,从而得到真实的坐标值)

  • 画图样式

刚只是得到了点的坐标,并没有画出来,下面将画出每个点

# 画手上landmarks的点的坐标
mpDraw = mp.solutions.drawing_utils
# 点的样式 三个值分别是b、g、r
handLms_Style = mpDraw.DrawingSpec(color=(0, 0, 255), thickness = 5)
# 线的样式
handCon_Style = mpDraw.DrawingSpec(color=(0, 0, 255), thickness = 10)

参数都是可以修改的,然后再在输出结果中加入循环,对每张图中每个点进行循环

# 把21个点画出来
        if result.multi_hand_landmarks:
            # 对每个点进行循环
            for handLms in result.multi_hand_landmarks:
                mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS, handLms_Style, handCon_Style)
                # 得到21个点的坐标,得到得是比例
                # 循环每只手的每个点(i从0到20)
                for i, lm, in enumerate(handLms.landmark):
                    # 根据前面得到的窗长和窗宽得到真实的x和y的位置,并转换成整数
                    xPos = int(lm.x * imgWidth)
                    yPos = int(lm.y * imgHeight)
                    cv2.putText(img, str(i), (xPos+25, yPos-5), cv2.FONT_HERSHEY_COMPLEX_SMALL, 0.4, (0, 0, 255), 2)
                    if i ==4:
                        cv2.circle(img, (xPos, yPos), 20, (166, 56, 56), cv2.FILLED)
                    print(i, xPos, yPos)

cv2.putText 可以在点旁进行标注

  • 可以计算每秒传输的帧数(使用time模块)

三、代码段

import cv2
import mediapipe as mp
import time

# 从摄像头捕获视频
# 参数为0表示打开计算机内置摄像头(我的电脑有点带不动,很卡) 也可以用视频的路径
cap = cv2.VideoCapture(0)
mpHands = mp.solutions.hands
hands = mpHands.Hands()     #如果使用函数本身的预设值的话,括号内不用写参数设置 按住ctrl点击函数可以看到函数的定义
# 画手上landmarks的点的坐标
mpDraw = mp.solutions.drawing_utils
# 点的样式 三个值分别是b、g、r
handLms_Style = mpDraw.DrawingSpec(color=(0, 0, 255), thickness = 5)
# 线的样式
handCon_Style = mpDraw.DrawingSpec(color=(0, 0, 255), thickness = 10)
# 设置两个时间 为了计算fps:每秒传输帧数
pTime = 0
cTime = 0

while True:
    # 会返回两个值ret和img
    ret,img = cap.read()
    if ret:     # 这表示如果ret没有问题,也就是ret = true
        imgRGB = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)        #将BGR格式的图片转换成RGB的格式
        result = hands.process(imgRGB)
        # print(result.multi_hand_landmarks)      #映射出手上的21个点的坐标
        # 为了下面得到的坐标从比例转换为真实坐标,这里首先得到窗长和窗宽
        imgHeight = img.shape[0]
        imgWidth = img.shape[1]


        # 把21个点画出来
        if result.multi_hand_landmarks:
            # 对每个点进行循环
            for handLms in result.multi_hand_landmarks:
                mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS, handLms_Style, handCon_Style)
                # 得到21个点的坐标,得到得是比例
                # 循环每只手的每个点(i从0到20)
                for i, lm, in enumerate(handLms.landmark):
                    # 根据前面得到的窗长和窗宽得到真实的x和y的位置,并转换成整数
                    xPos = int(lm.x * imgWidth)
                    yPos = int(lm.y * imgHeight)
                    cv2.putText(img, str(i), (xPos+25, yPos-5), cv2.FONT_HERSHEY_COMPLEX_SMALL, 0.4, (0, 0, 255), 2)
                    if i ==4:
                        cv2.circle(img, (xPos, yPos), 20, (166, 56, 56), cv2.FILLED)
                    print(i, xPos, yPos)
        # 计算得到每秒传输帧数
        cTime = time.time()
        fps = 1/(cTime-pTime)
        pTime = cTime
        cv2.putText(img, f"FPS: {int(fps)}", (30, 50), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255, 0, 0), 3)



        # 把每一帧显示出来
        cv2.imshow('img',img)
    # 卡1ms跳出
    if cv2.waitKey(0) == ord('q'):
        break

【Opencv+MediaPipe】使用Opencv实现手部追踪_第2张图片

电脑太拉了,FPS只有1(可怕)

参考来自:

手部21个关键点检测+手势识别-[MediaPipe]_开鑫9575的博客-CSDN博客_mediapipeicon-default.png?t=LBL2https://blog.csdn.net/weixin_45930948/article/details/115444916

你可能感兴趣的:(图像处理,opencv,计算机视觉,人工智能)