各位同学好,今天和大家分享一下如何使用 MediaPipe+Opencv 通过手势识别来控制电脑鼠标的移动和点击,如果有兴趣的话,可以代替鼠标去打游戏。先放图看效果。用画图板来测试

黄框代表电脑屏幕的范围,将黄框的宽高映射到电脑屏幕的宽高。食指竖起并且中指弯下时,移动鼠标食指和中指都竖起,并且两个指尖距离小于50时,认为是点击鼠标左上角30代表FPS值

移动鼠标移动时,食指指尖有淡蓝色圆点,表明鼠标在移动,如右图的绿色线条是鼠标移动轨迹

点击鼠标:当食指和中指间的距离小于50,食指指尖圆点变成绿色,点击鼠标,如画图板上的两个点,就是点击两下实现的。


1. 导入工具包

# 安装工具包
pip install opencv-contrib-python  # 安装opencv
pip install mediapipe  # 安装mediapipe
# pip install mediapipe --user  #有user报错的话试试这个
pip install cvzone  # 安装cvzone
pip install autopy  # 鼠标控制单元# 导入工具包
import numpy as np
import cv2
from cvzone.HandTrackingModule import HandDetector  # 手部追踪方法
import mediapipe as mp
import time
import autopy

21个手部关键点信息如下,本节我们主要研究食指指尖"8"中指指尖"12"的坐标信息。


2. 手部关键点检测

(1) cvzone.HandTrackingModule.HandDetector()   手部关键点检测方法

参数:

mode: 默认为 False,将输入图像视为视频流。它将尝试在第一个输入图像中检测手,并在成功检测后进一步定位手的坐标。在随后的图像中,一旦检测到所有 maxHands 手并定位了相应的手的坐标,它就会跟踪这些坐标,而不会调用另一个检测,直到它失去对任何一只手的跟踪。这减少了延迟,非常适合处理视频帧。如果设置为 True,则在每个输入图像上运行手部检测,用于处理一批静态的、可能不相关的图像。

maxHands: 最多检测几只手,默认为 2

detectionCon: 手部检测模型的最小置信值(0-1之间),超过阈值则检测成功。默认为 0.5

minTrackingCon: 坐标跟踪模型的最小置信值 (0-1之间),用于将手部坐标视为成功跟踪,不成功则在下一个输入图像上自动调用手部检测。将其设置为更高的值可以提高解决方案的稳健性,但代价是更高的延迟。如果 mode 为 True,则忽略这个参数,手部检测将在每个图像上运行。默认为 0.5

它的参数和返回值类似于官方函数 mediapipe.solutions.hands.Hands()

(2)cvzone.HandTrackingModule.HandDetector.findHands()    找到手部关键点并绘图

参数:

img: 需要检测关键点的帧图像,格式为BGR

draw: 是否需要在原图像上绘制关键点及识别框

flipType: 图像是否需要翻转,当视频图像和我们自己不是镜像关系时,设为True就可以了

返回值:

hands: 检测到的手部信息,包含:21个关键点坐标,检测框坐标及宽高,检测框中心坐标,检测出是哪一只手。

img: 返回绘制了关键点及连线后的图像

手部检测的代码如下:

import cv2
from cvzone.HandTrackingModule import HandDetector   # 手部检测方法
import time#(1)导数视频数据
cap = cv2.VideoCapture(0)  # 0代表自己电脑的摄像头
cap.set(3, 1280)  # 设置显示框的宽度1280
cap.set(4, 720)  # 设置显示框的高度720pTime = 0  # 设置第一帧开始处理的起始时间#(2)接收手部检测方法
detector = HandDetector(mode=False,  # 视频流图像 maxHands=1,  # 最多检测一只手detectionCon=0.8,  # 最小检测置信度 minTrackCon=0.5)   # 最小跟踪置信度#(3)处理每一帧图像
while True:# 图片是否成功接收、img帧图像success, img = cap.read()# 翻转图像,使自身和摄像头中的自己呈镜像关系img = cv2.flip(img, flipCode=1)  # 1代表水平翻转,0代表竖直翻转#(4)手部检测方法# 传入每帧图像, 返回手部关键点的坐标信息(字典构成的列表hands),绘制关键点后的图像imghands, img = detector.findHands(img, flipType=False)  # 上面反转过了,这里就不用再翻转了# print(hands)#(5)显示图像# 查看FPScTime = time.time() #处理完一帧图像的时间fps = 1/(cTime-pTime)pTime = cTime  #重置起始时间# 在视频上显示fps信息,先转换成整数再变成字符串形式,文本显示坐标,文本字体,文本大小cv2.putText(img, str(int(fps)), (70,50), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)  # 显示图像,输入窗口名及图像数据cv2.imshow('image', img)    if cv2.waitKey(1) & 0xFF==27:  #每帧滞留20毫秒后消失,ESC键退出break# 释放视频资源
cap.release()
cv2.destroyAllWindows()

打印每帧图像检测到的手部信息hands列表,由字典组成。lmList 代表21个手部关键点的像素坐标;bbox 代表检测框的左上角坐标和框的宽高;center 代表检测框的中心点的像素坐标;type 代表检测出的是左手还是右手。

----------------------------------------------------------------------------
[{'lmList': [[522, 755], [621, 761], [709, 724], [765, 675], [794, 615], [705, 629], [761, 588], [749, 643], [715, 686], [676, 599], [743, 565], [713, 637], [664, 684], [634, 565], [710, 543], [668, 622], [613, 666], [576, 533], [657, 519], [640, 580], [597, 620]],'bbox': (522, 519, 272, 242), 'center': (658, 640), 'type': 'Left'}]
[{'lmList': [[520, 763], [620, 774], [716, 753], [779, 707], [816, 650], [716, 655], [781, 619], [767, 677], [727, 721], [689, 627], [759, 595], [731, 667], [683, 710], [649, 594], [727, 579], [680, 653], [620, 689], [593, 558], [674, 549], [655, 608], [608, 642]],'bbox': (520, 549, 296, 225),'center': (668, 661),'type': 'Left'}]
----------------------------------------------------------------------------

检测结果如图所示:


2. 移动鼠标

移动鼠标的思路是:如果检测到食指竖起,并且中指弯下,那么就认为是移动鼠标,鼠标的位置坐标是食指指尖所在的位置坐标

检测哪个手指是竖起的方法是 detector.fingersUp() ,传入检测到的某只手的手部信息hands[0]返回值由5个元素构成的列表元素为1代表该手指竖起,0代表手指弯下,例如:[0,1,1,0,0] 就代表食指和中指竖起,其他手指弯下。

当手指在摄像头画面的下半部分移动时,由于摄像头界限范围问题,手掌部分会在摄像头画面中消失,导致检测不到手部关键点,因此,在屏幕画面的偏上半部分绘制一个黄色的矩形框,手指只能在矩形框中移动,避免手部关键点的消失。

由于我们设置的矩形框大小明显要小于电脑屏幕的大小,导致手控的鼠标无法在整个电脑屏幕上移动。因此,需要将矩形框的宽和高映射到电脑屏幕的宽和高。使用线性插值方法 np.interp(x, xp, fp)  简单来说就是将变量x的范围从原来的xp映射到fp。如:np.interp(x1, (pt1[0], pt2[0]), (0, wScr)),就是将x坐标的范围从原来的 pt1[0]pt1[0]+w,映射到整个电脑屏幕 wScr

返回电脑屏幕的宽和高: autopy.screen.size()

移动鼠标的位置到坐标(x,y): autopy.mouse.move(x, y)

autopy具体使用方法见下文:https://blog.csdn.net/qq_30462003/article/details/100130472

因此,我们在上述代码中补充:

import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector   # 手部检测方法
import time
# pip install autopy  #鼠标控制单元
import autopy#(1)导数视频数据
wScr, hScr = autopy.screen.size()   # 返回电脑屏幕的宽和高(1920.0, 1080.0)
wCam, hCam = 1280, 720   # 视频显示窗口的宽和高
pt1, pt2 = (100,100), (1100, 500)   # 虚拟鼠标的移动范围,左上坐标pt1,右下坐标pt2cap = cv2.VideoCapture(0)  # 0代表自己电脑的摄像头
cap.set(3, wCam)  # 设置显示框的宽度1280
cap.set(4, hCam)  # 设置显示框的高度720pTime = 0  # 设置第一帧开始处理的起始时间#(2)接收手部检测方法
detector = HandDetector(mode=False,  # 视频流图像 maxHands=1,  # 最多检测一只手detectionCon=0.8,  # 最小检测置信度 minTrackCon=0.5)   # 最小跟踪置信度#(3)处理每一帧图像
while True:# 图片是否成功接收、img帧图像success, img = cap.read()# 翻转图像,使自身和摄像头中的自己呈镜像关系img = cv2.flip(img, flipCode=1)  # 1代表水平翻转,0代表竖直翻转# 在图像窗口上创建一个矩形框,在该区域内移动鼠标cv2.rectangle(img, pt1, pt2, (0,255,255), 5)#(4)手部关键点检测# 传入每帧图像, 返回手部关键点的坐标信息(字典),绘制关键点后的图像hands, img = detector.findHands(img, flipType=False)  # 上面反转过了,这里就不用再翻转了# print(hands)# 如果能检测到手那么就进行下一步if hands:# 获取手部信息hands中的21个关键点信息lmList = hands[0]['lmList']  # hands是由N个字典组成的列表,字典包每只手的关键点信息# 获取食指指尖坐标,和中指指尖坐标x1, y1 = lmList[8]  # 食指尖的关键点索引号为8x2, y2 = lmList[12] # 中指指尖索引12#(5)检查哪个手指是朝上的fingers = detector.fingersUp(hands[0])  # 传入# print(fingers) 返回 [0,1,1,0,0] 代表 只有食指和中指竖起# 如果食指竖起且中指弯下,就认为是移动鼠标if fingers[1] == 1 and fingers[2] == 0:# 开始移动时,在食指指尖画一个圆圈,看得更清晰一些cv2.circle(img, (x1,y1), 15, (255,255,0), cv2.FILLED)  # 颜色填充整个圆#(6)确定鼠标移动的范围# 将食指的移动范围从预制的窗口范围,映射到电脑屏幕范围x3 = np.interp(x1, (pt1[0], pt2[0]), (0, wScr))y3 = np.interp(y1, (pt1[1], pt2[1]), (0, hScr))#(7)移动鼠标autopy.mouse.move(x3, y3)  # 给出鼠标移动位置坐标#(8)显示图像# 查看FPScTime = time.time() #处理完一帧图像的时间fps = 1/(cTime-pTime)pTime = cTime  #重置起始时间# 在视频上显示fps信息,先转换成整数再变成字符串形式,文本显示坐标,文本字体,文本大小cv2.putText(img, str(int(fps)), (70,50), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)  # 显示图像,输入窗口名及图像数据cv2.imshow('image', img)    if cv2.waitKey(1) & 0xFF==27:  #每帧滞留20毫秒后消失,ESC键退出break# 释放视频资源
cap.release()
cv2.destroyAllWindows()

效果图如下:


3. 点击鼠标

点击鼠标的思路是:如果食指和中指同时竖起,并且食指指尖和中指指尖之间的像素距离小于50时,那么就认为是点击鼠标。

检测哪个手指是竖起的方法是上面已经解释过的 detector.fingersUp() 方法,检测指尖距离的方法是: detector.findDistance(pt1, pt2, img)pt1pt2 是两个点的坐标,传入img来绘制指尖连线图。

点击鼠标的函数,autopy.mouse.click()

由于用手指控制鼠标时,每一帧的坐标位置的变化幅度较大,导致电脑鼠标在手指控制下很容易晃动,很难准确定位到一个目标。因此需要平滑每一帧的坐标变化,使坐标变化更缓慢一些

例如:cLocx = pLocx + (x3 - pLocx) / smooth,式中:前帧的鼠标位置的x坐标 cLocx前一帧的鼠标位置的x坐标 pLocx当前鼠标位置的x坐标 x3自定义平滑系数smooth,值越大鼠标移动就越慢,平稳性就越高。

因此,在上述代码中补充:

import cv2
import numpy as np
from cvzone.HandTrackingModule import HandDetector   # 手部检测方法
import time
import autopy#(1)导数视频数据
wScr, hScr = autopy.screen.size()   # 返回电脑屏幕的宽和高(1920.0, 1080.0)
wCam, hCam = 1280, 720   # 视频显示窗口的宽和高
pt1, pt2 = (100,100), (1100, 500)   # 虚拟鼠标的移动范围,左上坐标pt1,右下坐标pt2cap = cv2.VideoCapture(0)  # 0代表自己电脑的摄像头
cap.set(3, wCam)  # 设置显示框的宽度1280
cap.set(4, hCam)  # 设置显示框的高度720pTime = 0  # 设置第一帧开始处理的起始时间pLocx, pLocy = 0, 0  # 上一帧时的鼠标所在位置smooth = 4  # 自定义平滑系数,让鼠标移动平缓一些#(2)接收手部检测方法
detector = HandDetector(mode=False,  # 视频流图像 maxHands=1,  # 最多检测一只手detectionCon=0.8,  # 最小检测置信度 minTrackCon=0.5)   # 最小跟踪置信度#(3)处理每一帧图像
while True:# 图片是否成功接收、img帧图像success, img = cap.read()# 翻转图像,使自身和摄像头中的自己呈镜像关系img = cv2.flip(img, flipCode=1)  # 1代表水平翻转,0代表竖直翻转# 在图像窗口上创建一个矩形框,在该区域内移动鼠标cv2.rectangle(img, pt1, pt2, (0,255,255), 5)#(4)手部关键点检测# 传入每帧图像, 返回手部关键点的坐标信息(字典),绘制关键点后的图像hands, img = detector.findHands(img, flipType=False)  # 上面反转过了,这里就不用再翻转了# print(hands)# 如果能检测到手那么就进行下一步if hands:# 获取手部信息hands中的21个关键点信息lmList = hands[0]['lmList']  # hands是由N个字典组成的列表,字典包每只手的关键点信息# 获取食指指尖坐标,和中指指尖坐标x1, y1 = lmList[8]  # 食指尖的关键点索引号为8x2, y2 = lmList[12] # 中指指尖索引12#(5)检查哪个手指是朝上的fingers = detector.fingersUp(hands[0])  # 传入# print(fingers) 返回 [0,1,1,0,0] 代表 只有食指和中指竖起# 如果食指竖起且中指弯下,就认为是移动鼠标if fingers[1] == 1 and fingers[2] == 0:# 开始移动时,在食指指尖画一个圆圈,看得更清晰一些cv2.circle(img, (x1,y1), 15, (255,255,0), cv2.FILLED)  # 颜色填充整个圆#(6)确定鼠标移动的范围# 将食指的移动范围从预制的窗口范围,映射到电脑屏幕范围x3 = np.interp(x1, (pt1[0], pt2[0]), (0, wScr))y3 = np.interp(y1, (pt1[1], pt2[1]), (0, hScr))#(7)平滑,使手指在移动鼠标时,鼠标箭头不会一直晃动cLocx = pLocx + (x3 - pLocx) / smooth  # 当前的鼠标所在位置坐标cLocy = pLocy + (y3 - pLocy) / smooth            #(8)移动鼠标autopy.mouse.move(cLocx, cLocy)  # 给出鼠标移动位置坐标# 更新前一帧的鼠标所在位置坐标,将当前帧鼠标所在位置,变成下一帧的鼠标前一帧所在位置pLocx, pLocy = cLocx, cLocy#(9)如果食指和中指都竖起,指尖距离小于某个值认为是点击鼠标if fingers[1] == 1 and fingers[2] == 1:  # 食指和中指都竖起# 计算食指尖和中指尖之间的距离distance,绘制好了的图像img,指尖连线的信息infodistance, info, img = detector.findDistance((x1, y1), (x2, y2), img)# print(distance)# 当指间距离小于50(像素距离)就认为是点击鼠标if distance < 50:# 在食指尖画个绿色的圆,表示点击鼠标cv2.circle(img, (x1,y1), 15, (0,255,0), cv2.FILLED)# 点击鼠标autopy.mouse.click()#(10)显示图像# 查看FPScTime = time.time() #处理完一帧图像的时间fps = 1/(cTime-pTime)pTime = cTime  #重置起始时间# 在视频上显示fps信息,先转换成整数再变成字符串形式,文本显示坐标,文本字体,文本大小cv2.putText(img, str(int(fps)), (70,50), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)  # 显示图像,输入窗口名及图像数据cv2.imshow('image', img)    if cv2.waitKey(1) & 0xFF==27:  #每帧滞留20毫秒后消失,ESC键退出break# 释放视频资源
cap.release()
cv2.destroyAllWindows()

结果图像展示,在绘图板中每点击一次就绘制一个圆圈。

【机器视觉案例】(8) AI视觉,手势控制电脑鼠标,附python完整代码相关推荐

  1. 【机器视觉案例】(9) AI视觉,手势控制电脑键盘,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv+mediapipe 完成远程手势控制电脑键盘.感兴趣的可以看一下我前面一篇手势控制电脑鼠标:https://blog.csdn.net/dgvv4 ...

  2. 【MediaPipe】(3) AI视觉,人脸识别,附python完整代码

    各位同学好,今天和大家分享一下如何使用MediaPipe完成人脸实时跟踪检测,先放张图看效果,FPS值为14,右侧的输出为:每帧图像是人脸的概率,检测框的左上角坐标及框的宽高. 有需要的可以使用 cv ...

  3. 【机器视觉案例】(5) AI视觉,远程手势控制虚拟计算器,附python完整代码

    各位同学好,今天和大家分享一下如何使用MediaPipe+Opencv完成虚拟计算器,先放张图看效果.FPS值为29,食指和中指距离小于规定阈值则认为点击按键,为避免重复数字出现,规定每20帧可点击一 ...

  4. 【机器视觉案例】(5) AI视觉,手势调节物体尺寸,附python完整代码

    各位同学好,今天和大家分享一下如何使用opencv+mediapipe完成远程手势调节图片尺寸的案例.先放张图看效果.当拇指和食指竖起时,根据食指间的连线的长度自由缩放图片尺寸.图片的中点始终位于指尖 ...

  5. 【MediaPipe】(4) AI视觉,远程手势调节电脑音量,附python完整代码

    各位同学好,今天和大家分享一下如何使用MediaPipe完成手势调节电脑音量,先放张图看效果. 注意!! 本节需要用到手部关键点的实时跟踪,我已经在之前的文章中详细写过了,本节会直接使用,有疑问的同学 ...

  6. 基于mediapipe和opencv的手势控制电脑鼠标

    通过我的上一篇文章,可以了解到mediapipe关于手部检测的使用方法.这时我们就可以进行一些更加炫酷的操作.这篇文章我就来讲解一下如何用手势来控制电脑鼠标. 在开始之前我们要介绍一个能够操作电脑鼠标 ...

  7. 【机器视觉案例】(6) AI视觉,距离测量,自制AI小游戏,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv + mediapipe 创建一个AI视觉小游戏,先放图看效果. 游戏规则,用手按下屏幕上的圆形按钮,每按一次后松开,按钮就随机出现在屏幕上的一个位 ...

  8. TensorFlow 实战案例:利用 LSTM、GRU 进行股票数据预测(附 Python 完整代码)

    大家好,今天和各位分享一下如何使用循环神经网络 LSTM 和 GRU 完成对股票数据的预测.GRU 是在 LSTM 基础上的简化,将 LSTM 内部的三个闸门简化成两个,往往 GRU 的计算效果会优于 ...

  9. 【机器视觉案例】(10) AI视觉搭积木,手势移动虚拟物体,附python完整代码

    各位同学好,今天和大家分享一下如何使用 opencv+mediapipe 完成手势移动虚拟物体,可自定义各种形状的物体,通过手势搭积木.先放张图看效果. 规则:当食指在某个物体内部,并且中指指尖和食指 ...

最新文章

  1. 极客新闻——09、如何打造核心骨干团队
  2. leetcode 200岛屿的个数
  3. PyQt5 技术篇-设置滚动条拉动位置,scrollArea滚动条位置设置方法。
  4. 类和对象—对象特性—拷贝构造函数调用时期
  5. InsightFace及其mxnet、tensorflow代码实现
  6. Redis学习---(11)Redis 有序集合(sorted set)
  7. 为Laravel的artisan指令增加bash脚本
  8. yum命令 启用仓库_yum 命令详解-yum仓库配置文件详解
  9. sicily 1002. Anti-prime Sequences
  10. java线程死锁_Java线程死锁实例及解决方法
  11. tp框架like模糊查询报错
  12. 完整的连接器设计手册_特斯拉的高压连接器
  13. python中os库是标准库还是第三方库_Python os 标准库使用
  14. 语音降噪论文“A Hybrid Approach for Speech Enhancement ...“的研读
  15. Homestead 安装 phpMyAdmin 作为数据库管理客户端 — Laravel 实战 果酱 API 教程
  16. 强制删除正在运行的文件
  17. 自动控制原理(4)——传递函数、典型环节的传递函数
  18. 杰理之触摸、触摸按键不开 机【篇】
  19. Hutool生成图片二维码 输出到前端
  20. 第一次深度学习实习生面试经历

热门文章

  1. Android 计时器 Chronometer
  2. Tablayout 修改默认选项页,或者跳转到指定的选项页
  3. 微信小程序showModel使用注意
  4. android 的中文意思
  5. 想搞自动识别系统的应用程序,希望能跟有志于此的朋友交流
  6. 目标反射回波检测算法及其FPGA实现 之一:算法概述
  7. C++ 笔记(23)— STL vector 类(实例化 vector、末尾插入、指定位置插入、数组方式访问元素、指针方式访问元素、删除元素、大小与容量区别)
  8. python基础 条件和循环
  9. Android 知识杂记(MVP模式)
  10. 0709 C语言常见误区----------函数指针问题