基于opencv的手势识别

2023-11-16

大家好,我是一名本科生,我的主要学习方向是计算机视觉以及人工智能。按照目前的学习进度来说,我就是一小白,在这里写下自己编写的程序,与大家分享,记录一下自己的成长。
在这里插入图片描述

今天与大家分享的是基于OpenCv的手势识别。

思路分析

获取图片,在图片中找到手,然后进行一系列的闭运算,降噪平滑处理,轮廓查找,凸缺陷检测。(如果你不太理解这些操作,别着急在下面的源码中我会尝试着解释)
然后根据凸包缺陷的个数来判断手指的个数。

遇到的困难

在上述的过程借助opencv库很容易就可以实现,但实现的过程中令人头疼的地方。

在图像中找出手部是很麻烦的,一开始按照书上的方法是将读入的图片由BGR转换为HSV模式,由HSV来确定手的肤色范围,将手从图像中分离出来,代码如下:

//设置肤色范围,该范围的数值是百度出来的人体肤色范围
lower_skin = np.array([0,28,70],dtype = np.uint8)
upper_skin = np.array([20,255,255],dtype = np.uint8)
//根据肤色范围进行手的查找,
//cv2.inRange函数会将图像内不在该范围区域设置为黑色
mask = cv2.inRange(img_hsv,lower_skin,upper_skin)
//但是该方法的效果不理想,找出的手部不准确

我又在网上查找一番,找到了比HSV好的方法:椭圆肤色检测

//这里我写成了一个类
class check_skin():
    def __init__(self):
        // 创建椭圆模型
        self.ellipse_mode = np.zeros((256, 256), dtype=np.uint8)
        /// 在图像上绘制白色椭圆
        cv2.ellipse(self.ellipse_mode, (113, 155), (23, 15), 43, 0, 360, (255, 255, 255), -1)
    def check_finger(self,path):
        img = cv2.imread(path, cv2.IMREAD_COLOR)
        // 图像皮肤掩膜创建
        skin_mask = np.zeros(img.shape[:2], dtype=np.uint8)
        // 将图像转换为YCBCR
        img_ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                cr = img_ycrcb[i, j][1]
                cb = img_ycrcb[i, j][2]
                if self.ellipse_mode[cr, cb] > 0:
                    skin_mask[i, j] = 255
        img = cv2.bitwise_and(img,img,mask = skin_mask)
        return img

这个方法要比HSV检测出来的手部效果好的多,效果图就不展示了,有兴趣的可以自己实验一下。
更多的肤色检测方法:请点击这里

手部识别的问题解决后,我来讲一下手势识别的过程
首先,了解一下凸包与凸缺陷

红色为凸包,蓝色点为凸缺陷的最深点(即边缘点到凸包距离最大点),绿色是轮廓。红色与绿色之间的区域即为凸缺陷。在这里插入图片描述
接着我们使用函数:cv2.convexityDefects,convexityDefects:输出参数,检测到的最终结果,返回一个数组,其中每一行包含的值是[起点,终点,最远的点,到最远点的近似距离]。前三个点都是轮廓索引。前三个值得含义分别为:凸缺陷的起始点,凸缺陷的终点,凸缺陷的最深点(即边缘点到凸包距离最大点)
就是上图的蓝色小点,然后根据convexityDefects返回数组的每一行的前三个值,构成的三角形由于人手指伸开的时候所构成的三角形角度总是小于90度,来去除不属于手指的凸缺陷,然后统计小于90度的凸缺陷个数再加1就是手指的个数。
在伸出的手指的个数为一和零的时候统计凸缺陷是不可行的,如图:
在这里插入图片描述
在这里插入图片描述
这时候应该统计轮廓以及凸包的面积,设置比例关系来判断手指为1和0的情况。

代码

import numpy as np
import cv2
import time
import math
#将肤色检测的椭圆模型设计为类
class check_skin():
    def __init__(self):
        # 创建椭圆模型
        self.ellipse_mode = np.zeros((256, 256), dtype=np.uint8)
        # 在图像上绘制白色椭圆
        cv2.ellipse(self.ellipse_mode, (113, 155), (23, 15), 43, 0, 360, (255, 255, 255), -1)
    def check_finger(self,path):
        img = cv2.imread(path, cv2.IMREAD_COLOR)
        # 图像皮肤掩膜创建
        skin_mask = np.zeros(img.shape[:2], dtype=np.uint8)
        # 将图像转换为YCBCR
        img_ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                cr = img_ycrcb[i, j][1]
                cb = img_ycrcb[i, j][2]
                if self.ellipse_mode[cr, cb] > 0:
                    skin_mask[i, j] = 255
        img = cv2.bitwise_and(img,img,mask = skin_mask)
        return img
 #将类初始化为对象
check_finger = check_skin()
#这个列表储存图片名称
img_path = ['zero','one','two','three','four','five']

for path in img_path:
	#图片地址合成以及椭圆模型检测
    finger_img = check_finger.check_finger(path+'.JPG')

    #转换为灰度图像
    finger_img_gray = cv2.cvtColor(finger_img,cv2.COLOR_BGR2GRAY)
    #阈值函数转化为二值图像
    _,finger_img_binary = cv2.threshold(finger_img_gray,50,255,cv2.THRESH_BINARY)
    #进行闭运算
    kernel = np.ones((4,4),dtype = np.uint8)
    finger_img_binary = cv2.morphologyEx(finger_img_binary,cv2.MORPH_CLOSE,kernel,iterations = 2)
    #高斯滤波进行去噪平滑
    finger_img_binary = cv2.GaussianBlur(finger_img_binary,(3,3),50)
    #轮廓查找
    contours, hierarchy = cv2.findContours(finger_img_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    area_cont = cv2.contourArea(contours[0])
    #凸缺陷检测
    hull1 = cv2.convexHull(contours[0])
    area_hull = cv2.contourArea(hull1)
    #根据轮廓面积和轮廓凸包面积的比例来确定zero和one
    percentage = (area_hull-area_cont)/area_cont
    print(percentage)
    hull = cv2.convexHull(contours[0], returnPoints=False)
    convex = cv2.convexityDefects(contours[0],hull)
    #用来统计小于90的角的个数
    count = 0
    for i in range(convex.shape[0]):
        s,e,f,d = convex[i][0]
        start = contours[0][s][0]
        end = contours[0][e][0]
        far = contours[0][f][0]
        #计算三角形的三边的长度
        a = math.sqrt((start[0]-far[0])**2+(start[1]-far[1])**2)
        b = math.sqrt((end[0]-far[0])**2+(end[1]-far[1])**2)
        c = math.sqrt((start[0]-end[0])**2+(start[1]-end[1])**2)
        #计算角度
        angle = math.acos((a**2+b**2-c**2)/(2*a*b))*57
        #画出角度
        cv2.line(finger_img,start,far,(0,255,0),2)
        cv2.line(finger_img,end,far,(0,255,0),2)
        # #在角上放上角的度数
        # cv2.putText(finger_img,str(angle),far,cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),1)
        #判断角度小于九十度的角的个数
        if angle<90:
            count += 1
    if count == 0 :
        if percentage < 0.2 :
            cv2.putText(finger_img,str(count),(50,20),cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),1)
        else:
            cv2.putText(finger_img, str(count+1), (50,20), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 1)
    else:
        cv2.putText(finger_img, str(count+1), (50,20), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 1)

    cv2.imshow(path,finger_img)
    cv2.waitKey(0)

cv2.destroyAllWindows()

结尾

后来在网上无意间发现了mediapipe这个手势检测库,然后我使用这个库重新又写了一个手势识别的程序,如果大家想要了解,请看我的下一个文章。

最后,创作不易,请各位支持一下。我也是小白一名,欢迎大家的指导,交流。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于opencv的手势识别 的相关文章

  • 查找彼此接近的对象边界

    我正在研究一个计算机视觉问题 其中问题的第一步是找到物体彼此靠近的位置 例如 在下图中 我感兴趣的是找到灰色标记的区域 Input Output 我目前的方法是首先反转图像 然后通过侵蚀进行形态梯度跟随 然后删除一些不感兴趣的轮廓 脚本如下
  • Opencv未找到所有轮廓

    我试图找到该图像的轮廓 但是该方法查找轮廓只返回1轮廓 轮廓突出显示image 2 我正在努力寻找all外部轮廓就像这些圆圈 里面有数字 我究竟做错了什么 我可以做什么来实现它 image 1 image 2 以下是我的代码的相关部分 th
  • 使用 opencv warpPerspective() 生成道路的自上而下视图

    我正在尝试实施逆透视映射计算与道路上另一辆车的距离 我知道在应用该函数之前我需要生成一个包含源点和目标点的变换矩阵warpPerspective 但我不知道如何计算目的地点 我在这个论坛和其他网站中搜索 但无法将第一张图片转换为第二张图片
  • 如何在给定目标大小的情况下在 python 中调整图像大小,同时保留纵横比?

    首先 我觉得这是一个愚蠢的问题 对此感到抱歉 目前 我发现计算最佳缩放因子 目标像素数的最佳宽度和高度 同时保留纵横比 的最准确方法是迭代并选择最佳缩放因子 但是必须有更好的方法来做到这一点 一个例子 import cv2 numpy as
  • OpenCV的拼接模块可以拼接平行运动相机拍摄的图像吗?

    我想知道是否缝合 http docs opencv org modules stitching doc stitching html http docs opencv org modules stitching doc stitching
  • OpenCV 错误:使用 COLOR_BGR2GRAY 函数时断言失败

    我在使用 opencv 时遇到了一个奇怪的问题 我在 jupyter 笔记本中工作时没有任何问题 但在尝试运行此 Sublime 时却出现问题 错误是 OpenCV错误 cvtColor中断言失败 深度 CV 8U 深度 CV 16U 深度
  • 我可以使用 openCV 比较两张不同图像上的两张脸吗?

    我对 openCV 很陌生 我看到它可以计算出脸部并返回一个矩形来指示脸部 我想知道 openCV 是否可以访问两张包含一张脸的图像 并且我希望 openCV 返回这两个人是否相同的可能性 Thanks OpenCV 不提供完整的人脸识别引
  • 如何将 mat 转换为 array2d

    我为dlib http dlib net face landmark detection ex cpp html那里的面部地标代码使用 array2d 来获取图像 但我喜欢使用 Mat 读取图像并转换为 array2d 因为 dlib 仅支
  • 曲线/路径骨架二值图像处理

    我正在尝试开发一个可以处理图像骨架的路径 曲线的代码 我想要一个来自两点之间骨架的点向量 该代码在添加一些点后结束 我没有找到解决方案 include opencv2 highgui highgui hpp include opencv2
  • OpenCV 仅围绕大轮廓绘制矩形?

    第一次发帖 希望我以正确的方式放置代码 我正在尝试检测和计算视频中的车辆 因此 如果您查看下面的代码 我会在阈值处理和膨胀后找到图像的轮廓 然后我使用 drawContours 和矩形在检测到的轮廓周围绘制一个框 我试图在 drawCont
  • BASH 脚本编译多个 C++ 文件 - OpenCV

    请参见在C 和OpenCV中调用其他文件中的函数 https stackoverflow com questions 24442836 call functions in other files in c and opencv 对于最初的问
  • 指纹奇异点检测

    我正在尝试确定指纹的核心点和增量点 我正在使用庞加莱指数方法 但我无法成功检测到这一点 而且我不明白为什么 First I divide the image in 15x15 blocks then I calculate the x an
  • 创建 OpenCV 的 mouseCallback 函数的基于类的实现时遇到问题

    正如标题所示 我在基于类的 C 结构中实现 OpenCV 的 mouseCallback 函数时遇到了一些麻烦 请允许我解释一下 我定义了一个名为 BriskMatching 的类 在其中创建了一个名为 mouseCallback 的成员函
  • 从图像坐标获取对象的世界坐标

    I have been following this http docs opencv org modules calib3d doc camera calibration and 3d reconstruction html docume
  • OpenCV IP 相机应用程序崩溃 [h264 @ 0xxxxx] 访问单元中缺少图片

    我在 cpp 中有一个 opencv 应用程序 它使用 opencv 的简单结构捕获视频流并将其保存到视频文件中 它与我的网络摄像头完美配合 但是 当我运行它从 IP 摄像机捕获流时 它可能会在大约十秒后崩溃 我的编译命令是 g O3 IP
  • 2d 图像点和 3d 网格之间的交点

    Given 网格 源相机 我有内在和外在参数 图像坐标 2d Output 3D 点 是从相机中心发出的光线穿过图像平面上的 2d 点与网格的交点 我试图找到网格上的 3d 点 This is the process From Multip
  • opencv人脸检测示例

    当我在设备上运行应用程序时 应用程序崩溃并显示以下按摩 java lang UnsatisfiedLinkError 无法加载 detector based tracker findLibrary 返回 null 我正在使用 OpenCV
  • cv2.drawContours() - 取消填充字符内的圆圈(Python,OpenCV)

    根据 Silencer的建议 我使用了他发布的代码here https stackoverflow com questions 48244328 copy shape to blank canvas opencv python 482465
  • 在 Visual Studio 2012 中安装 OpenCV

    我正在尝试安装 OpenCV 来与 Visual Studio 一起使用 我使用的是2012Pro版本 但我认为它应该与vs10相同 我正在关注这个教程 http docs opencv org doc tutorials introduc
  • YOLOv8获取预测边界框

    我想将 OpenCV 与 YOLOv8 集成ultralytics 所以我想从模型预测中获取边界框坐标 我该怎么做呢 from ultralytics import YOLO import cv2 model YOLO yolov8n pt

随机推荐

  • web常见的攻击方式有哪些,以及如何进行防御?

    一 是什么 Web攻击 WebAttack 是针对用户上网行为或网站服务器等设备进行攻击的行为 如植入恶意代码 修改网站权限 获取网站用户隐私信息等等 Web应用程序的安全性是任何基于Web业务的重要组成部分 确保Web应用程序安全十分重要
  • react组件中设置多个className

    错误写法
  • c++下的文件批量读写——查找文件的类 struct _finddata_t结构体用法

    查找文件的类 struct finddata t结构体用法 https blog csdn net yang332233 article details 53081785 但是运行原链接的代码时在while findnext handle
  • Android APP的安装路径

    小Tips app安装在哪个路径 2021 6 10更新 1 安装路径共五个 system app 系统自带的应用程序 无法删除 root后可以删除 system priv app 比system app 中的应用权限更加高 如Launch
  • DC/DC和LDO的区别是什么?以及如何选择?

    LDO是线性电源 DC DC是开关电源 SMPS 是两种不同种类电源 工作原理也不相同 开关电源和线性电源的区别 开关电源 SMPS 和低压差线性稳压电源 LDO 从模型理解原理 电源技术与新能源 面包板社区 LDO DC DC如何选型 L
  • DB2约束

    清单 1 查询数据库目录以判断哪些数据库列可为空 db2 select tabname colname nulls from syscat columns where tabschema MELNYK and nulls N 仅单独存在 惟
  • 告别BeanUtils,Mapstruct从入门到精通

    如果你现在还在使用BeanUtils 看了本文 也会像我一样 从此改用Mapstruct 对象之间的属性拷贝 之前用的是Spring的BeanUtils 有一次 在学习领域驱动设计的时候 看了一位大佬的文章 他在文章中提到使用Mapstru
  • LSB(Least Significant Bit)和MSB(Most Significant Bit)

    LSB Least Significant Bit 意为最低有效位 MSB Most Significant Bit 意为最高有效位 若MSB 1 则表示数据为负值 若MSB 0 则表示数据为正 MSB高位前导 LSB低位前导 谈到字节序的
  • MVC架构

    10 MVC 什么是MVC Model view Controller 模型视图控制器 10 1 以前的架构 用户可以直接访问控制层 控制层可以直接操作数据库 Servlet gt CURD gt 数据库 弊端 程序十分臃肿 不利于维护 S
  • hiveSql 重分组聚合问题

    hiveSql 重分组聚合问题 问题 分析 实现 最后 问题 将下图中A表转变为B和C 即A gt B A gt C 分析 1 首先看A gt B 可见是将name列分组 取最大组内最大id 介绍两种求解方式 1 很容易想到 开窗函数fir
  • html使用iframe包含pdf文件,HTML embedded PDF iframe

    It s downloaded probably because there is not Adobe Reader plug in installed In this case IE it doesn t matter which ver
  • 【数据架构系列-06】一文搞懂数据模型的3种类型——概念模型、逻辑模型、物理模型

    数据模型就是模拟现实世界的方法论 是通向智慧世界的基石 从现实世界发展到智慧世界 要数经历现实世界 信息世界 计算机世界 数据世界 智慧世界五个不同的世界 我们天生具有从混沌的世界抽象信息变为信息世界的能力 但是到另外几个世界需要我们懂得计
  • spring的自动装配即装配的各种模式

    Spring的自动装配 无须在Spring配置文件中描述javabean之间的依赖关系 IOC容器会自动建立JavaBean之间的关联关系 根据属性名称自动装配autowire byName 根据数据类型自动装配autowire byTyp
  • 完整安装datax-web教程

    1 安装mysql5 7 a 创建目录下载安装rpm包 mkdir p opt software cd opt software wget i c http dev mysql com get mysql57 community relea
  • 【c++复习笔记】——智能指针详细解析(智能指针的使用,原理分析)

    个人主页 努力学习的少年 版权 本文由 努力学习的少年 原创 在CSDN首发 需要转载请联系博主 如果文章对你有帮助 欢迎关注 点赞 收藏 一键三连 和订阅专栏哦 目录 一 智能指针的基本概念 二 智能指针的定义和使用 三 auto ptr
  • Pytorch-Lightning基本方法介绍

    文章目录 LIGHTNINGMODULE Minimal Example 一些基本方法 Training Training loop Validation loop Test loop Inference Inference in rese
  • Qt之再谈阴影边框

    前面就窗口阴影已经写过一篇博客 使用九宫格的思路实现的 在我看来 凡是用程序能实现的尽量不要使用图片代替 在保证效率的前提下 今天再次分享关于我的一些小见解 先看效果 窗口阴影任意调节 包括阴影像素 是否圆角等 直接上代码 void Dro
  • linux如何查看入口地址,宝塔Linux面板安全入口地址忘了(方法一)

    宝塔Linux面板安全入口地址忘了 方法一 面板 地址 入口 宝塔 所示 宝塔Linux面板安全入口地址忘了 方法一 易采站长站 站长之家为您整理了宝塔Linux面板安全入口地址忘了 方法一 的相关内容 现在新安装的宝塔 Linux 面板时
  • win10-未知的USB设备-解决自己问题的记录

    若是没有解决你的问题 再找找其他办法看看 我也是网上搜的 刚好解决了我的问题我就记录了一下而已 哈哈哈 原文链接 修复 未知的USB设备 设备描述符请求失败 在Windows 10中 1 设备管理器 gt 通用串行总线控制器 gt 未知US
  • 基于opencv的手势识别

    大家好 我是一名本科生 我的主要学习方向是计算机视觉以及人工智能 按照目前的学习进度来说 我就是一小白 在这里写下自己编写的程序 与大家分享 记录一下自己的成长 今天与大家分享的是基于OpenCv的手势识别 思路分析 获取图片 在图片中找到