基于opencv-mediapipe的手势识别

上一篇文章介绍了基于opencv的手势识别,如果大家运行了我的代码,会发现代码中找出手部轮廓的效果不是很理想。当时我在网上找寻解决的办法,刚好找到了mediapip库,然后我就利用opencv和mediapipe这两个库重新进行了手势识别的代码编写。效果还不错,写篇文章记录一下。

1.mediapipe简介

Mediapipe是google的一个开源项目,可以提供开源的、跨平台的常用机器学习(machine learning)方案。Mediapipe实际上是一个集成的机器学习视觉算法的工具库,包含了人脸检测、人脸关键点、手势识别、头像分割和姿态识别等各种模型。

由于我主要做的是手势识别,我就主要简单地讲解一下该库的手部检测模块,以便大家能更好的理解最后的手势识别的源代码。(如果大家想要了解其他模块,可以点击这里的进行了解:mediapipe官方简介

首先进行手部检测模块的初始化
mphand = mp.solutions.hands
hands = mphand.Hands()
mpHand.Hands参数 参数详解
static_image_mode=False 如果设置为False ,减少了延迟,非常适合处理视频帧。如果设置为True ,适合处理一批可能不相关的静态图像。默认为False 。
max_num_hands=2 要检测的最大手数。默认为2
model_complexity=1 手部标志模型的复杂性:0或1 .地标精度和推理延迟通常随着模型复杂性的增加而增加。默认为 1
min_detection_confidence=0.5 手部检测模型中的最小置信度值 ,以便将检测视为成功。默认为 0.5
min_tracking_confidence=0.5 地标跟踪模型中的最小置信度值 ,表示手部地标被视为成功跟踪,否则将在下一个输入图像上自动调用手部检测。将其设置为更高的值可以提高解决方案的健壮性,但代价是延迟更高。如果static_image_mode为 True,则忽略,其中手部检测只是在每个图像上运行。默认为0.5

如果不太理解上面的参数含义,没关系,直接默认就好。我认为只要知道max_num_hands和min_detection_confidence两个参数的含义就可以了

接着就是手势检测过程
hand = hands.process(img)

参数img是要进行检测的图片,由于opencv读入的图片为BGR模式,这里的img一定要转换为RGB模式

最后就是读取检测后的结果
 finger = []
    for handlms in hand.multi_hand_landmarks:
        for lm in handlms.landmark:
        	img_height,img_width,_ =  img.shape
        	#这里检测返回的x,y的坐标是基于原图像大小的比例坐标,
        	#所以要与原图像相乘得到真实的坐标
            x, y = int(lm.x * img_width), int(lm.y * img_height)
            finger.append([x, y])

如果打印一下finger列表,你就会看到21个坐标值。这21个坐标就是midiapipe基于人体手部21个关键点在原图像上位置坐标的检测。这21个坐标值对应的手部检测的关键点如下图:

基于opencv-mediapipe的手势识别_第1张图片

2.手势识别思路

mediapipe的基本用法大家已经了解了,现在讲解思路以及关键技巧的讲解

思路讲解

首先使用opencv调用摄像头,从摄像头读取图像,将图像反转(摄像头读取的图像与现实中是相反的),并将图像转换为RGB模式。接着使用mediapipe进行手部检测,并用列表存储。然后利用手指构成的角度来判断手指是否弯曲。

关键点讲解

整个程序似乎是没有什么难度的,主要的关键就是如何检测手指是否弯曲。

我在书上看到利用手指尖端与手指根部相减,观察结果的正与负来判断手指弯曲。举个例子,上图中我用8坐标点y值减去6坐标点的y值(此处y值不理解的话,点击这里),若结果为正,则表示该手指弯曲,为负,表示手指伸张。
但是这里存在着两个问题
第一,大拇指的弯曲与其余四个手指的弯曲是不同的(这里大家可以伸出自己的手观察一下,就可以理解),例如上图中我用4坐标和1坐标进行y值(此处y值同上)相减,但是并不是所有人大拇指弯曲的时候的4坐标的y值一定大于1坐标的y值,这时候就无法判断大拇指是否弯曲。
对于这个问题,我曾经想设置一个阈值来解决,但是需要不断的调试这个阈值的大小,并且每个人的手指大小不同可能这个阈值适合你,但不适合其他人。
第二,不知道大家发现没有上面的示例都是基于手部指尖朝上的情况,如果手部指尖朝下,朝左,朝右。这些情况怎么办?难道要多写一些判断条件,逐个分析。这样代码量很大,我不是很推荐。

引入角度来解决问题
引入三角函数,用手指构成的角度大小来进行判断
举个例子,这里我采用5,6,7坐标点为顶点来构成的三角形,这里我
以5,6坐标构成的边为a,
以6,7坐标构成的边为b,
以5,7坐标构成的边为c,
然后利用余弦函数来计算顶点6的角度,公式为:
a 2 + b 2 − c 2 / 2 a b a^2+b^2-c^2/2ab a

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