通过我的上一篇文章,可以了解到mediapipe关于手部检测的使用方法。这时我们就可以进行一些更加炫酷的操作。这篇文章我就来讲解一下如何用手势来控制电脑鼠标。

在开始之前我们要介绍一个能够操作电脑鼠标的库pyautogui,这里我简单介绍一下该库的一些函数,方便大家观看最后的源码

函数名 作用
pyautogui.size() 获取屏幕的分辨率,返回值为width,height
pyautogui.click(x,y,button = ‘left/right’) 在屏幕的(x,y)处进行左键或右键的点击操作
pyautogui.doubleClick(x,y) 在屏幕的(x,y)处双击左键
pyautogui.moveTo(x, y, duration=0) 将鼠标移动到指定的(x,y)处;duration 的作用是设置移动时间,是可选参数
pyautogui.FAILSAFE =True 默认这项功能为True, 这项功能意味着:当鼠标在屏幕的最左上角,程序会报错;目的是防止程序一直控制鼠标导致程序无法结束

由于mediapipe的使用方法在上一篇文章中已经介绍过了,这里就不再重复介绍了。如果小伙伴不知道mediapipe是什么的话,点击这里,看我的上一篇文章

思路

首先使用opencv调用摄像头,从摄像头读取图像,将图像反转(摄像头读取的图像与现实中是相反的),并将图像转换为RGB模式。接着使用mediapipe进行手部检测,并用列表存储手部的21个关键点的坐标。利用该列表进行检测:
        当手指食指小于160度的时候认定鼠标点击左键
        当手指中食小于160度的时候认定鼠标点击右键
        当手指食指和中值之间的距离小于40的时候认定鼠标点双击左键
        (如果不知道如何检测手指角度数,请看我的上一篇文章)
然后我用手部关键点的0和9的坐标的中值来代替鼠标,大概就在下图我标注的绿色点的位置

实现过程的难点

这里有两个难点:第一,一开始的时候我获取到屏幕的分辨率(width,height),然后再在获取的每一帧的图像的大小(x,y),接着获取比例关系(ratio_x=width/x,ratio_y=height/y),当得到如上图的绿色点的坐标乘上比例关系就获得了屏幕鼠标应该在的位置。这样做看起来很好,但在实践的过程中有很大的问题,因为你会发现屏幕上的鼠标会到达不了屏幕的边缘区域(你可以亲自测试一下)。
第二,如果手指悬停在某一点处,电脑上的鼠标会一直晃动。因为你的手指会一直抖动,做不到完全静止,这细微的变化乘上比例,就会被放大,这样就会造成看似手指悬停,但是屏幕上的鼠标会抖动的原因。

解决办法:

第一:在网上看见了numpy.interp(),这是一个一维的插值函数(该函数的参数,这里就不讲解了,在最后的源代码中我会做注释讲解的),下图时插值函数的效果图,图上的x,y轴代表了图像和屏幕的大小。虽然这里的插值和我使用的比例方法可以都看作是线性的直线方程,但是还是插值函数效果更好。这令我很困惑。

第二:对于手指悬停,鼠标一直抖动的问题。我们可以先记录一下这次屏幕上鼠标的坐标(pre_x, pre_y),等得到下一次鼠标坐标(mouse_x,mouse_y)的时候,
进行计算x = (mouse_x - pre_x)/ smooth 和 y =(mouse_y - pre_y)/ smooth
这里的(mouse_x - pre_x)和(mouse_y - pre_y)相当与计算出了这两次鼠标的距离,除以smooth
相当于缩短了距离,然后用(pre_x + x, pre_y + y)用于当前鼠标的坐标位置,然后更新
pre_x = pre_x + x, pre_y = pre_y + y。这样就缩减了前后两次鼠标的距离,来防止鼠标的抖动,且更新了鼠标的位置。
这里要注意(mouse_x - pre_x)和 (mouse_y - pre_y)的相减顺序,以及smooth一定要大于1(小于1相当于扩大了距离),当smooth的值越大时,鼠标移动会变慢,鼠标会稳定;值越小,鼠标移动就会变快,鼠标会抖动。

完整代码;

import pyautogui
import time
import cv2
import numpy as np
import math
import mediapipe as mp# 获取手指的坐标,全部获取存入列表中并返回该列表
def finger_coordinate(hand):finger = []for handlms in hand.multi_hand_landmarks:for lm in handlms.landmark:x, y = int(lm.x * cap_x), int(lm.y * cap_y)finger.append([x, y])#mpdraw.draw_landmarks(frame, handlms, mphand.HAND_CONNECTIONS)return finger#判断手指的弯曲度数以及食指和中值的距离,将判断的结果存入judge_finfer列表中,
#如果食指弯曲则judge_finger[0] = 1,中指弯曲则judge_finger[1] = 1,如果两手指的距离小于40则judge_finger[2] = 1
#最后返回judge_finger
def check_finger(finger):judge_finger = [0,0,0]for i,id in enumerate([5,9]):a = round(math.hypot(finger[id][0]-finger[id+1][0],finger[id][1]-finger[id+1][1]),2)b = round(math.hypot(finger[id+1][0]-finger[id+2][0],finger[id+1][1]-finger[id+2][1]),2)c = round(math.hypot(finger[id][0]-finger[id+2][0],finger[id][1]-finger[id+2][1]),2)try:angle = math.acos((a**2+b**2-c**2)/(2*a*b))*57except ValueError:angle = 180except ZeroDivisionError:angel = 0if angle < 160:judge_finger[i] = 1dist = math.hypot(finger[8][0]-finger[12][0],finger[8][1]-finger[12][1])cv2.circle(frame, finger[8], 25, (255, 0, 255), -1, )cv2.circle(frame, finger[12], 25, (255, 0, 255), -1, )if dist < 40:judge_finger[2] = 1return judge_finger########################
#变量设置区域
offset_x = 60
offset_y = 150smooth = 5
pre_x = 0
pre_y = 0
################################################
#初始化区域
cap = cv2.VideoCapture(0)cap_x = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
cap_y = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
screen_x,screen_y = pyautogui.size()mphand = mp.solutions.hands
hands = mphand.Hands()
mpdraw = mp.solutions.drawing_utils
########################while cap.isOpened():#从摄像头中获取图像,并将图像反转,转换为RGB模式_,frame = cap.read()frame = cv2.flip(frame, 1)img = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)cv2.rectangle(frame, (offset_x, offset_y), (cap_x - offset_x, cap_y), (0, 255, 0), 2)#进行手势的检测,返回关于手势的检测值hand = hands.process(img)#判断是否检测到手部if hand.multi_hand_landmarks:#检测手指的坐标值,并返回列表finger = finger_coordinate(hand)#1.确定鼠标的坐标#以编号0和9的中值为鼠标点x,y = (finger[0][0]+finger[9][0])//2,(finger[0][1]+finger[9][1])//2cv2.circle(frame, (x,y), 25, (255, 0, 255), -1)#使用插值法进行图像点到屏幕鼠标点的映射mouse_x = np.interp(x,(offset_x,cap_x-offset_x),(0,screen_x))mouse_y = np.interp(y,(offset_y,cap_y),(0,screen_y))#平滑鼠标坐标mouse_x = pre_x + (mouse_x-pre_x) / smoothmouse_y = pre_y + (mouse_y-pre_y) / smoothpre_x = mouse_xpre_y = mouse_y#将确定的鼠标点进行在屏幕上移动pyautogui.moveTo(mouse_x, mouse_y, duration=0)#2.检测手指来确定鼠标的点击操作#以第二根和第三根手指弯曲的角度为左右键,小于160度视为点击操作,以及两手指的距离小于40视为左键双击judge_finger = check_finger(finger)# 每次只能进行一个操作,所以返回值只能有一个为真,如果有超过1个为真,则进行下一次循环count = judge_finger.count(1)if count == 1:index = judge_finger.index(1)if index == 0:pyautogui.click(mouse_x,mouse_y,button = 'left')cv2.putText(frame, 'click left', (10, 20), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 1)elif index == 1:pyautogui.click(mouse_x,mouse_y,button = 'right')cv2.putText(frame, 'click right', (10, 20), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 1)else:pyautogui.doubleClick(mouse_x,mouse_y)cv2.putText(frame, 'click double', (10, 20), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 1)else:cv2.putText(frame,'no or more operate',(10,20),cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),1)else:cv2.putText(frame, 'plese put your hand', (10, 20), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 1)#显示图像,并在按下ESC按键时退出程序cv2.imshow('img',frame)ret = cv2.waitKey(1)if ret == 27:break#释放摄像头
cap.release()
cv2.destroyAllWindows()'''
英语单词
capture  捕获
frame   帧
coordinate 坐标
offset 偏移
smooth 平滑
previous  以前
'''

总结

现在的计算机视觉,语音识别,自然语言的处理都离不开机器学习和深度学习。刚好学院现在也开了机器学习这门课,其中的内容和公式真是令人望而生畏,所以接下来我打算记录下自己的学习过程,以及自己的理解感悟,分享给大家。创作不易,希望大家能多多支持。

基于mediapipe和opencv的手势控制电脑鼠标相关推荐

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

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

  2. 基于ESP32-CAM 和 OpenCV 设计的手势控制虚拟鼠标

    概述 在本文中,我们将使用ESP32-CAM和OpenCV开发手势控制虚拟鼠标.ESP32 Camera Module和Python程序可用于无线控制鼠标跟踪和点击操作. 入门者必须具备 Python ...

  3. 【涵子来信python大全】——第二季——opencv第四篇-用手势控制屏幕鼠标

    各位亲爱的读者,博主: 大家好,我是涵子.今天我们需要使用cv2,mediapipe和pyautogui用手势控制屏幕鼠标. 目录 一.准备 二.代码 可以先去看看之前的文章哦. 一.准备 首先pip ...

  4. 【基于Arduino APDS9960 传感器的手势控制非接触式电梯】

    基于Arduino APDS9960 传感器的手势控制非接触式电梯 前言 所需组件 APDS9960 RGB & 手势传感器 电路原理图 代码说明 测试手势控制的非接触式升降机 完整代码 前言 ...

  5. c++ opencv 通过网络连接工业相机_使用OpenCV进行手势控制游戏+源码分享

    前期文章链接: 霍夫变换--形状特征提取算法:车道线检测 开源自动驾驶汽车数据集 基于深度学习和神经网络的重要基础及方法概要 深度学习背后的数学思想 正文: 在本文中,您将了解使用OpenCV在Pyt ...

  6. 基于STM32或STC的手势控制MP3语音播放器的设计

    一. 系统设计框图 区别于传统设计中的按键开关控制,本设计可以实现通过手势控制MP3播放器.采用STM32或STC15单片机和PAJ7620手势模块,能够识别九种手势,分别为上下左右前后,顺时针,逆时 ...

  7. 计算机为什么连接鼠标后不能控制,电脑鼠标连接不上怎么回事解决教程

    鼠标连不上电脑怎么办,明明新买的鼠标却不能连接,是系统问题吗?那么下面就由学习啦小编来给你们说说电脑鼠标连接不上的解决方法吧,希望可以帮到你们哦! 电脑鼠标连接不上的解决方法一: 第一种方法即重启你的 ...

  8. Python wxpy通过ModBus控制电脑鼠标和键盘

    Python代码 import sys import ctypes import os import win32 import win32gui import threading import tim ...

  9. python控制电脑鼠标和键盘,登录QQ

    import os from pynput.mouse import Button,Controller from pynput.keyboard import Key from pynput.key ...

最新文章

  1. 为什么kafka的消费者要有分组的概念
  2. 第三章 搜索与图论 【完结】
  3. tcp/udp高并发和高吐吞性能测试工具
  4. 通达信波段王指标公式主图_通达信波段线主图指标公式
  5. webconfig和appconfig中出现特殊字符如何处理
  6. windows的bpython安装方法以及数据库报错--记录
  7. 工作188:表单校验规则
  8. ecilpse+python中文输入输出
  9. C++ std::unordered_map怎么用
  10. 远程桌面工具mRemoteNG与Tsmmc
  11. python识别文字坐标_python识别图片上的文字并返回文字在图片中的坐标
  12. 网易博客搬家至CSDN博客指南
  13. tinyproxy王卡免流配置_【免流教程】王卡动态tiny免流教程
  14. 眼底病php 是什么病,眼底病常见的7种类型 你都需要了解清楚!
  15. c++实现文件传输之三:断点续传与多线程传输
  16. 软件工程之需求分析②(软件需求规则说明书、数据要求说明书、初步用户手册、软件开发实施计划)
  17. 六大质疑拷问大中华第一妖股 蒙古能源估值调查
  18. Android App开发实战项目之模仿美图秀秀的抠图工具(附源码和演示视频 简单易懂 可直接使用)
  19. 软考高级(信息系统项目管理师)高频考点:项目质量管理
  20. RT-Thread 的自动初始化机制

热门文章

  1. Springboot毕设项目烬燃电竞酒店管理系统7xgz8(java+VUE+Mybatis+Maven+Mysql)
  2. WCF实现全双工通信笔记
  3. 百度地图开发(二)——开发前的准备(密钥的申请)
  4. 金蝶K3 14.0 泛微OA10.0 注册机 学习沟通
  5. selenium + python处理select标签下拉框的选项
  6. java实现传入URL下载图片并压缩,导出到excel
  7. 聚乙烯原料最新价格 聚丙烯价格多少钱一吨?
  8. [HDLbits] Conway‘s game of life
  9. 数字化转型2020,如何加速传统IT到企业云的过渡?
  10. 开源项目 02 HttpLib