opencv实战项目 手势识别-手部距离测量

手势识别系列文章目录

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

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

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

3.手势识别-手势音量控制(opencv)

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

5.opencv实战项目 手势识别-手部距离测量

未完待续

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

在这里插入图片描述

 代码需要用到opencv   HandTraqckModule模块   mediapipe模块

一、HandTraqckModule模块 

这次我们给HandTraqckModule模块继续增加新的内容  已经会的可以直接跳过,复制粘贴调用即可。

import cv2
import mediapipe as mp
import math

定义 HandDetector 类:

class HandDetector:def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):# 初始化参数self.mode = modeself.maxHands = maxHandsself.detectionCon = detectionConself.minTrackCon = minTrackCon# 初始化 Mediapipe 的手部检测模块和绘制工具self.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.minTrackCon)self.mpDraw = mp.solutions.drawing_utilsself.tipIds = [4, 8, 12, 16, 20]self.fingers = []self.lmList = []

定义 findHands 方法,用于在图像中检测手部:

def findHands(self, img, draw=True, flipType=True):# 将图像从 BGR 转换为 RGB 格式imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 使用 Mediapipe 进行手部检测self.results = self.hands.process(imgRGB)allHands = []h, w, c = img.shapeif self.results.multi_hand_landmarks:for handType, handLms in zip(self.results.multi_handedness, self.results.multi_hand_landmarks):myHand = {}# 提取关键点的像素坐标并存储在 mylmList 中mylmList = []xList = []yList = []for id, lm in enumerate(handLms.landmark):px, py = int(lm.x * w), int(lm.y * h)mylmList.append([px, py])xList.append(px)yList.append(py)# 计算边界框信息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)myHand["lmList"] = mylmListmyHand["bbox"] = bboxmyHand["center"] = (cx, cy)if flipType:if handType.classification[0].label == "Right":myHand["type"] = "Left"else:myHand["type"] = "Right"else:myHand["type"] = handType.classification[0].labelallHands.append(myHand)# 在图像上绘制手部信息if draw:self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS)cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),(bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),(255, 0, 255), 2)cv2.putText(img, myHand["type"], (bbox[0] - 30, bbox[1] - 30), cv2.FONT_HERSHEY_PLAIN,2, (255, 0, 255), 2)if draw:return allHands, img  # 返回检测到的手部信息和绘制后的图像else:return allHands  # 只返回检测到的手部信息,不进行绘制

定义 fingersUp 方法,用于检测有多少个手指张开:

def fingersUp(self, myHand):# 获取手部信息myHandType = myHand["type"]myLmList = myHand["lmList"]if self.results.multi_hand_landmarks:fingers = []# 检测拇指if myHandType == "Right":if myLmList[self.tipIds[0]][0] > myLmList[self.tipIds[0] - 1][0]:fingers.append(1)else:fingers.append(0)else:if myLmList[self.tipIds[0]][0] < myLmList[self.tipIds[0] - 1][0]:fingers.append(1)else:fingers.append(0)# 检测其他手指for id in range(1, 5):if myLmList[self.tipIds[id]][1] < myLmList[self.tipIds[id] - 2][1]:fingers.append(1)else:fingers.append(0)return fingers

最后,main 函数使用 HandDetector 类来检测手部,并在图像中绘制检测结果:

def main():cap = cv2.VideoCapture(0)detector = HandDetector(detectionCon=0.8, maxHands=2)while True:# 获取图像帧success, img = cap.read()# 检测手部并获取手部信息和绘制后的图像hands, img = detector.findHands(img)if hands:# 处理检测到的手部信息,如关键点、边界框、手型等# ...# 显示图像cv2.imshow("Image", img)cv2.waitKey(1)if __name__ == "__main__":main()

在这个循环中,程序从摄像头捕获图像帧,然后使用 HandDetector 类来检测手部并绘制检测结果。你可以根据需要添加代码以获取手部信息并进行处理。

全部代码

"""
Hand Tracking Module
By: Computer Vision Zone
Website: https://www.computervision.zone/
"""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(static_image_mode=self.mode, max_num_hands=self.maxHands,min_detection_confidence=self.detectionCon, min_tracking_confidence = self.minTrackCon)self.mpDraw = mp.solutions.drawing_utilsself.tipIds = [4, 8, 12, 16, 20]self.fingers = []self.lmList = []def findHands(self, img, draw=True, flipType=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)allHands = []h, w, c = img.shapeif  self.results.multi_hand_landmarks:for handType,handLms in zip(self.results.multi_handedness,self.results.multi_hand_landmarks):myHand={}## lmListmylmList = []xList = []yList = []for id, lm in enumerate(handLms.landmark):px, py = int(lm.x * w), int(lm.y * h)mylmList.append([px, py])xList.append(px)yList.append(py)## bboxxmin, 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)myHand["lmList"] = mylmListmyHand["bbox"] = bboxmyHand["center"] =  (cx, cy)if flipType:if handType.classification[0].label =="Right":myHand["type"] = "Left"else:myHand["type"] = "Right"else:myHand["type"] = handType.classification[0].labelallHands.append(myHand)## drawif draw:self.mpDraw.draw_landmarks(img, handLms,self.mpHands.HAND_CONNECTIONS)cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),(bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),(255, 0, 255), 2)cv2.putText(img,myHand["type"],(bbox[0] - 30, bbox[1] - 30),cv2.FONT_HERSHEY_PLAIN,2,(255, 0, 255),2)if draw:return allHands,imgelse:return allHandsdef fingersUp(self,myHand):"""Finds how many fingers are open and returns in a list.Considers left and right hands separately:return: List of which fingers are up"""myHandType =myHand["type"]myLmList = myHand["lmList"]if self.results.multi_hand_landmarks:fingers = []# Thumbif myHandType == "Right":if myLmList[self.tipIds[0]][0] > myLmList[self.tipIds[0] - 1][0]:fingers.append(1)else:fingers.append(0)else:if myLmList[self.tipIds[0]][0] < myLmList[self.tipIds[0] - 1][0]:fingers.append(1)else:fingers.append(0)# 4 Fingersfor id in range(1, 5):if myLmList[self.tipIds[id]][1] < myLmList[self.tipIds[id] - 2][1]:fingers.append(1)else:fingers.append(0)return fingersdef main():cap = cv2.VideoCapture(0)detector = HandDetector(detectionCon=0.8, maxHands=2)while True:# Get image framesuccess, img = cap.read()# Find the hand and its landmarkshands, img = detector.findHands(img)  # with draw# hands = detector.findHands(img, draw=False)  # without drawif hands:# Hand 1hand1 = hands[0]lmList1 = hand1["lmList"]  # List of 21 Landmark pointsbbox1 = hand1["bbox"]  # Bounding box info x,y,w,hcenterPoint1 = hand1['center']  # center of the hand cx,cyhandType1 = hand1["type"]  # Handtype Left or Rightfingers1 = detector.fingersUp(hand1)if len(hands) == 2:# Hand 2hand2 = hands[1]lmList2 = hand2["lmList"]  # List of 21 Landmark pointsbbox2 = hand2["bbox"]  # Bounding box info x,y,w,hcenterPoint2 = hand2['center']  # center of the hand cx,cyhandType2 = hand2["type"]  # Hand Type "Left" or "Right"fingers2 = detector.fingersUp(hand2)# Find Distance between two Landmarks. Could be same hand or different handslength, info, img = detector.findDistance(lmList1[8], lmList2[8], img)  # with draw# length, info = detector.findDistance(lmList1[8], lmList2[8])  # with draw# Displaycv2.imshow("Image", img)cv2.waitKey(1)if __name__ == "__main__":main()

----------------------------------------分割线-----------------------------

本次的手部检测模块,我们优化了位置检测融合到了手部检测中

二、主模块

思路是:计算5和17这两个关键点的位置信息,然后算得到两点的欧几里得距离,这个距离随着手移动在图中所示出来像素距离随之变化,我们按顺序测算部分位置变化信息,以此设计一个函数来匹配这个位置变化关系。  (当然不同人的手掌会有不同,这个只是一个大致距离,误差在3%左右)

接下来是主模块代码

导入必要的库和模块:

import cv2
from HandTrackingModule import HandDetector
import math
import numpy as np
import cvzone

设置摄像头参数和手部检测器:

cap = cv2.VideoCapture(0)
cap.set(3, 1280)  # 设置摄像头宽度
cap.set(4, 720)   # 设置摄像头高度
detector = HandDetector(detectionCon=0.8, maxHands=1)  # 创建 HandDetector 实例

 定义用于将手部距离映射到厘米值的函数:

# Find Function
x = [300, 245, 200, 170, 145, 130, 112, 103, 93, 87, 80, 75, 70, 67, 62, 59, 57]
y = [20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
coff = np.polyfit(x, y, 2)  # 使用二次多项式拟合数据,得到系数 A, B, C

 进入主循环,处理实时摄像头图像:

while True:success, img = cap.read()hands = detector.findHands(img, draw=False)  # 在图像中检测手部,不进行绘制if hands:# 获取手部信息lmList = hands[0]['lmList']  # 关键点列表x, y, w, h = hands[0]['bbox']  # 边界框坐标和尺寸x1, y1 = lmList[5]  # 大拇指第一个关键点的坐标x2, y2 = lmList[17]  # 小指最后一个关键点的坐标# 计算两点之间的欧几里得距离distance = int(math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2))# 将距离映射到厘米值A, B, C = coffdistanceCM = A * distance ** 2 + B * distance + C# 在图像中绘制边界框和距离信息cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 3)cvzone.putTextRect(img, f'{int(distanceCM)} cm', (x+5, y-10))cv2.imshow("Image", img)cv2.waitKey(1)  # 按下任意按键退出循环

此代码块的主要目的是使用摄像头实时捕获图像,使用 HandDetector 类检测手部,计算两个关键点之间的距离,并将距离映射为厘米值,然后在图像中绘制边界框和距离信息。最后,通过 cv2.imshow 将绘制结果显示在窗口中,使用 cv2.waitKey 来等待并处理键盘输入,从而使程序可以持续运行。

 全部代码

import cv2
from HandTrackingModule import HandDetector
import math
import numpy as np
import cvzone# Webcam
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)# Hand Detector
detector = HandDetector(detectionCon=0.8, maxHands=1)# Find Function
# x is the raw distance y is the value in cm
x = [300, 245, 200, 170, 145, 130, 112, 103, 93, 87, 80, 75, 70, 67, 62, 59, 57]
y = [20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
coff = np.polyfit(x, y, 2)  # y = Ax^2 + Bx + C# Loop
while True:success, img = cap.read()hands = detector.findHands(img, draw=False)if hands:lmList = hands[0]['lmList']x, y, w, h = hands[0]['bbox']x1, y1 = lmList[5]x2, y2 = lmList[17]distance = int(math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2))A, B, C = coffdistanceCM = A * distance ** 2 + B * distance + C# print(distanceCM, distance)cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 3)cvzone.putTextRect(img, f'{int(distanceCM)} cm', (x+5, y-10))cv2.imshow("Image", img)cv2.waitKey(1)

有遇到的问题欢迎评论区留言

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

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

相关文章

MySQL索引和事务

目录 索引的作用 与 概念 MySQL有哪几种索引类型 如何提高查找效率 聚簇索引与非聚簇索引 覆盖索引 索引的优点和缺点 索引的一些基本操作 索引优化 B树、B树、Hash、红黑树的区别 B树与B树的区别 MySQL为什么使用B树作为索引 联合索引中的顺序 MySQL的最左前缀原…

第三节:在WORD为应用主窗口下关闭EXCEL的操作(1)

【分享成果&#xff0c;随喜正能量】夏日里的遗憾&#xff0c;一定都会被秋风温柔化解。吃素不难&#xff0c;难于不肯捨贪口腹之心。若不贪口腹&#xff0c;有何吃素之不便乎。虽吃华素&#xff0c;不吃素日&#xff0c;亦须少吃。以一切物类&#xff0c;皆是贪生怕死&#xf…

Spring Boot集成Mybatis Plus通过Pagehelper实现分页查询

文章目录 0 简要说明Pagehelper1 搭建环境1.1 项目目录1.2 项目搭建需要的依赖1.3 配置分页插件拦截器1.4 源代码启动类实体类数据层xml映射文件业务层业务层实现类控制层接口配置swagger请求体 2 可能出现的疑问或者问题2.1 关于total属性疑问2.2 分页不生效问题 3 案例说明3.…

Dynamic Web TWAIN Crack

Dynamic Web TWAIN Crack 文件编辑 提供 GUI 和非 GUI 图像编辑器 内置基本图像编辑界面&#xff0c;如旋转、裁剪、镜像、翻转、擦除和更改图像大小 支持向图像添加彩色矩形 支持文字注释 提供图像交换功能 支持清除图像的指定区域并用颜色填充清除的区域 内置变焦 提供多图像…

VUE3组件

组件基础 {#components-basics} 组件允许我们将 UI 划分为独立的、可重用的部分&#xff0c;并且可以对每个部分进行单独的思考。在实际应用中&#xff0c;组件常常被组织成层层嵌套的树状结构&#xff1a; 这和我们嵌套 HTML 元素的方式类似&#xff0c;Vue 实现了自己的组件…

pyscenic分析:视频教程

我们之前更新过pyscenic的教程&#xff1a;pySCENIC单细胞转录因子分析更新&#xff1a;数据库、软件更新。我们也说过&#xff0c;我们号是放弃R语言版的SCENIC的分析了&#xff0c;因为它比较耗费计算资源和时间&#xff0c;所以我们的单细胞转录因子分析教程都是基于pysceni…

JavaScript算法【入门】

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于海外某世界知名高校就读计算机相关专业。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。…

openocd调试esp32(通过FT232H)

之前在学习ESP32&#xff0c;其中有一部分课程是学习openocd通过JTAG调试程序的&#xff0c;因为我用的是ESP32-wroom&#xff0c;usb端口没有集成对应的usb转jtag的ft232&#xff0c;查了ESP32相关的资料&#xff08;JTAG 调试 - ESP32 - — ESP-IDF 编程指南 latest 文档 (es…

React如何配置env环境变量

React版本&#xff1a; "react": "^18.2.0" 1、在package.json平级目录下创建.env文件 2、在‘.env’文件里配置环境变量 【1】PUBLIC_URL 描述&#xff1a;编译时文件的base-href 官方描述&#xff1a; // We use PUBLIC_URL environment variable …

使用 PyTorch 逐步检测单个对象

一、说明 在对象检测任务中&#xff0c;我们希望找到图像中对象的位置。我们可以搜索一种类型的对象&#xff08;单对象检测&#xff0c;如本教程所示&#xff09;或多个对象&#xff08;多对象检测&#xff09;。通常&#xff0c;我们使用边界框定义对象的位置。有几种方法可以…

netty基础与原理

Netty线程模型和Reactor模式 简介&#xff1a;reactor模式 和 Netty线程模型 设计模式——Reactor模式&#xff08;反应器设计模式&#xff09;&#xff0c;是一种基于 事件驱动的设计模式&#xff0c;在事件驱动的应用中&#xff0c;将一个或多个客户的 服务请求分离&#x…

windows任务栏右下角不显示网络图标解决方法

1、背景 我运行windows诊断服务之后&#xff0c;然后重启了一把电脑&#xff0c;结果发现电脑无法上网了&#xff0c;进一步发现任务栏右下角的网络显示图标也没有了&#xff0c;网络状态显示也是一条横线。 几经折腾终于给解决了&#xff0c;遇到了不少坑&#xff0c;记录一…

三、web核心防御机制(下)

文章目录 核心防御机制2.3处理攻击者2.3.1 处理错误2.3.2 维护审计日志2.3.3 向管理员发出警报2.3.4 应对攻击 2.4 管理应用程序 核心防御机制 2.3处理攻击者 任何设计安全应用程序的开发人员必须基于这样一个假设&#xff1a;应用程序将成为蓄意破坏且经验丰富的攻击者的直接…

双端口存储器原理实验

1.实验目的及要求 1.1实验目的 1&#xff09;了解双端口静态随机存储器IDT7132的工作特性及使用方法。 2&#xff09;了解半导体存储器怎样存储和读出数据。 3&#xff09;了解双端口存储器怎样并行读写&#xff0c;并分析冲突产生的情况。 1.2实验要求 1&#xff09;做好…

Oracle连接数据库提示 ORA-12638:身份证明检索失败

ORA-12638 是一个 Oracle 数据库的错误代码&#xff0c;它表示身份验证&#xff08;认证&#xff09;检索失败。这通常与数据库连接相关&#xff0c;可能由于以下几个原因之一引起&#xff1a; 错误的用户名或密码&#xff1a; 提供的数据库用户名或密码不正确&#xff0c;导致…

[HDLBits] Exams/2012 q1g

Consider the function f shown in the Karnaugh map below. Implement this function. (The original exam question asked for simplified SOP and POS forms of the function.) //

Three.js 设置模型材质纹理贴图和修改材质颜色,材质透明度,材质网格

相关API的使用&#xff1a; 1 traverse &#xff08;模型循环遍历方法&#xff09; 2. THREE.TextureLoader&#xff08;用于加载和处理图片纹理&#xff09; 3. THREE.MeshLambertMaterial&#xff08;用于创建材质&#xff09; 4. getObjectByProperty&#xff08;通过材…

交换排序——选择排序和冒泡排序的区别是什么?

今天重温一下算法&#xff0c;其实刚开始我觉得冒泡排序和选择排序是一样的&#xff0c;因为他们排序过程中都是通过相邻的数据比较找到最小/最大的数据&#xff0c;通过不断思考和学习才明白&#xff0c;两者还是有区别的。 冒泡排序 概念 冒泡排序(Bubble Sort)&#xff0…

Django实现音乐网站 ⑽

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是后台对歌曲类型、歌单功能原有功能进行部分功能实现和显示优化。 目录 歌曲类型功能优化 新增编辑 优化输入项标题显示 父类型显示改为下拉菜单 列表显示 父类型显示名称 过滤器增加父类型 歌单表功能优化…

OpenStack监控工具

OpenStack是一个开源的云计算管理平台项目&#xff0c;是一系列软件开源项目的组合。由NASA和Rackspace合作研发并发起&#xff0c;以Apache许可证&#xff08;Apache软件基金会发布的一个自由软件许可证&#xff09;授权。 OpenStack为私有云和公有云提供可扩展的弹性的云计算…