基于OpenCV的手势1~5识别系统(源码&环境部署)

1.研究背景与意义

项目参考AAAI Association for the Advancement of Artificial Intelligence

研究背景与意义:

随着计算机视觉技术的快速发展,手势识别系统在人机交互、虚拟现实、智能监控等领域得到了广泛应用。手势识别系统可以通过分析人体的手势动作,实现与计算机的自然交互,提高用户体验和操作效率。基于OpenCV的手势1~5识别系统是一种利用计算机视觉技术,通过摄像头捕捉用户手势动作并识别其代表的数字,从而实现手势数字输入的系统。

手势识别技术的应用非常广泛。在人机交互方面,手势识别系统可以替代传统的鼠标和键盘输入方式,使用户能够通过手势来操作计算机,提高交互的自然性和便捷性。在虚拟现实领域,手势识别系统可以实现用户在虚拟环境中的自由移动和操作,增强虚拟现实的沉浸感和真实感。在智能监控方面,手势识别系统可以用于识别特定的手势动作,例如手势警报系统可以通过识别求救手势来及时报警,提高安全性和应急响应能力。

目前,基于OpenCV的手势识别系统已经取得了一定的研究进展。OpenCV是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法,可以用于实现手势识别系统的各个环节,包括图像采集、预处理、特征提取和分类识别等。基于OpenCV的手势1~5识别系统是一种基于机器学习算法的手势识别系统,通过训练模型来识别手势动作所代表的数字。

然而,目前基于OpenCV的手势识别系统还存在一些挑战和问题。首先,手势识别系统需要准确地捕捉和识别用户的手势动作,但是手势动作的多样性和复杂性给图像采集和处理带来了挑战。其次,手势识别系统需要具备实时性和稳定性,能够在不同的环境和光照条件下进行准确的识别。最后,手势识别系统需要具备较高的准确率和鲁棒性,能够识别不同人的手势动作,并且对于噪声和干扰具有一定的容错能力。

因此,基于OpenCV的手势1~5识别系统的研究具有重要的意义。首先,该系统可以提供一种新的人机交互方式,改善用户体验和操作效率。其次,该系统可以应用于虚拟现实领域,提高虚拟现实的沉浸感和真实感。最后,该系统可以应用于智能监控领域,提高安全性和应急响应能力。

在研究过程中,需要解决以下几个关键问题:首先,如何准确地捕捉和识别手势动作,提高图像采集和处理的效果。其次,如何提高系统的实时性和稳定性,适应不同的环境和光照条件。最后,如何提高系统的准确率和鲁棒性,识别不同人的手势动作,并具备一定的容错能力。

总之,基于OpenCV的手势1~5识别系统是一种利用计算机视觉技术实现手势数字输入的系统,具有广泛的应用前景和重要的研究意义。通过解决关键问题,可以提高手势识别系统的准确性、实时性和稳定性,推动手势识别技术在人机交互、虚拟现实和智能监控等领域的应用。

2.图片演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.视频演示

基于OpenCV的手势1~5识别系统(源码&环境部署)_哔哩哔哩_bilibili

4.手势

手势的概述

手势是指人类用语言中枢建立起来的一套用手掌和手指位置、形状的特定语言系统。手势包括单幅图片的静态手势和连续的动态手势。前者是指人手的一个简单动作,即单个手形;后者是指人手与手臂组合产生一系列的动作l36]。简单地说,在手势相关的模型参数空间中,动态手势是由一连串连续的静态手势组成的运动轨迹,而其中每个静态手势可以看成一个独立的点,如果给它们分别定义一个特定的含义,那么,就成为了某种语言体系。换而言之,我们常说的静态手势是一种空间特性,而动态手势包含了时、空两种特性。手势的含义就是通过分析空间模型中点与轨迹的含义得到的。

手势的输入方式

(1)数据手套
数据手套就是一种传感器系统,可以把人的动作变为信号,并编程输入到计算机,计算机分析这些信号后,得到手势的动作信息。它同时是虚拟现实系统的一个媒介设备。数据手套的样式也很多,从复杂程度上来说,可以分为简单的数据手套和复杂的数据手套,前者可能只有几个传感器来测量手的变化,而后者会有较多的传感器来测量手的姿势变化。
通过使用数据手套,系统可以有效的得到手势的大量数据信息来识别多种手势,并且可以准确的获取手的三维运动信息。但是她也有许多缺点,如每次使用都要进行数据手套的穿戴,带来很多麻烦,而且一般数据手套的价格偏高,这样使它很难推广。
(2)基于计算机视觉
基于计算机视觉的手势识别方法是使用摄像头获取手的运动过程,从获取的视频图像中获取关键帧,并提取手势,然后对手势图像进行特征检测和参数估计,最后根据模型参数对手势进行识别,获得当前手势信息。这种方法的优点是对用户限制较少,但是需要处理的数据量大,而且处理方法相对复杂,准确率相对较低,且依赖各环节的处理方法。

基于计算机视觉的手势识别系统组成

基于计算机视觉的手势识别是通过摄像头获取手势信息,通过建立手势映射模型来识别手势信息,从而使得交互的任务更加具体化。
一个基于视觉的手势识别系统一般有以下几部分构成:
在这里插入图片描述

首先通过一个或多个摄像头获取视频数据流,接着系统根据手势输入的交互模型检测获取的数据流里判断是否有手势出现,要是有的话,就需要从视频信号中将这个手势分离出来。进而选择出手势模型对手势进行分析,分析过程中主要有特征检测和模型参数估计两个部分。在识别阶段,分类手势的时候要依据模型的参数,而且满足不同的需求,从而得到手势描述,最后系统按照得出的描述驱动,实现具体的应用。
手势的建模主要是通过一定的算法在所捕获的图像中确定手的位置,能够快速的定位,使得后续的工作可以及时的进行。目前有通过肤色模型的算法,而且也出现了通过Haar-like特征以及基于Adaboost算法的人脸检测等方法。在一定的程度下,这些算法都具有相当好的鲁棒性。
手势的分析通常是在确定好手势区域的基础上,然后利用几何算法,将比较明显的特征提取出来,比如手指,或者手指的顶点处。从而,在系统中就可以将相对的坐标分辨出来,从而为后面的交互提供了基础。

5.核心代码讲解

5.1 gesture.py

封装为类的代码如下:

class HandGestureRecognition:def __init__(self):self.cap = cv2.VideoCapture(0)def run(self):while(self.cap.isOpened()):ret, img = self.cap.read()cv2.rectangle(img,(300,300),(100,100),(0,255,0),0)crop_img = img[100:300, 100:300]grey = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY)value = (35, 35)blurred = cv2.GaussianBlur(grey, value, 0)_, thresh1 = cv2.threshold(blurred, 127, 255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)cv2.imshow('Thresholded', thresh1)contours, hierarchy = cv2.findContours(thresh1.copy(),cv2.RETR_TREE, \cv2.CHAIN_APPROX_NONE)max_area = -1for i in range(len(contours)):cnt=contours[i]area = cv2.contourArea(cnt)if(area>max_area):max_area=areaci=icnt=contours[ci]x,y,w,h = cv2.boundingRect(cnt)cv2.rectangle(crop_img,(x,y),(x+w,y+h),(0,0,255),0)hull = cv2.convexHull(cnt)drawing = np.zeros(crop_img.shape,np.uint8)cv2.drawContours(drawing,[cnt],0,(0,255,0),0)cv2.drawContours(drawing,[hull],0,(0,0,255),0)hull = cv2.convexHull(cnt,returnPoints = False)defects = cv2.convexityDefects(cnt,hull)count_defects = 0cv2.drawContours(thresh1, contours, -1, (0,255,0), 3)for i in range(defects.shape[0]):s,e,f,d = defects[i,0]start = tuple(cnt[s][0])end = tuple(cnt[e][0])far = tuple(cnt[f][0])a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2)c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2)angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57if angle <= 90:count_defects += 1cv2.circle(crop_img,far,1,[0,0,255],-1)#dist = cv2.pointPolygonTest(cnt,far,True)cv2.line(crop_img,start,end,[0,255,0],2)#cv2.circle(crop_img,far,5,[0,0,255],-1)......

你可以通过创建一个HandGestureRecognition的实例并调用run方法来运行这段代码。

这个程序文件名为gesture.py,主要功能是通过摄像头捕捉手势图像,并根据手势的形状判断手势的数字。

程序首先导入了需要的库,包括cv2、numpy和math。然后通过cv2.VideoCapture(0)打开摄像头,进入一个循环,不断读取摄像头捕捉到的图像。

在每一帧图像中,程序首先在图像上绘制一个矩形框,用于标记手势区域。然后从图像中裁剪出手势区域,并将其转换为灰度图像。

接下来,程序对灰度图像进行高斯模糊处理,并进行二值化处理,得到一个二值图像。然后通过cv2.findContours函数找到图像中的轮廓。

程序通过计算轮廓的面积,找到最大的轮廓,并将其绘制在裁剪后的图像上。然后通过cv2.convexHull函数找到轮廓的凸包,并将凸包绘制在图像上。

接下来,程序通过cv2.convexityDefects函数找到轮廓的凸缺陷,并计算凸缺陷的个数。根据凸缺陷的个数,判断手势的数字,并在原始图像上绘制相应的文字。

最后,程序将绘制的图像显示出来,并通过cv2.waitKey函数等待用户按下ESC键退出程序。

整个程序的功能是实时捕捉手势图像,并根据手势的形状判断手势的数字。

5.2 test.py

封装为类后的代码如下:

class FaceDB:def __init__(self):self.host = "localhost"       # 主机名self.user = "root"            # 用户名self.passwd = "ltc19981118"   # 密码self.db = "facedb"              # 数据库名称self.port = 3306self.conn = MySQLdb.connect(host=self.host, port=self.port, user=self.user, passwd=self.passwd, db=self.db, charset='utf8')self.cursor = self.conn.cursor()def get_ppt_count(self, table_name):sql = "SELECT ppt FROM " + table_nameself.cursor.execute(sql)return len(self.cursor.fetchall())

在这个类中,我们将原来的全局变量封装为类的属性,并将数据库连接和查询操作封装为类的方法。这样可以更好地组织代码,提高代码的可读性和可维护性。

这个程序文件名为test.py,它的功能是使用PyQt5库创建一个图形用户界面,同时还引入了其他一些必要的库。程序的主要功能是连接到MySQL数据库,执行一个查询语句并打印结果的长度。具体的代码如下:

  1. 导入所需的库:

    • PyQt5.QtCore:PyQt5的核心模块
    • PyQt5.QtWidgets:PyQt5的窗口部件模块
    • PyQt5.QtGui:PyQt5的图形用户界面模块
    • PyQt5:PyQt5的整体模块
    • numpy:用于数值计算的库
    • time:用于时间相关的操作的库
    • MySQLdb:用于连接MySQL数据库的库
    • cv2:用于图像处理的库
    • sys:用于系统相关的操作的库
    • os:用于操作系统相关的操作的库
    • math:用于数学计算的库
  2. 设置全局变量:

    • host:数据库的主机名
    • user:数据库的用户名
    • passwd:数据库的密码
    • db:数据库的名称
    • port:数据库的端口号
  3. 连接到MySQL数据库:

    • 使用MySQLdb.connect()函数连接到数据库,传入相应的参数
    • 创建一个数据库连接对象conn
  4. 执行查询语句:

    • 构建查询语句sql,从表’bingbing’中选择’ppt’列的数据
    • 创建一个游标对象cursor
    • 使用cursor.execute()函数执行查询语句
  5. 打印结果长度:

    • 使用cursor.fetchall()函数获取查询结果的所有行
    • 使用len()函数获取查询结果的长度
    • 使用print()函数打印结果的长度
5.3 ui.py
class GestureRecognitionSystem(QtWidgets.QMainWindow):def __init__(self):super().__init__()self.setupUi(self)def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(1280, 960)MainWindow.setStyleSheet("background-image: url(\"./template/carui.png\")")self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.label = QtWidgets.QLabel(self.centralwidget)self.label.setGeometry(QtCore.QRect(168, 60, 1000, 71))self.label.setAutoFillBackground(False)self.label.setStyleSheet("")self.label.setFrameShadow(QtWidgets.QFrame.Plain)self.label.setAlignment(QtCore.Qt.AlignCenter)self.label.setObjectName("label")self.label.setStyleSheet("font-size:50px;font-weight:bold;font-family:SimHei;background:rgba(255,255,255,0);")self.label_2 = QtWidgets.QLabel(self.centralwidget)self.label_2.setGeometry(QtCore.QRect(40, 200, 550, 501))self.label_2.setStyleSheet("background:rgba(255,255,255,0.4);")self.label_2.setAlignment(QtCore.Qt.AlignCenter)self.label_2.setObjectName("label_2")self.label_3 = QtWidgets.QLabel(self.centralwidget)self.label_3.setGeometry(QtCore.QRect(620, 200, 550, 501))self.label_3.setStyleSheet("background:rgba(255,255,255,0.4);")self.label_3.setAlignment(QtCore.Qt.AlignCenter)self.label_3.setObjectName("label_3")self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)self.textBrowser.setGeometry(QtCore.QRect(73, 746, 851, 174))self.textBrowser.setStyleSheet("background:rgba(255,255,255,0.4);")self.textBrowser.setObjectName("textBrowser")self.pushButton = QtWidgets.QPushButton(self.centralwidget)self.pushButton.setGeometry(QtCore.QRect(1020, 750, 150, 40))self.pushButton.setStyleSheet("background:rgba(53,142,255,1);border-radius:10px;padding:2px 4px;")self.pushButton.setObjectName("pushButton")self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_3.setGeometry(QtCore.QRect(1020, 800, 150, 40))self.pushButton_3.setStyleSheet("background:rgba(53,142,255,1);border-radius:10px;padding:2px 4px;")self.pushButton_3.setObjectName("pushButton_3")self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_2.setGeometry(QtCore.QRect(1020, 850, 150, 40))self.pushButton_2.setStyleSheet("background:rgba(53,142,255,1);border-radius:10px;padding:2px 4px;")self.pushButton_2.setObjectName("pushButton_2")self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_4.setGeometry(QtCore.QRect(1020, 900, 150, 40))self.pushButton_4.setStyleSheet("background:rgba(53,142,255,1);border-radius:10px;padding:2px 4px;")self.pushButton_4.setObjectName("pushButton_4")MainWindow.setCentralWidget(self.centralwidget)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "手势识别系统"))self.label.setText(_translate("MainWindow", "手势识别系统"))self.label_2.setText(_translate("MainWindow", "请添加对象,注意路径不要存在中文"))self.pushButton.setText(_translate("MainWindow", "选择文件"))self.pushButton_3.setText(_translate("MainWindow", "文件检测"))self.pushButton_2.setText(_translate("MainWindow", "实时检测"))self.pushButton_4.setText(_translate("MainWindow", "退出系统"))# 点击文本框绑定槽事件self.pushButton.clicked.connect(self.openfile)self.pushButton_3.clicked.connect(self.det)self.pushButton_2.clicked.connect(self.det2)self.pushButton_4.clicked.connect(self.handleCalc4)def det2(self):cap = cv2.VideoCapture(0)while True:_, frame = cap.read()if frame is None:breakimg = frameimg0 = framecrop_img = imggrey = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY)value = (35, 35)blurred = cv2.GaussianBlur(grey, value, 0)_, thresh1 = cv2.threshold(blurred, 20, 255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)self.showimg2(thresh1)contours, hierarchy = cv2.findContours(thresh1.copy(), cv2.RETR_TREE, \cv2.CHAIN_APPROX_NONE)max_area = -1for i in range(len(contours)):cnt = contours[i]area = cv2.contourArea(cnt)if (area > max_area):max_area = areaci = icnt = contours[ci]x, y, w, h = cv2.boundingRect(cnt)cv2.rectangle(crop_img, (x, y), (x + w, y + h), (0, 0, 255), 0)xx = (x + w * 0.5) / wyy = (y + h * 0.5) / hhull = cv2.convexHull(cnt)drawing = np.zeros(crop_img.shape, np.uint8)cv2.drawContours(drawing, [cnt], 0, (0, 255, 0), 0)cv2.drawContours(drawing, [hull], 0, (0, 0, 255), 0)......

这是一个使用PyQt5库创建的用户界面程序。程序文件名为ui.py。该程序创建了一个主窗口,窗口大小为1280x960像素,并设置了背景图片。主窗口中包含了几个标签、按钮和文本框等控件,用于显示图像和文字信息。程序还定义了一些函数,用于处理按钮点击事件和图像处理等功能。其中,det2函数实现了实时手势检测功能,openfile函数实现了选择文件功能,handleCalc4函数实现了退出系统功能,printf函数用于在文本框中显示文字信息,showimg函数用于显示图像。

6.系统整体结构

整体功能和构架概述:

这个工程是一个基于OpenCV的手势识别系统,主要包括三个程序文件:gesture.py、test.py和ui.py。

gesture.py文件负责实时捕捉手势图像,并根据手势的形状判断手势的数字。

test.py文件连接到MySQL数据库,执行一个查询语句并打印结果的长度。

ui.py文件创建了一个图形用户界面,包含了标签、按钮和文本框等控件,用于显示图像和文字信息,并实现了一些功能,如手势检测、选择文件和退出系统。

下表整理了每个文件的功能:

文件名功能
gesture.py实时捕捉手势图像,判断手势的数字
test.py连接到MySQL数据库,执行查询语句并打印结果的长度
ui.py创建图形用户界面,显示图像和文字信息,实现手势检测、选择文件和退出系统功能

7.手势图像的预处理

手势图像预处理是消除图像中无关的信息、增强可用信息的可检测性和最大限度地简化数据,以此来简化对手势图像进行特征分割、特征提取和配准。

手势图像预处理概述

当手势转变为数字图像信息的时候,转变过程中因受到外界影响,手势图像会因噪声而在不同程度上出现畸变。图像预处理的目的是用来消除或减少待匹配图像之间的灰度偏差和几何变化,使图像处理过程顺利进行。

手势图像预处理方法

图像预处理的一个重要任务就是去除噪声的同时尽可能地保留图像的边缘和细节。为了更好地对手势区域进行识别,需要对采集得到的图像进行一些处理,使得分割出来的手势区域更加完整。

图像滤波

(1)均值滤波
均值滤波是典型的线性滤波算法,采用的主要方法为邻域平均法。它是指使用一个模板在图像上移动,用该模板中的全体像素的平均值来代替原来像素值。
假设一幅图片f(x, y),对它使用二维模板W进行均值滤波,则输出图像如式所示。
在这里插入图片描述

式中,g(x,y)为输出图像,m为该模板中包含当前像素在内的像素总个数。
均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在去噪时图像的细节部分被破坏了,会得到模糊的图像,消除噪声点的效果不是很好。
(2)中值滤波
中值滤波法是一种非线性平滑技术,在一个窗内的所有像素点进行排序,得到的中间值作为当前像素点的像素值。能够有效抑制噪声,消除单个的噪声点。
假设一幅图片fxy),对它使用二维模板W进行中值滤波,则输出图像如式所示。
在这里插入图片描述

中值滤波法可以有效地消除椒盐噪声。
(3)高斯滤波
高斯滤波又称高斯模糊,高斯滤波后图像被平滑的程度取决于标准差。它的输出是领域像素的加权平均,同时离中心越近的像素权重越高。因此,相对于均值滤波,它的平滑效果更柔和,而且边缘保留的也更好。
在这里插入图片描述

二值化

图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。
设原始图像为f(x,y),按照一定的准则在f(x,y)中找到特征值T,将图像分割为两部分,得到二值图像g(x,y)如下式:

其中,T为阈值,bo、b分别分割后的图像两个像素值。若取: b。=0(黑),b= 1(白),即为0-1二值图像。
OpenCV中的函数接口为: void cvThreshold( …)。
使用cvThreshold(dst,dst,130,255,Cv_THRESH_BINARY_INV)对图(a)分割得到图(b)。
在这里插入图片描述

在数字图像处理中,形态学处理是通过数字模板从图像中获取有用或去除无用图像细节的方法。图像形态学算法包括膨胀和腐蚀、开运算和闭运算等。腐蚀过程是通过锚点在图片上移动,每次取有效点中的最小值作为此时锚点的值。与腐蚀相反,膨胀过程是通过锚点在图片上移动,每次取有效点中的最大值作为此时锚点的值。开操作是先腐蚀、后膨胀处理。闭操作是先膨胀、后腐蚀处理。

滤波方法应用

OpenCV提供cvSmooth函数实现了图像平滑处理,该函数实现了中值滤波、高斯滤波、双边滤波三种滤波的方法。
cvSmooth 函数的接口为: void cvSmooth( const CvArrsrc,CvArr dst,intsmoothtype=CV_GAUSSIAN, int param1=3, int param2=0,double param3=0, doubleparam4=0 );
OpenCV提供了均值漂移分割算法,也可以通过设置输入参数用作滤波。它的函数接口为: void cvPyrMeanShifFiltering(const CvArrsrc,CvArrdst,double sp, double sr, intmax_level=1,CVTermCriteria termcrit = cvTermCriteria(CV_TERMCRIT_ITER + V_TERMCRIT_EPS,5,1))。
对加入椒盐噪声的的图像,分别用均值、中值、高斯、双线性和均值漂移滤波方法进行处理,结果如图所示。
在这里插入图片描述

形态学方法应用

在OpenCV中,已经封装好了这些函数的接口,在使用时可以直接调用。OpenCV中提供的腐蚀函数接口: cvErode(const CvArrsrc, CvArrdst, IplConvKernelelementCcV DEFAULT(NULL), int iterations CV_DEFAULT(1))。
膨胀函数的接口为: cvDilate(const CvArr
src, CvArr* dst, IplConvKernel*elementcV DEFAULT(NULL), int iterations CV_DEFAULT(1))。
在这里插入图片描述

8.手势分割

复杂的背景和周围环境光照的改变,需要选择一种合适的颜色空间。该颜色空间要求对人体肤色具有很好的聚类性,且对光照的变化不敏感。手势分割的好坏对于特征的提取有很大的影响,有可能导致最后无法正确识别,所以,有效地分割方法是本章研究的重点。首先,从颜色空间着手,改进了一种基于HSV颜色空间的肤色分割模型,然后,又提出了一种动态阈值分割算法。还定义了一种图片间颜色距离,给出了肤色筛选算法和质心矩形扩展算法。
在这里插入图片描述

在3维颜色空间中使用阈值分割,是图像分割中常用的方法。这样的颜色空间有很多,如RGB、HSV、YUV等。颜色空间的选择,一般取决于数字化硬件和应用的对象(41]。在图像处理中,我们最熟悉的是RGB颜色空间。但是他在机器视觉的应用中存在严重缺陷。它的细节难以进行数字化调整。它将色调、亮度和饱和度三个量放在一起表示,很难分开。
而HSV颜色空间是为了更好进行数字化颜色处理而设计出来。由于这类空间已经去除了大多数显著地相关性,对肤色有较好的聚类性,因而可以采用阈值分割。
由于RGB颜色空间对光照过于敏感,R、G、B三个通道的相关性过强,它将色调、亮度和饱和度三个量放在一起表示,很难分开。所以进行肤色检测时,需要先转换颜色空间再进行肤色检测。通常将RGB转换到HSV或YUV(即 YCrCb):首先,HSV和YUV颜色空间对光照变化不敏感;其次,它们是为了更好进行数字化颜色处理而设计出来。由于这类空间已经去除了大多数显著地相关性,对肤色有较好的聚类性,因而可以采用恒定的阈值分割。
为了说明构造肤色模型对肤色分割的有效性,分别使用HS’V和H’S’V空间模型进行分割实验,如图所示。从图三的实验结果中可以看出HSV颜色空间模型的分割时有效的。
在这里插入图片描述

9.手势特征提取

手势特征提取是手势识别的关键步骤。特征提取的过程就是从手势图像中抽象出某个特定动作的特征,包括形状、轨迹、轮廓、方向、角度等。在进行特征提取时,需要对这些特征进行分析和处理,从而得到最佳特征。本章主要介绍了基于拓扑的特征提取、基于几何距的特征提取、基于傅立叶描绘子的特征提取、基于指尖检测的特征提取以及几何特征的提取,并提出了一种基于逼近轮廓缺陷圆的指尖检测算法。

手势特征提取概述

在得到有效的手势分割区域之后,下面就需要对手势图像进行特征提取,得到手势的有效描述。当选取手势的特征较合适时,才能准确的对手势进行识别。
在静态手势识别系统中,一般要求手形的特征矢量需要具有旋转、平移和缩放的不变性。即当手势绕中线旋转,或者放大缩小,或移动到另一个位置,手势的特征矢量的值都应当是保持一致的。也就是说,在同一个系统中同一个手势应该具有特征矢量的不变性。而在动态手势识别系统中,就没有这样的要求,因为旋转的手势可能会表示不同的含义。例如,手掌张开,向上或者向下旋转代表不同的含义。所以,在动态手势识别系统中,手势的特征矢量只需具有平移和缩放的不变性,不具有旋转性不变性。
手势的形状特征可由几何属性、统计属性和拓扑属性来描述,相对应的有基于几何距的特征提取、基于统计信息的特征提取、基于拓扑的特征提取。本章主要介绍基于拓扑的特征提取、基于几何矩特征的特征提取和基于傅立叶描述子的特征提取,最后,给出了一种指尖检测的方法。

基于拓扑的特征提取

基于拓扑的手势特征提取方法对比较简单的手势比较适用,但不能很好的应用于较复杂的手势识别系统。基于拓扑学的特征提取的算法如下:[46]
(1)将手势图像二值化后,找出该二值化图像中手势区域的手掌中心点;(2)以手掌的中心点作为圆心,半径为r作圆;
(3)在上一步找到的圆中,记录在这些圆上象素值发生变化的点,从О变为1或者从1变为0的点保存下来,即E={Pi = 1,2,3.…., n};
(4)计算每两个点之间的距离,如果间距比域值要小,即D=|PP-|<s,那么认为这两点为噪声点,并删除这两点;
(5)重复步骤(2)~(4),直至r >w/2( w为手势区域的宽度)为止。
特征值的选取过程如下:通过执行以上步骤,对于所有的圆形路径,因为每个圆形路径在每个手指上会有两个交点,所以当前手势的手指的个数是上述步骤中得到的特征点个数的一半。找到特征点的个数BN最多的圆,可以得到其它两个特征值,分别为手腕的宽度BW,和手指到手腕的距离BD。这三个特征值BN、BW和BD可以用于手势识别的特征量,如图所示。
在这里插入图片描述

基于逼近轮廓缺陷圆的指尖检测

本文轮廓逼近算法采用的是D-P (Douglas-Peucker)算法。根据参考文献[53]它常用作曲线数据压缩算法,是一种垂距限值法,在数字化过程中,需要对曲线进行采样简化,即在曲线上取有限个点,将其变为折线,并且能够在一定程度上保持原有的形状。所以该算法对手势轮廓的多边形逼近后,能够得到一个较规则的多边形,从而有利于指尖的检测。
D-P算法描述如下:
Step1:设定阈值s 。
Step2:连接曲线首尾两点A、B,并作为两个基准点,得到一条曲线的弦,计算离弦最远的点C,并计算该点到弦的距离d。如果这个距离大于s,将点C记为第n个基准点,删除弦AB,可以得到两组基准顶点对,分别为第一个点和点C和将点C和最后一个点;如果所有点到曲线弦的距离都不大于s,则该弦作为曲线的逼近。
Step3:重复将Step2中得到的基准顶点对进行计算,直到所有点到他们的弦的距离都小于等于 。
由上面的过程可以看出,D-P算法是一个从整体到局部,
由浅入深的递归过程,对一般的变化平缓的曲线而言它具有良好的化简效果,且编程易于实现。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

10.系统整合

下图完整源码&环境部署视频教程&自定义UI界面

在这里插入图片描述

参考博客《基于OpenCV的手势1~5识别系统(源码&环境部署)》

11.参考文献


[1]刘赟,孙炎辉,黄向荣,等.基于BP神经网络的手势识别系统[J].物联网技术.2013,(7).DOI:10.3969/j.issn.2095-1302.2013.07.008 .

[2]关然,徐向民,罗雅愉,等.基于计算机视觉的手势检测识别技术[J].计算机应用与软件.2013,(1).DOI:10.3969/j.issn.1000-386x.2013.01.038 .

[3]李博男,林凡.基于曲率的指尖检测方法[J].南京航空航天大学学报.2012,(4).DOI:10.3969/j.issn.1005-2615.2012.04.026 .

[4]袁里驰.基于改进的隐马尔科夫模型的词性标注方法[J].中南大学学报(自然科学版).2012,(8).

[5]邱迪.基于HSV与YCrCb颜色空间进行肤色检测的研究[J].电脑编程技巧与维护.2012,(10).DOI:10.3969/j.issn.1006-4052.2012.10.034 .

[6]杨家骏,郭远晴,魏诗云.时空数据压缩的基于 Douglas-Peucker 算法的改进与实现[J].计算机光盘软件与应用.2012,(7).176.

[7]依玉峰,高立群,郭丽.基于Mean Shift随机游走图像分割算法[J].计算机辅助设计与图形学学报.2011,(11).

[8]张争珍,石跃祥.YCgCr与YCgCb颜色空间的肤色检测[J].计算机工程与应用.2010,(34).DOI:10.3778/j.issn.1002-8331.2010.34.051 .

[9]李德启,王化喆.基于误差反向传播神经网络算法的分析与研究[J].濮阳职业技术学院学报.2010,(1).DOI:10.3969/j.issn.1672-9161.2010.01.042 .

[10]张增银,元昌安,胡建军,等.基于GEP和Baum-Welch算法训练HMM模型的研究[J].计算机工程与设计.2010,(9).

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

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

相关文章

LTO编译器优化介绍以及开启方法

文章目录 LTO介绍LTO 开启方法 LTO介绍 LTO&#xff08;Link Time Optimization&#xff0c;链接时优化&#xff09;是一种在链接阶段进行优化的技术。传统的编译过程中&#xff0c;编译器仅能对单个编译单元进行优化。LTO 允许编译器看到跨编译单元的代码&#xff0c;从而进行…

jquery 判断是手机端还是电脑端

判断为手机端&#xff1a; var sUserAgent navigator.userAgent.toLowerCase(); var bIsIpad sUserAgent.match(/ipad/i) "ipad"; var bIsIphoneOs sUserAgent.match(/iphone os/i) "iphone os"; var bIsMidp sUserAgent.match(/midp/i) "mid…

【开源】基于Vue和SpringBoot的快递管理系统

项目编号&#xff1a; S 007 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S007&#xff0c;文末获取源码。} 项目编号&#xff1a;S007&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 数据中心模块2.2 快递类型模块2.3 快…

【读书笔记】微习惯

周日晚上尝试速读一本书《微习惯》&#xff0c;共七章看了下目录结构并不复杂&#xff0c;计划每章7-8分钟读完&#xff0c; 从20:15-21:00。读的时候&#xff0c;订下闹钟&#xff0c;催促着自己的进度。边读边记了一些要点和微信读书里面的划线。 第六章实践内容最为丰富&…

“此应用专为旧版android打造,因此可能无法运行”,问题解决方案

当用户在Android P系统上打开某些应用程序时&#xff0c;可能会弹出一个对话框&#xff0c;提示内容为&#xff1a;“此应用专为旧版Android打造&#xff0c;可能无法正常运行。请尝试检查更新或与开发者联系”。 随着Android平台的发展&#xff0c;每个新版本通常都会引入新的…

wvp gb28181 pro 平台国标级连功能说明

国标28181不同平台之间支持两种连接方式&#xff0c;平级和上下级&#xff0c;WVP目前支持向上级级联。 测试环境 测试平台上级&#xff1a;192.168.10.209&#xff08;Alam centos8&#xff09; 测试平台下级&#xff1a;192.168.10.206&#xff08;ky10_x86&#xff09; 下级…

KDE环境文件夹user-dirs为英文

KDE环境文件夹user-dirs 修改KDE主页文件夹为英文 该文件路径 ~/.config/user-dirs.dirs打开后会发现里面的内容如下 # This file is written by xdg-user-dirs-update # If you want to change or add directories, just edit the line youre # interested in. All local …

openGauss学习笔记-140 openGauss 数据库运维-例行维护-例行维护表

文章目录 openGauss学习笔记-140 openGauss 数据库运维-例行维护-例行维护表140.1 相关概念140.2 操作步骤140.3 维护建议 openGauss学习笔记-140 openGauss 数据库运维-例行维护-例行维护表 为了保证数据库的有效运行&#xff0c;数据库必须在插入/删除操作后&#xff0c;基于…

Ant Design Pro 框架设置API Token拦截器的功能

分享记录一个解决方法&#xff0c;希望对大家有帮助。 找到文件&#xff0c;然后定义一个方法。最后调用一下即可。 代码我也给你贴上了。 // 获取token 拦截方法 const setTokenRequest (config: any) > {const token 30|eh5GNXWRe5rO4XLjbbnqy132RABfiKqI338EoIhqc790a…

思维模型 反馈效应

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。反馈促进改进。 1 反馈效应的应用 1.1 反馈效应在营销中的应用 1 “可口可乐与百事可乐之战” 在 20 世纪 80 年代&#xff0c;可口可乐公司是全球最大的饮料公司之一&#xff0c;其市场…

利用reddit的api进行爬虫

1 介绍 Reddit是一个社交新闻聚合网站&#xff0c;用户可以发布、评价和讨论各种话题。Reddit的内容涵盖了广泛的主题&#xff0c;可以从中获取大量的文本数据进行情绪分析。 2 注册 2.1 注册reddit 你需要先注册一个reddit的账号。 2.2 注册api https://www.reddit.com/…

文科专业和编程基础薄弱的女孩子做软件的神器——aardio学习资源入门

相关资源 aardio 开发桌面应用&#xff0c;这几点必须要掌握&#xff01; - 星安果的文章 - 知乎 https://zhuanlan.zhihu.com/p/430970376 从使用者角度来为aardio编程软件说句话 - popdes的文章 - 知乎 https://zhuanlan.zhihu.com/p/461290014 故事和情怀 优点 1 快捷 2 …

HarmonyOS开发(九):数据管理

1、概述 1.1、功能简介 数据管理为开发者提供数据存储、数据管理能力。 它分为两个部分&#xff1a; 数据存储&#xff1a;提供通用数据持久化能力&#xff0c;根据数据特点&#xff0c;分为用户首选项、键值型数据库和关系型数据库。数据管理&#xff1a;提供高效的数据管…

Bean的加载控制

Bean的加载控制 文章目录 Bean的加载控制编程式注解式ConditionalOn*** 编程式 public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {try {Class<?> clazz Class.forName("…

UCore-OS实验Lab0

实验内容&#xff1a;搭建ucore-os的实验环境 实验准备内容&#xff1a;vmware虚拟机&#xff0c;ubuntu22.04镜像&#xff0c;qemu7.0.0源码 ucore代码地址 GitHub - chyyuu/os_kernel_lab at x86-32 实验步骤&#xff1a; 在vmware中安装ubuntu&#xff0c;因为我个人喜欢…

openEuler学习04-ssl升级到openssl-1.1.1w

当前环境ssl的版本是 1.1.1f &#xff0c;计划升级到openssl-1.1.1w [roottest ~]# more /etc/os-release NAME"openEuler" VERSION"20.03 (LTS-SP3)" ID"openEuler" VERSION_ID"20.03" PRETTY_NAME"openEuler 20.03 (LTS-SP3)&q…

ES6 Promise的用法,async/await异步处理同步化

文章目录 一、什么是promise &#xff1f;二、await / async ES7的新规范&#xff0c;异步处理同步化 一、什么是promise &#xff1f; promise是解决异步的方法&#xff0c;本质上是一个构造函数&#xff0c;可以用它实例化一个对象。对象身上有resolve、reject、all&#xff…

java学习part33Date

1.Jdk8之前 1.1当前系统时间 1.2.Date类 1.2.1util.date 两个构造器两个方法 1.2.2sql.date 1.3SimpleDateFormat日期格式 1.4Calendar日历 147-常用类与基础API-JDK8之前日期时间API的使用&#xff1a;Date、SimpleDateFormat、Calendar_哔哩哔哩_bilibili 2.Jdk8 2.1本地时…

【C语言学习疑难杂症】第6期:C语言中如何打印一些特殊字符,比如打印扩展ascii码字符

首先我们来看下ascii表和ascii拓展表: ascii表中的字符只有128个,是从0-127,而拓展ascii表的内容是128-255。拓展表中它们都是一些特殊的字符,如果我们想答应ascii拓展码中的一些字符应该要怎么操作呢? 比如下面的代码: unsigned char a = 176, b = 219;printf("%…

Nginx反向代理和负载均衡详细教程

1、Nginx反向代理概述 关于正向代理和反向代理&#xff0c;我们在前面的章节已经通过一张图给大家详细的介绍过了&#xff0c;简而言之就是正向代理代理的对象是客户端&#xff0c;反向代理代理的是服务端&#xff0c;这是两者之间最大的区别。 Nginx即可以实现正向代理&#x…