手势识别控制鼠标和键盘

项目已经及上传github,需者自取。

https://github.com/grey-wood-wolf/Gesture-recognition-mouse-and-keyboard-control

完成人:李政廉 黄鑫杰 傅英伦

实现功能

实现左右手的手势识别,并非触摸控制鼠标的移动和点击,以及键盘上下按键的控制。

所用模型

本项目使用了MediaPipe中的MediaPipe Hands模型以及python的AutoPy GUI工具包。

MediaPipe是一款由 Google Research 开发并开源的多媒体机器学习模型应用框架。MediaPipe的核心框架由C++实现。

MediaPipe Hands为MediaPipe中的手部识别模型,它是一种高保真手和手指跟踪解决方案,采用机器学习 (ML) 从单个帧中推断出手的21个3D地标。

(1) Palm Detection Model(手掌检测模型)

手掌检测模型,对整个图像进行操作并返回一个定向的手部边界框。

使用非极大值抑制(NMS)算法来解决手部自遮挡的问题,使用bounding box来建模。

(2)Hand Landmark Model(手部地标模型)

手部地标模型,对手掌检测器定义的裁剪图像区域进行操作,并返回高保真3D手部关键点。

在训练该模型时,使用人工注释的大约30K个具有 21个3D 坐标的真实世界图像对模型进行训练。

 检测手的集合,其中每只手表示为 21 个手部标志的列表,每个标志由x、y和z组成。x和y的范围由图像宽度和高度进行归一化处理为0-1。z表示以手腕深度为原点的地标深度,值越小,地标离相机越近。

AutoPy

AutoPy是一个简单跨平台的 Python GUI工具包,可以控制鼠标,键盘,匹配颜色和屏幕上的位图。

      本项目主要使用的autopy方法

      autopy.mouse.move()

通过x,y方向的坐标控制鼠标的移动。

autopy.mouse.toggle(None, True/False)

控制鼠标是否点击。值为True时控制鼠标点击,值为False时控制鼠标松开,默认为鼠标左键。

autopy.mouse.click(autopy.mouse.Button.RIGHT)

控制鼠标右键的点击。

autopy.key.toggle(autopy.key.Code.DOWN_ARROW, True/False, [])

控制键盘向下箭头的键入。

autopy.key.toggle(autopy.key.Code.UP_ARROW, True/False, [])

控制键盘向上箭头的键入。

实现流程

主函数

 

	def findHands(self, img, draw=True)def findPosition(self, img, handNo=0, draw=True)def fingersUp(self)def findDistance(self, p1, p2, img, draw=True, r=15, t=3)

第一个函数可以检测手的存在,并且给出21个点位的原始数据。

第二个函数可以将21个点位的数据进行变化,最总得到在显示屏上映射的相对位置信息。

第三个函数可以根据节点的相对位置判断每每根手指的抬起和放下情况。

第四个函数可以得到两根手指末端的间距大小。

跟踪

 

对象检测和跟踪管道可以实现为一个MediaPipe图,它内部利用了一个对象检测子图、一个对象跟踪子图和一个渲染子图。

一般来说,对象检测子图(在内部执行ML模型推断)仅在请求时运行,例如以任意帧速率或由特定信号触发。更具体地说,在这个特殊的图中,一个PacketResampler计算单元在传入的视频帧被传递到对象检测子图之前,暂时对其进行0.5 fps的子采样。这个帧率可以配置为不同的选项在PacketResampler。

目标跟踪子图在每一帧上实时运行,跟踪被检测到的目标。它扩展了盒跟踪子图,增加了额外的功能:当新的检测到达时,它使用IoU(交叉Union)将当前跟踪的对象/盒与新的检测相关联,以删除过时或重复的目标框。

手部检测

位置处理 

 手指识别

距离判断 

行为控制 

 模块调用关系

识别代码被分成了5个模块,分别为手部检测模块,位置处理模块,手指识别模块,距离判断模块,行为控制模块。分别实现,手部检测,位置处理,手指识别,距离判断,行为控制的功能。

其中的调用关系为这5个模块都在主函数中被调用,然后各个模块给出对应需要的数据。

如下图:

 

各模块的对应关系:

手部识别理模块会利用所使用的框架将图片中的手识别,并给出21个点位信息给位置处理模块。

位置处理模块会利用21个点位的信息我,算出屏幕映射位置,并传给手指识别模块和距离判断模块。

之后手指识别模块会利用映射位置判断手指的抬起判断结果,最终返回给行为控制模块。

距离判断模块会利用映射位置算出两个手指间的距离,并返回结果给行为控制模块。、

最终行为控制模块将根据判断,控制鼠标键盘,以及屏幕的显示。

关系如下图:

测试及评估结果

 

分析:因为利用轻量级的识别,可以实现较高帧率的显示,对于手的识别也成功率十分高,无论实在或明或暗,或者将手藏起来部分,也可以识别出来,并且显示点位,并且对于手势控制鼠标和键盘十分成功,并不会出现太明显的误判和未识别。交互控制过程很流畅,没有出现滞留和延时的情况,但对于手翻转后的手势判定,无法识别,于是我们利用位置信息进行判断,实现手翻面后的识别和控制。 

分析:再加入判断后,右手反转或者左手控制也可以实现相对应的功能,没有出现控制判断错误的情况产生,并且,整个人机交互过程也十分的流畅和高效。 

代码展示

手部检测和人机交互控制主程序代码

import cv2
import numpy as np
import HandTrackingModule as htm
import time
import autopy##########################
wCam, hCam = 640, 480
frameR = 100  # Frame Reduction
smoothening = 7
#########################pTime = 0
plocX, plocY = 0, 0
clocX, clocY = 0, 0cap = cv2.VideoCapture(0)
cap.set(3, wCam)
cap.set(4, hCam)
detector = htm.handDetector(maxHands=1)
wScr, hScr = autopy.screen.size()
# print(wScr, hScr)flag = 0
while True:# 1. Find hand Landmarkssuccess, img = cap.read()img = detector.findHands(img)lmList, bbox = detector.findPosition(img)# 2. Get the tip of the index and middle fingersif len(lmList) != 0:x1, y1 = lmList[8][1:]x2, y2 = lmList[12][1:]# print(x1, y1, x2, y2)cv2.rectangle(img, (frameR, frameR), (wCam - frameR, hCam - frameR),(255, 0, 255), 2)# 3. Check which fingers are upfingers = detector.fingersUp()if fingers:# print(fingers)# 4. Only Index Finger : Moving Modeif fingers[1] == 1 and fingers[2] == 0:# 5. Convert Coordinatesx3 = np.interp(x1, (frameR, wCam - frameR), (0, wScr))y3 = np.interp(y1, (frameR, hCam - frameR), (0, hScr))# 6. Smoothen ValuesclocX = plocX + (x3 - plocX) / smootheningclocY = plocY + (y3 - plocY) / smoothening# 7. Move Mouseautopy.mouse.move(wScr - clocX, clocY)cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)plocX, plocY = clocX, clocY# 8. Both Index and middle fingers are up : Clicking Modeif fingers[1] == 1 and fingers[2] == 1:# 9. Find distance between fingerslength, img, lineInfo = detector.findDistance(8, 12, img)if length < 40 and flag == 0:cv2.circle(img, (lineInfo[4], lineInfo[5]),15, (0, 255, 0), cv2.FILLED)autopy.mouse.toggle(None,True)flag = 1elif length >= 40 and flag == 1:cv2.circle(img, (lineInfo[4], lineInfo[5]),15, (0, 255, 0), cv2.FILLED)autopy.mouse.toggle(None,False)flag = 0if fingers[0] == 0 and fingers[1] == 0 and fingers[2] == 0:autopy.mouse.click(autopy.mouse.Button.RIGHT)if fingers[0] == 1 and fingers[1] == 0 and fingers[2] == 0:autopy.key.toggle(autopy.key.Code.DOWN_ARROW, True, [])autopy.key.toggle(autopy.key.Code.DOWN_ARROW, False, [])if fingers[0] == 1 and fingers[1] == 1 and fingers[2] == 1:autopy.key.toggle(autopy.key.Code.UP_ARROW, True, [])autopy.key.toggle(autopy.key.Code.UP_ARROW, False, [])# 11. Frame RatecTime = time.time()fps = 1 / (cTime - pTime)pTime = cTimecv2.putText(img, str(int(fps)), (20, 50), cv2.FONT_HERSHEY_PLAIN, 3,(255, 0, 0), 3)# 12. Displaycv2.imshow("Image", img)cv2.waitKey(1)

手部识别跟踪代码

import cv2
import mediapipe as mp
import time
import mathclass handDetector():def __init__(self, mode=False, maxHands=1, detectionCon=0.5, trackCon=0.5):self.mode = modeself.maxHands = maxHandsself.detectionCon = detectionConself.trackCon = trackConself.mpHands = mp.solutions.handsself.hands = self.mpHands.Hands(static_image_mode=self.mode,max_num_hands=self.maxHands,min_detection_confidence=self.detectionCon,min_tracking_confidence=self.trackCon)self.mpDraw = mp.solutions.drawing_utilsself.tipIds = [4, 8, 12, 16, 20]def findHands(self, img, draw=True):imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)self.results = self.hands.process(imgRGB)#print(self.results.multi_hand_landmarks)if self.results.multi_hand_landmarks:for handLms in self.results.multi_hand_landmarks:if draw:self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS)return imgdef findPosition(self, img, handNo=0, draw=True):xList = []yList = []bbox = []self.lmList = []if self.results.multi_hand_landmarks:myHand = self.results.multi_hand_landmarks[handNo]for id, lm in enumerate(myHand.landmark):# print(id, lm)h, w, c = img.shapecx, cy = int(lm.x * w), int(lm.y * h)xList.append(cx)yList.append(cy)self.lmList.append([id, cx, cy])if draw:cv2.circle(img, (cx, cy), 5, (255, 0, 255), cv2.FILLED)xmin, xmax = min(xList), max(xList)ymin, ymax = min(yList), max(yList)bbox = xmin, ymin, xmax, ymaxif draw:cv2.rectangle(img, (xmin - 20, ymin - 20), (xmax + 20, ymax + 20),(0, 255, 0), 2)return self.lmList, bboxdef fingersUp(self):fingers = []if self.lmList:if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0] - 1][1] \and self.lmList[self.tipIds[1]][1] > self.lmList[self.tipIds[2]][1] \or self.lmList[self.tipIds[0]][1] < self.lmList[self.tipIds[0] - 1][1] \and self.lmList[self.tipIds[1]][1] < self.lmList[self.tipIds[2]][1]:fingers.append(1)else:fingers.append(0)# Fingersfor id in range(1, 5):if self.lmList[self.tipIds[id]][2] < self.lmList[self.tipIds[id] - 2][2]:fingers.append(1)else:fingers.append(0)# totalFingers = fingers.count(1)return fingersdef findDistance(self, p1, p2, img, draw=True, r=15, t=3):x1, y1 = self.lmList[p1][1:]x2, y2 = self.lmList[p2][1:]cx, cy = (x1 + x2) // 2, (y1 + y2) // 2if draw:cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), t)cv2.circle(img, (x1, y1), r, (255, 0, 255), cv2.FILLED)cv2.circle(img, (x2, y2), r, (255, 0, 255), cv2.FILLED)cv2.circle(img, (cx, cy), r, (0, 0, 255), cv2.FILLED)length = math.hypot(x2 - x1, y2 - y1)return length, img, [x1, y1, x2, y2, cx, cy]def main():pTime = 0cTime = 0cap = cv2.VideoCapture(0)detector = handDetector()while True:success, img = cap.read()img = detector.findHands(img)lmList, bbox = detector.findPosition(img)if len(lmList) != 0:print(lmList[4])cTime = time.time()fps = 1 / (cTime - pTime)pTime = cTimecv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,(255, 0, 255), 3)cv2.imshow("Image", img)cv2.waitKey(1)if __name__ == "__main__":main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/62543.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Parsec】远程控制鼠标消失不可见的解决方法

转载连接&#xff1a;https://www.cnblogs.com/cowmax/p/13577769.html 一、问题描述 通过在云端的主机上部署 frp 服务&#xff0c;实现「使用Windows 远程桌面&#xff08;RDP&#xff09;从互联网侧访问内网的主机」。但是&#xff0c;使用 Windows 自带的远程桌面工具 RD…

员工离职倾向尽在公司掌握,争议发生后,监控系统研发商悄悄下架相关服务

你上班时会使用公司WiFi还是自己的流量呢&#xff1f;如果你平时经常用公司的网络摸鱼&#xff0c;那你现在可要注意了&#xff0c;因为你的上网记录很有可能都被监控下来了。 事情经过 上周&#xff0c;有一个网友发帖称自己开工第一天就被裁&#xff0c;原因竟是领导知道了…

2017 年 IT 界最严重的裁员事件汇总

程序猿&#xff08;微信号&#xff1a;imkuqin&#xff09; 猿妹 整编 裁员年年都有&#xff0c;今年特别多从微软、Oracle、IBM&#xff0c;到思科、HPE&#xff0c;再到雅虎、stackoverflow&#xff0c;无论是处于转型变革中的老牌巨头&#xff0c;还是日渐成熟的创新型公司&…

这可能是2018年IT界规模最大的裁员事件了

作者&#xff1a;焱公子&#xff0c;发型光芒万丈的跨界理工男。多年500强&#xff0c;专注写职场。解薄情人世&#xff0c;书深情故事。 来自&#xff1a;焱公子&#xff08;ID&#xff1a;Yangongzi2015&#xff09; 这可能是2018年IT界规模最大的裁员事件了。近日&#xff0…

阿里最新发布2023版Java八股文PDF版,是真的很强

大家好&#xff0c;今天给大家分享一套 阿里10w字 Java 面试手册。266页&#xff0c;涵盖基础篇、JVM篇、多线程并发篇、Spring篇、MyBatis篇、SpringBoot篇、MySQL篇、SpringCloud篇、Dubbo篇、Nginx篇、MQ篇、数据结构与算法篇、Linux篇、Zookeeper篇、Redis篇、分布式篇、网…

阿里原来这么容易就能进去…

最近和阿里的一个老朋友闲聊&#xff0c;感触颇深&#xff0c;据他说公司近期招聘的测试工程师&#xff0c;大多数候选人都有一个“通病”&#xff1a;在工作2-3年的时候遇到瓶颈&#xff0c;而且是一道很难跨越的坎。 为什么会遇到这种情况&#xff1f;因为大部分测试工程师在…

二战阿里巴巴成功上岸,准备了小半年,要个28k应该也算不上很高吧~

先说下我基本情况&#xff0c;本科不是计算机专业&#xff0c;现在是学通信&#xff0c;然后做图像处理&#xff0c;可能面试官看我不是科班出身没有问太多计算机相关的问题&#xff0c;因为第一次找工作&#xff0c;阿里的游戏专场又是最早开始的&#xff0c;就投递了&#xf…

阿里巴巴原来这么容易就能进去…

最近和阿里的一个老朋友闲聊&#xff0c;感触颇深&#xff0c;据他说公司近期招聘的测试工程师&#xff0c;大多数候选人都有一个“通病”&#xff1a;在工作2-3年的时候遇到瓶颈&#xff0c;而且是一道很难跨越的坎。 为什么会遇到这种情况&#xff1f;因为大部分测试工程师在…

这是一篇能够教会你运营阿里巴巴国际站的文章

对于很多跨境人来说&#xff0c;运营真的是一个让人头疼的大事情。不知道要从哪个方面下手&#xff0c;不知道要往哪方面努力等等问题都是很常见的&#xff0c;所以今天龙哥就解剖一下阿里巴巴国际站的运营方法&#xff0c;简单地给大家讲一下要掌握哪些方面的知识。运营这条路…

威洛特:狗狗骨折如何应急的去处理?

狗狗这种喜欢活蹦乱跳的动物&#xff0c;真的一不小心可能就把自己骨头折了。骨折会影响狗狗的身体健康和正常生活&#xff0c;必须及时治疗。接下来威洛特就给大家分享一些狗狗骨折的相关注意事项。 一、狗狗骨折的应急处理 当狗狗骨折的时候&#xff0c;它的骨头很可能错位了…

安全狗的绕过

环境&#xff1a; phpstudy2018 安全狗apache版 sqllabs靶场 安全狗绕过思路&#xff1a; 安全狗是基于正则匹配的绕过&#xff0c;所以总是能够绕过其正则匹配实现sql的命令执行&#xff0c;需要对数据库语句灵活掌握。经过对安全狗的fuzz&#xff0c;测试其拦截规则&#xff…

Android Watchdog 狗子到底做了啥

作者&#xff1a;流浪汉kylin 原文链接&#xff1a;https://juejin.cn/post/7215498393429983291 前言 有一定开发经验的或多或少有听过Watchdog&#xff0c;那什么是Watchdog呢&#xff1f;Watchdog又称看门狗&#xff0c;看门狗是育碧开发的一款游戏&#xff0c;目前已出到《…

python程序编程代码大全,python编程代码详解

大家好&#xff0c;本文将围绕python程序编程代码大全展开说明&#xff0c;python编程游戏代码是一个很多人都想弄明白的事情&#xff0c;想搞清楚python代码大全简单需要先了解以下几个事情。 1、python编程例子有哪些&#xff1f; python编程经典例子&#xff1a; 1、画爱心…

宝峰数科带你读懂数字家庭的真正内涵

由建标〔2021〕28号文《关于加快发展数字家庭提高居住品质的指导意见》开启的数字家庭国家建设已有一年多&#xff0c;但仍有不少人不能清晰理解数字家庭与早已存在的智能家居、智慧家庭、全屋智能等传统智能之间的区别&#xff0c;业内对数字家庭的认识还不够深入、有待提高。…

易观数科代码埋点、全埋点、可视化埋点

讲埋点的文章那么多&#xff0c;我们为什么还要写它&#xff1f;首先&#xff0c;这不是一篇纯技术文章&#xff0c;而是从一个非技术人员的角度&#xff0c;希望通过浅显的语言描述&#xff0c;让运营同学能快速了解概念。 此外&#xff0c;目前市面的埋点文章&#xff0c;要…

京东数科(实习一面)

数据库之范式数据库之索引线程间通信反射什么是字节码&#xff1f;采用字节码的最大好处是什么&#xff1f;Java如何实现一次编译到处运行的。 数据库之范式 目前关系型数据库一共有 6 种范式&#xff0c;按照范式级别&#xff0c;从低到高分别是&#xff1a;1NF&#xff08;第…

360数科发布2020全年财报:全年收入上涨47.1%,科技为运营效率提供第一动力

3月16日&#xff0c;360数科发布2020年第4季度及全年未经审计的财务报告。2020财年&#xff0c;360数科实现收入135.64亿元&#xff0c;较2019年92.2亿元增长47.1%&#xff1b;非美国会计准则&#xff08;Non-GAAP&#xff09;下净利润为37.97亿元&#xff0c;较2019年27.52亿元…

不追逐标准化产品,360数科的一站式风控体系有何不同?

新冠肺炎疫情无疑加速了金融行业数字化转型&#xff0c;竞争者不断涌入&#xff0c;逐渐形成由BATJ、传统银行旗下金融科技子公司、以及专注于金融机构的数字化服务公司构成的竞争格局。然而&#xff0c;风控始终是金融行业的核心。作为定位于中国零售金融领域科技服务商的360数…

没有场景,不做单点技术输出,360数科如何做金融科技的最佳实践?

作者 | Just 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 从互联网金融公司转变为金融科技公司&#xff0c;品牌升级后的360数科强化了“科技”的外衣。 在近期的首个360数科技术开放日&#xff0c;360数科CEO吴海生表示&#xff0c;他们已经做好金融科技的最佳…

融象数科Java开发实习记录(一)

遇到的问题和解决方法 maven安装依赖卡死 重启等方法无效。 解决办法 修改maven Importing的jvm参数, 默认为700多, 直接修改成 -Xms1024m -Xmx2048m后端启动后&#xff0c;访问前端出现数据库字段无法识别错误 数据库和前后端代码无错&#xff0c;重新安装依赖无效&#…