手指和手势识别算法原理和解析
最近发现了一个挺厉害的人工智能学习网站,内容通俗易懂,风趣幽默,感兴趣的可以点击此链接进行查看:床长人工智能教程
废话不多说,请看正文!
1、问题陈述
我们将从视频序列中识别手势。为了从实时视频序列中识别这些手势,我们首先需要单独取出手部区域,以去除视频序列中所有不需要的部分。在分割手部区域之后,我们对视频序列中显示的手指进行计数,以基于手指计数来指示机器人。因此,可以使用2个简单的步骤解决整个问题
- 1.从视频序列中找到并分割手部区域。
- 2.从视频序列中分割的手区域计算手指的数量。
2、分割手区域
手势识别的第一步显然是通过消除视频序列中所有其他不需要的部分来找到手部区域。起初这似乎令人恐惧。但是不用担心。使用Python和OpenCV会容易得多!
注意:视频序列只是相对于时间运行的帧集合或图像集合。
在深入探讨细节之前,让我们了解如何确定手部区域。
1)、背景扣除
首先,我们需要一种有效的方法来将前景与背景分开。为此,我们使用移动平均值的概念。我们使我们的系统可以查看特定场景的30帧。在此期间,我们计算当前帧和先前帧的运行平均值。通过这样做,我们实质上告诉我们的系统-
弄清楚背景之后,我们举起手来,使系统了解我们的手是进入背景的新条目,这意味着它成为前景对象。但是,我们将如何单独看待这一前景呢?答案是背景减法。
查看下面的图片,其中描述了背景减法的工作原理。
在使用移动平均值计算出背景模型之后,我们使用当前框架以及背景来保存前景对象(在本例中为hand)。我们计算背景模型(随时间更新)与当前帧(有我们的手)之间的绝对差值,以获取包含新添加的前景对象(即我们的手)的差值图像。这就是背景减法的全部含义。
2)、运动检测和阈(yù)值
为了从该差异图像中检测出手部区域,我们需要对差异图像进行阈值处理,以使只有我们的手部区域可见,而所有其他不需要的区域都被涂成黑色。这就是运动检测的全部意义。
注意:阈值是基于特定阈值级别将像素强度分配为0和1,以便仅从图像中捕获我们感兴趣的对象。
3)、轮廓提取
对差异图像进行阈值处理后,我们在结果图像中找到轮廓。假定面积最大的轮廓是我们的手。
注意:轮廓线是图像中对象的轮廓或边界。
因此,我们从视频序列中找到手部区域的第一步涉及三个简单步骤。
- 1、背景扣除
- 2、运动检测和阈值
- 3、轮廓提取
3、实操
我们使用函数来计算背景模型和当前帧之间的移动平均值。此函数接受两个参数- iamge(当前帧)和aWeight,这就像在图像上执行移动平均的阈值。如果背景模型为“ 无”(即,如果它是第一帧),则使用当前帧对其进行初始化。然后,使用cv2.accumulateWeighted()函数计算背景模型和当前帧的移动平均值。使用下面给出的公式计算移动平均值
dst(x,y)=(1−a).dst(x,y)+a.src(x,y)
src(x,y)----源图像或输入图像(1或3通道,8位或32位浮点)
dst(x,y)---目标图像或输出图像(与源图像相同的通道,32位或64位浮点)
a ----源图像的权重(输入图像)
下一个功能用于从视频序列中分割手部区域。这个函数有两个参数- 当前帧和阈值用于阈值化的差分图像。
首先,我们使用cv2.absdiff()函数找到背景模型和当前帧之间的绝对差异。
接下来,我们对差异图像进行阈值处理以仅显示手部区域。最后,我们对阈值图像执行轮廓提取,并获取面积最大的轮廓(这就是我们的手)。
我们将阈值图像和分割图像作为元组返回。阈值法背后的数学原理非常简单。如果x(n)表示输入图像在特定像素坐标处的像素强度,那么threshold决定我们如何将图像分割/阈值为二值图像。
x(n)={1, if n >= threshold
0, if n < threshold
上面的代码示例是我们程序的主要功能。我们将aWeight初始化为0.5。如移动平均值方程式中更早显示的那样,此阈值意味着如果为该变量设置较低的值,则将在较大数量的先前帧上执行移动平均值,反之亦然。我们使用cv2.VideoCapture(0)引用了我们的网络摄像头,这意味着我们在计算机中获取了默认的网络摄像头实例。
代替从整个视频序列中识别手势,我们将尝试最小化系统必须在其中寻找手部区域的识别区域(或区域)。为了突出显示该区域,我们使用cv2.rectangle()函数,该函数需要顶部,右侧,底部和左侧像素坐标。
为了跟踪帧数,我们初始化一个变量num_frames。然后,我们开始无限循环,并使用camera.read()函数从网络摄像头读取帧。然后,我们使用imutils库将输入帧的大小调整为700像素的固定宽度,以保持宽高比,并翻转该帧以避免产生镜像。
接下来,我们使用简单的NumPy切片仅取出感兴趣的区域(即识别区域)。然后,我们将此ROI转换为灰度图像,并使用高斯模糊来最小化图像中的高频分量。直到超过30帧为止,我们继续将输入帧添加到run_avg函数并更新背景模型。请注意,在此步骤中,必须使相机保持不动。否则,整个算法将失败。
更新背景模型后,将当前输入帧传递到分割函数中,并返回阈值图像和分割图像。所分割的轮廓绘制在使用帧cv2.drawContours() ,并使用被示出阈值化的输出cv2.imshow() 。
4、数我的手指
从实时视频序列中分割出手部区域后,我们将使我们的系统对通过摄像头/网络摄像头显示的手指进行计数。我们不能使用任何模板(由OpenCV提供)来执行此操作,因为这确实是一个具有挑战性的问题。
上一教程我们使用了“背景减法”,“运动检测”和“阈值化”概念从实时视频序列中分割出手部区域。
我们通过将分割的手区域假定为框架中的最大轮廓(即具有最大面积的轮廓)来获得该区域。如果您在此框架中引入了一个比您的手大的大物体,则此算法将失败。因此,您必须确保您的手占据框架中大部分区域。
我们将使用在可变手中获得的分段手区域。请记住,此手形变量是具有阈值(阈值图像)和分段(分段的手区域)的元组。我们将利用这两个变量来计算所显示的手指。我们该怎么做?
可以使用多种方法来数手指,但是在本教程中我们将看到一种这样的方法。如Malima等人提出的,这是一种执行手势识别的更快的方法。下图显示了计数手指的方法(由Malima等人提出)。
5、四个中间步骤
- 找到分割的手部区域的凸包(轮廓),并计算凸包中的最极端点(极端顶部,极端底部,极端左侧,极端右侧)。
- 使用凸包中的这些极值点找到手掌的中心。
- 使用手掌的中心,以最大欧几里德距离(手掌的中心与端点之间)为半径,构造一个圆。
- 在带阈值的手形图像(帧)和圆形ROI(蒙版)之间执行按位与运算。这显示了手指切片,可以进一步用于计算所示手指的数量。
在下面,您可以看到用于执行上述四个步骤的全部功能。
- 输入- 阈值(阈值图像)和分段(分段的手部区域或轮廓)
- 输出- 计数(手指数)。
每个中间步骤都需要对图像处理基础知识有所了解,例如轮廓,按位与,欧氏距离和凸包。
1)、等高线
感兴趣对象的轮廓或边界。使用OpenCV的cv2.findContours()函数可以轻松找到该轮廓。在解压缩此函数的返回值时要小心,因为在OpenCV 3.1.0- Contours中,我们需要三个变量来解压缩此元组。
2)、按位与
在两个对象之间执行按位逻辑与。您可以从视觉上将其想象为使用遮罩并提取图像中仅位于此遮罩下的区域。OpenCV提供cv2.bitwise_and()函数来执行此操作- 按位与。
3)、欧氏距离
这是此处所示方程式给出的两点之间的距离。Scikit-learn提供了一个名为pairwise.euclidean_distances ()的函数,用于计算单行代码“ 成对欧氏距离”中从一个点到多个点的欧氏距离。在那之后,我们采取了最大的使用与NumPy的所有这些距离argmax()函数。
4)、凸包
您可以将凸包视为动态的,可拉伸的信封,将目标对象包裹起来。
5)、肤色检测
在要跟踪用户手部运动的应用程序中,肤色直方图将非常有用。然后,此直方图用于从图像中减去背景,只保留图像中包含肤色的部分。
一种检测皮肤的简单得多的方法是找到某个RGB或HSV范围内的像素。上述方法的问题在于,改变光照条件和肤色会确实干扰皮肤检测。另一方面,直方图往往更准确,并考虑了当前的光照条件。
绿色矩形绘制在框架上,用户将手放在这些矩形内。应用程序从用户的手中获取肤色样本,然后创建直方图。
使用以下功能绘制矩形:
这里没有什么复杂的事情。我创建了四个阵列hand_rect_one_x,hand_rect_one_y,hand_rect_two_x,hand_rect_two_y以保持每个矩形的坐标。然后,代码遍历这些数组,并使用绘制它们在框架上cv2.rectangle。这total_rectangle只是数组的长度,即9。
既然用户了解了他或她的手掌的放置位置,接下来的步骤是从这些矩形中提取像素并使用它们生成HSV直方图。
此处功能将输入帧转换为HSV。使用Numpy,我们创建[90 * 10]具有3彩色通道大小的图像,并将其命名为ROI (Intrest区域)。然后,它从绿色矩形中获取900像素的值,并将其放入ROI矩阵中。
在cv2.calcHist创建使用肤色的ROI矩阵直方图和cv2.normalize标准化使用标准型这个矩阵cv2.NORM_MINMAX。现在我们有了一个直方图来检测帧中的皮肤区域。
既然用户了解了他或她的手掌的放置位置,接下来的步骤是从这些矩形中提取像素并使用它们生成HSV直方图。
现在我们拥有皮肤颜色直方图,我们可以使用它来查找包含皮肤的框架的组成部分。OpenCV为我们提供了一种便捷的方法,cv2.calcBackProject该方法使用直方图来分离图像中的特征。我使用此功能将肤色直方图应用于帧。
在前两行中,我将输入帧更改为HSV,然后应用cv2.calcBackProject肤色直方图hist。之后,我使用了“过滤和阈值”功能来平滑图像。最后,我使用该cv2.bitwise_and函数屏蔽了输入帧。最后一个框架应该是只包含肤色区域。
6、结合背景相减和肤色检测
先进行获取肤色样本.按 ’z’ 后建立肤色HSV直方图.
肤色标本建立后进行获取背景模型,按 ’z’ 建立背景模型.
对手指检测时:
- 当前帧与背景模型相减,获取到前景(hand)
- 对前景进行肤色检测, 获取一个只含肤色区域的框架(hist_mask_image).
手指和手势识别算法原理和解析相关推荐
- KNN 分类算法原理代码解析
作者 | Charmve 来源 | 迈微AI研习社 k-最近邻算法是基于实例的学习方法中最基本的,先介绍基x`于实例学习的相关概念. 基于实例的学习 已知一系列的训练样例,很多学习方法为目标函数建立起 ...
- python中kmeans用的是什么距离_python Kmeans算法原理深入解析
一. 概述 首先需要先介绍一下无监督学习,所谓无监督学习,就是训练样本中的标记信息是位置的,目标是通过对无标记训练样本的学习来揭示数据的内在性质以及规律.通俗得说,就是根据数据的一些内在性质,找出其内 ...
- 手指静脉细化算法过程原理解析 以及python实现细化算法
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/8672489.html 文中的一些图片以及思想很多都是参考https://www.cnblogs ...
- python文件去重算法_使用Python检测文章抄袭及去重算法原理解析
在互联网出现之前,"抄"很不方便,一是"源"少,而是发布渠道少:而在互联网出现之后,"抄"变得很简单,铺天盖地的"源"源 ...
- python去重算法_使用Python检测文章抄袭及去重算法原理解析
在互联网出现之前,"抄"很不方便,一是"源"少,而是发布渠道少:而在互联网出现之后,"抄"变得很简单,铺天盖地的"源"源 ...
- 国科大学习资料--人工智能原理与算法-第一次作业解析(学长整理)
国科大学习资料–人工智能原理与算法-第一次作业解析(张文生老师主讲)(1.3.1.7.1.9.1.14.1.15) 1.3 反射行动(比如从热炉子上缩回你的手)是理性的吗?它们是智能的吗? 答:反射行 ...
- 索引算法原理解析(B-tree以及磁盘存储原理)
刚开始学习的时候,百度去查,但发现好多说得太复杂不好理解,结合各个文章总结一下(建议大概看文字,不理解不要紧,然后再看图的执行步骤然后在结合文字,这样一切就清晰好多) B-tree,B是balance ...
- 邻近算法(KNN)原理简单解析
邻近算法(KNN)原理简单解析 一.什么是邻近算法 1.1简介 1.2核心思想 1.3 算法流程 1.4 优缺点 二.实例演示KNN算法 一.什么是邻近算法 1.1简介 邻近算法,或者说K最近邻(KN ...
- p.563算法原理解析
p.563算法原理解析 1.概览 下图展示了,人工主观语音评估mos-lqs,双端和单端客观语音评估mos-lqo这三种方法的差异. p563算法可以被想象成一个专家使用测试设备如传统的听筒侦 ...
最新文章
- 电子商务创造的第二次产业机会
- 太任性!00 后少年买不到回国机票,因“泄愤”找黑客攻击系统,被判刑 4 年
- uCOS-II 学习笔记--------OSInit函数
- php html url编码,html中url编码是什么?有什么用?
- javascript箭头函数和this的指向问题
- 容易造成单片机内存溢出的几个陷阱
- 王者服务器维修2019年四月份,王者荣耀4月25日更新内容 王者荣耀2019年4月25日全服不停机更新公告...
- linux登录pg数据库密码,PostgreSQL:修改数据库用户的密码
- gentry同态加密算法_IBM同态加密技术重大突破,加解密速度可提升75倍
- [No000072]Windows环境变量列表
- vs2010 c语言乱码,从vs2010中复制带有中文字符的代码到office等时出现乱码的解决方案.doc...
- PPT文件的密码如何破解掉
- 计算机中安装音乐软件是一种,电脑必装的八款软件,你装了吗?
- Solidity智能合约案例——投票存在的问题
- 从纯洁男孩到堕落男人
- 趋势 | 极简再见,极繁回潮
- 刚注册的Linkedin账号
- poj计算几何题推荐
- 圆圈怎么用html实现,如何利用css实现圆形效果?
- 查看网络交换机光口的光功率