opencv实战项目 手势识别-手势控制键盘

手势识别是一种人机交互技术,通过识别人的手势动作,从而实现对计算机、智能手机、智能电视等设备的操作和控制。

1.  opencv实现手部追踪(定位手部关键点)

2.opencv实战项目 实现手势跟踪并返回位置信息(封装调用)

3.opencv实战项目 手势识别-手势控制鼠标

4.opencv实战项目 手势识别-手势控制键盘

未完待续

本专栏记录作者的学习之旅会一直更新下去,欢迎订阅一起学习进步

本项目是使用了谷歌开源的框架mediapipe,里面有非常多的模型提供给我们使用,例如面部检测,身体检测,手部检测等在这里插入图片描述

 代码需要用到opencv   HandTraqckModule模块   mediapipe模块和一个键盘控制模块pynput,cvzone模块

一、HandTraqckModule模块 

前面的文章中有封装手部检测模块的教程,这边简单的介绍一下,有新增加的模块可以简单学习一下

import cv2
import mediapipe as mp
import mathclass HandDetector:"""Finds Hands using the mediapipe library. Exports the landmarksin pixel format. Adds extra functionalities like finding howmany fingers are up or the distance between two fingers. Alsoprovides bounding box info of the hand found."""def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):""":param mode: In static mode, detection is done on each image: slower:param maxHands: Maximum number of hands to detect:param detectionCon: Minimum Detection Confidence Threshold:param minTrackCon: Minimum Tracking Confidence Threshold"""self.mode = modeself.maxHands = maxHandsself.detectionCon = detectionConself.minTrackCon = minTrackConself.mpHands = mp.solutions.handsself.hands = self.mpHands.Hands(self.mode, self.maxHands,self.detectionCon, self.minTrackCon)self.mpDraw = mp.solutions.drawing_utilsself.tipIds = [4, 8, 12, 16, 20]self.fingers = []self.lmList = []def findHands(self, img, draw=True):"""Finds hands in a BGR image.:param img: Image to find the hands in.:param draw: Flag to draw the output on the image.:return: Image with or without drawings"""imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)self.results = self.hands.process(imgRGB)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):"""Finds landmarks of a single hand and puts them in a listin pixel format. Also finds the bounding box around the hand.:param img: main image to find hand in:param handNo: hand id if more than one hand detected:param draw: Flag to draw the output on the image.:return: list of landmarks in pixel format; bounding box"""xList = []yList = []bbox = []bboxInfo = []self.lmList = []if self.results.multi_hand_landmarks:myHand = self.results.multi_hand_landmarks[handNo]for id, lm in enumerate(myHand.landmark):h, w, c = img.shapepx, py = int(lm.x * w), int(lm.y * h)xList.append(px)yList.append(py)self.lmList.append([px, py])if draw:cv2.circle(img, (px, py), 5, (255, 0, 255), cv2.FILLED)xmin, xmax = min(xList), max(xList)ymin, ymax = min(yList), max(yList)boxW, boxH = xmax - xmin, ymax - yminbbox = xmin, ymin, boxW, boxHcx, cy = bbox[0] + (bbox[2] // 2), \bbox[1] + (bbox[3] // 2)bboxInfo = {"id": id, "bbox": bbox, "center": (cx, cy)}if draw:cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),(bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),(0, 255, 0), 2)return self.lmList, bboxInfodef fingersUp(self):"""Finds how many fingers are open and returns in a list.Considers left and right hands separately:return: List of which fingers are up"""if self.results.multi_hand_landmarks:myHandType = self.handType()fingers = []# Thumbif myHandType == "Right":if self.lmList[self.tipIds[0]][0] > self.lmList[self.tipIds[0] - 1][0]:fingers.append(1)else:fingers.append(0)else:if self.lmList[self.tipIds[0]][0] < self.lmList[self.tipIds[0] - 1][0]:fingers.append(1)else:fingers.append(0)# 4 Fingersfor id in range(1, 5):if self.lmList[self.tipIds[id]][1] < self.lmList[self.tipIds[id] - 2][1]:fingers.append(1)else:fingers.append(0)return fingersdef findDistance(self, p1, p2, img, draw=True):"""Find the distance between two landmarks based on theirindex numbers.:param p1: Point1 - Index of Landmark 1.:param p2: Point2 - Index of Landmark 2.:param img: Image to draw on.:param draw: Flag to draw the output on the image.:return: Distance between the pointsImage with output drawnLine information"""if self.results.multi_hand_landmarks:x1, y1 = self.lmList[p1][0], self.lmList[p1][1]x2, y2 = self.lmList[p2][0], self.lmList[p2][1]cx, cy = (x1 + x2) // 2, (y1 + y2) // 2if draw:cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)length = math.hypot(x2 - x1, y2 - y1)return length, img, [x1, y1, x2, y2, cx, cy]def handType(self):"""Checks if the hand is left or right:return: "Right" or "Left""""if self.results.multi_hand_landmarks:if self.lmList[17][0] < self.lmList[5][0]:return "Right"else:return "Left"def main():cap = cv2.VideoCapture(0)detector = HandDetector(detectionCon=0.8, maxHands=1)while True:# Get image framesuccess, img = cap.read()# Find the hand and its landmarksimg = detector.findHands(img)lmList, bboxInfo = detector.findPosition(img)print(detector.handType())# Displaycv2.imshow("Image", img)cv2.waitKey(1)if __name__ == "__main__":main()

  1. 导入库:导入了必要的库,包括 OpenCV (cv2) 用于图像处理和显示,Mediapipe (mediapipe) 用于手部检测和跟踪,以及数学库 (math)。

  2. HandDetector 类:这是主要的手势检测器类,提供了多个方法来处理手部检测和分析手势。

    • __init__ 方法:初始化检测器的参数,例如检测模式、最大检测手数、检测和跟踪的置信度阈值等。

    • findHands 方法:在给定的图像中寻找手部,可以选择是否绘制检测结果。

    • findPosition 方法:找到单个手部的关键点位置(landmarks)并将它们存储在像素格式的列表中,同时计算手部的边界框信息。

    • fingersUp 方法:确定手势中有多少个手指打开,将结果以列表形式返回。

    • findDistance 方法:计算两个指定关键点之间的距离,并在图像上绘制结果。

    • handType 方法:确定手的类型是左手还是右手。

具体就不展开讲了

这个函数在有一个专门的包叫做cvzone里有,但是不知道是不是版本的问题,少了一些东西,运行不起来,只能自己手撸检测模块。

下面是主函数的代码

import cv2
from cvzone.HandTrackingModule import HandDetector
from HandTrackingModule import *
from time import sleep
import numpy as np
import cvzone
from pynput.keyboard import Controllercap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)detector =HandDetector(detectionCon=0.5)
keys = [["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],["A", "S", "D", "F", "G", "H", "J", "K", "L", ";"],["Z", "X", "C", "V", "B", "N", "M", ",", ".", "/"]]
finalText = ""keyboard = Controller()def drawAll(img, buttonList):for button in buttonList:x, y = button.posw, h = button.sizecvzone.cornerRect(img, (button.pos[0], button.pos[1], button.size[0], button.size[1]),20, rt=0)cv2.rectangle(img, button.pos, (x + w, y + h), (255, 0, 255), cv2.FILLED)cv2.putText(img, button.text, (x + 20, y + 65),cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)return img#
# def drawAll(img, buttonList):
#     imgNew = np.zeros_like(img, np.uint8)
#     for button in buttonList:
#         x, y = button.pos
#         cvzone.cornerRect(imgNew, (button.pos[0], button.pZXos[1], button.size[0], button.size[1]),
#                           20, rt=0)
#         cv2.rectangle(imgNew, button.pos, (x + button.size[0], y + button.size[1]),
#                       (255, 0, 255), cv2.FILLED)
#         cv2.putText(imgNew, button.text, (x + 40, y + 60),
#                     cv2.FONT_HERSHEY_PLAIN, 2, (255, 255, 255), 3)
#
#     out = img.copy()
#     alpha = 0.5
#     mask = imgNew.astype(bool)
#     print(mask.shape)
#     out[mask] = cv2.addWeighted(img, alpha, imgNew, 1 - alpha, 0)[mask]
#     return outclass Button():def __init__(self, pos, text, size=[85, 85]):self.pos = posself.size = sizeself.text = textbuttonList = []
for i in range(len(keys)):for j, key in enumerate(keys[i]):buttonList.append(Button([100 * j + 50, 100 * i + 50], key))while True:success, img = cap.read()img = detector.findHands(img)lmList, bboxInfo = detector.findPosition(img)img = drawAll(img, buttonList)if lmList:for button in buttonList:x, y = button.posw, h = button.sizeif x < lmList[8][0] < x + w and y < lmList[8][1] < y + h:cv2.rectangle(img, (x - 5, y - 5), (x + w + 5, y + h + 5), (175, 0, 175), cv2.FILLED)cv2.putText(img, button.text, (x + 20, y + 65),cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)l, _, _ = detector.findDistance(8, 12, img, draw=False)print(l)## when clickedif l < 30:keyboard.press(button.text)cv2.rectangle(img, button.pos, (x + w, y + h), (0, 255, 0), cv2.FILLED)cv2.putText(img, button.text, (x + 20, y + 65),cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)finalText += button.textsleep(0.15)cv2.rectangle(img, (50, 350), (700, 450), (175, 0, 175), cv2.FILLED)cv2.putText(img, finalText, (60, 430),cv2.FONT_HERSHEY_PLAIN, 5, (255, 255, 255), 5)cv2.imshow("Image", img)cv2.waitKey(1)
  1. 导入库:导入了需要的库,包括 OpenCV (cv2) 用于图像处理和显示,Mediapipe 中的 HandDetector 用于手部检测,cvzone 用于绘制按钮外观,numpy 用于数组处理,pynput.keyboard 中的 Controller 用于模拟键盘输入,time 用于延时。

  2. 设置摄像头参数:通过 OpenCV 设置摄像头的分辨率为 1280x720。

  3. 创建 HandDetector 实例:使用 HandDetector 类创建一个手势检测器实例,设置检测的置信度阈值为 0.5。

  4. 创建按钮列表:创建了一个包含虚拟键盘按钮信息的列表,按键布局通过嵌套列表 keys 定义。

  5. 创建 Button 类:用于创建虚拟按钮的类,每个按钮包含位置、文本内容和大小。

  6. 主循环:进入一个无限循环,用于处理实时的摄像头捕获图像帧。

    • 读取图像帧:从摄像头捕获图像帧。

    • 手部检测:使用手势检测器找出图像中的手部和关键点。

    • 绘制按钮:调用 drawAll 函数在图像上绘制虚拟按钮。

    • 遍历按钮列表:对每个按钮进行检查,看是否有手指触摸到按钮。

      • 如果手指在按钮范围内,绘制高亮效果。

      • 计算手指触摸点与按钮中心的距离,如果小于一定阈值,则模拟键盘按下并记录输入。

    • 绘制已输入的文本:在图像上绘制已输入的文本。

    • 显示图像:通过 OpenCV 显示处理后的图像。

    • 等待键盘输入:等待 1 毫秒,以便保持图像窗口的响应性。

  7. 运行主程序:执行主循环,处理实时的摄像头捕获和手势识别。

如果有遇到问题可以评论区留言,大家一起相互学习!

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

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

相关文章

机器学习线性代数基础

本文是斯坦福大学CS 229机器学习课程的基础材料&#xff0c;原始文件下载 原文作者&#xff1a;Zico Kolter&#xff0c;修改&#xff1a;Chuong Do&#xff0c; Tengyu Ma 翻译&#xff1a;黄海广 备注&#xff1a;请关注github的更新&#xff0c;线性代数和概率论已经更新完毕…

多元最短路(Floyd)

是一个基于动态规划的全源最短路算法。它可以高效地求出图上任意两点之间的最短路 时间复杂度 O(n^3) 状态转移方程 f[i][j]min(f[i][j],f[i][k]f[k][j]) 核心代码 void floyd(){for(int k1;k<n;k)for(int i1;i<n;i)for(int j1;j<n;j)s[i][j]min(s[i][j],s[i][k…

springboot 基础

巩固基础&#xff0c;砥砺前行 。 只有不断重复&#xff0c;才能做到超越自己。 能坚持把简单的事情做到极致&#xff0c;也是不容易的。 SpringBoot JavaEE 简介 JavaEE的局限性&#xff1a; 1、过于复杂&#xff0c;JavaEE正对的是复杂的分布式企业应用&#xff0c;然而现实…

现代无人机技术

目录 1.发展 2.应用领域 3.对战争的影响 4.给人类带来的福利 5.给人类带来的坏处 1.发展 无人机的发展可以分为以下几个关键步骤&#xff1a; 1. 早期试验和研究&#xff1a;20世纪初&#xff0c;飞行器的概念开始出现&#xff0c;并进行了一些早期的试飞和实验。这些尝试包…

马来西亚的区块链和NFT市场调研

马来西亚的区块链和NFT市场调研 基本介绍 参考&#xff1a; https://zh.wikipedia.org/wiki/%E9%A9%AC%E6%9D%A5%E8%A5%BF%E4%BA%9A zz制度&#xff1a;联邦议会制 语言文字&#xff1a; 马来语 民族&#xff1a; 69.4%原住民&#xff08;土著&#xff09;&#xff0c;23.2%…

[HDLBits] Exams/m2014 q3

Consider the function f shown in the Karnaugh map below. Implement this function. d is dont-care, which means you may choose to output whatever value is convenient. //empty

【网络基础实战之路】实现RIP协议与OSPF协议间路由交流的实战详解

系列文章传送门&#xff1a; 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 PS&#xff1a;本要求基于…

Labview控制APx(Audio Precision)进行测试测量(七)

处理集群控制子集 大多数用户不会想要设置所有的控制包括在一个大的控制集群&#xff0c;如水平和增益配置控制。例如&#xff0c;假设您只在 APx 中使用模拟不平衡输出连接器&#xff0c;而您想要做的就是控制发电机的电平和频率。在这种情况下&#xff0c;水平和增益配置集群…

一休休的面试题

重点面试题(今天又看了很多的博客大概有个三十来篇吧所以总结了一休休的面试题)&#xff1a; ps:已经入秋了为什么还是这么热&#xff01;&#xff01;&#xff01; 1、受管 bean 的生命周期 对于普通的 Java 对象&#xff0c;new 的时候会去创建对象&#xff0c;而当它没有…

记录--用css画扇形菜单

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 1、效果图 用手机录屏再用小程序转换的gif&#xff0c;可能精度上有点欠缺。 2、实现过程 1、观察及思考 开始编码前我们首先观察展开后的结构&#xff1a;两个四分之一的圆加三个圆形菜单项。 文章名…

Tomcat的动静分离以及多实例部署

一、动静分离 Nginx实现负载均衡的原理&#xff1a; Nginx实现负载均衡是通过反向代理实现Nginx服务器作为前端&#xff0c;Tomcat服务器作为后端&#xff0c;web页面请求由Nginx服务来进行转发。 但不是把所有的web请求转发&#xff0c;而是将静态页面请求Ncinx服务器自己来处…

【C++起飞之路】初级—— auto、范围for循环、宏函数和内联函数

auto、范围for、内联函数、宏函数和nullptr 一、auto — 类型推导的魔法&#xff08;C 11)1、auto 是什么&#xff1f;2、工作原理3、优势4、限制和注意事项 二、范围for (C11)1、基本语法2、优势3、工作原理4、注意事项5、C11&#xff1a; 范围 for 循环的扩展&#xff1a; 三…

如何预防ssl中间人攻击?

当我们连上公共WiFi打开网页或邮箱时&#xff0c;殊不知此时可能有人正在监视着我们的各种网络活动。打开账户网页那一瞬间&#xff0c;不法分子可能已经盗取了我们的银行凭证、家庭住址、电子邮件和联系人信息&#xff0c;而这一切我们却毫不知情。这是一种网络上常见的“中间…

刨根问底,不再纠结Linux 文件权限问题

Linux 与Windows的区别 与Windows 系统不一样&#xff0c;在Linux系统中&#xff0c;无论是系统内核还是应用程序&#xff0c;都是文件。正如此&#xff0c;当你学习Linux中遇到问题时&#xff0c;总能看到热心网友的解决方法&#xff1a; rm -rf * 一旦运行此命令&#x…

Maven 基础学习及使用

Maven1 Maven简介1.1 Maven模型1.2 仓库 2 Maven安装配置3 Maven基本使用3.1 Maven 常用命令3.2 Maven 生命周期 4 IDEA使用Maven4.1 IDEA配置Maven环境4.2 Maven 坐标详解4.3 IDEA 创建 Maven项目4.4 IDEA 导入 Maven项目 5 依赖管理5.1 使用坐标引入jar包5.2 依赖范围 Maven …

STM32的电动自行车信息采集上报系统(学习)

摘要 针对电动自行车实时监管不便的问题&#xff0c;设计了一种基于STM32的电动自行车信息采集系统&#xff0c;通过获取电池、位置和行驶状态信息并上报到服务器中&#xff0c;实现实时监管。 通过多路串口请求电池、行驶状态和位置信息&#xff0c;以并发方式进行数据接收、…

块、行内块水平垂直居中

1.定位实现水平垂直居中 <div class"outer"><div class"test inner1">定位实现水平垂直居中</div></div><style>.outer {width: 300px;height: 300px;border: 1px solid gray;margin: 100px auto 0;position: relative;}.te…

Redis集群(三十七)

部署搭建Redis主从复制、哨兵模式、集群部署 目录 一、Redis主从复制 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;作用 &#xff08;三&#xff09;缺点 &#xff08;四&#xff09;流程 &#xff08;五&#xff09;搭建 二、Redis哨兵模式 &#xff0…

软件测试基础篇——MySQL

MySQL 1、数据库技术概述 数据库database&#xff1a;存放和管理各种数据的仓库&#xff0c;操作的对象主要是【数据data】&#xff0c;科学的组织和存储数据&#xff0c;高效的获取和处理数据SQL&#xff1a;结构化查询语言&#xff0c;专为**关系型数据库而建立的操作语言&…

ORB-SLAM2第二节---双目地图初始化

比起单目初始化&#xff0c;而双目实现地图的初始化非常简单&#xff0c;只需要一帧&#xff08;左右目图像&#xff09;即可完成初始化。 行特征点统计。考虑用图像金字塔尺度作为偏移量&#xff0c;在当前点上下正负偏移量&#xff08;r)内的纵坐标值都认为是匹配点可能存在…