手指和手势识别算法原理和解析

最近发现了一个挺厉害的人工智能学习网站,内容通俗易懂,风趣幽默,感兴趣的可以点击此链接进行查看:床长人工智能教程

 废话不多说,请看正文!

1、问题陈述

        我们将从视频序列中识别手势。为了从实时视频序列中识别这些手势,我们首先需要单独取出手部区域,以去除视频序列中所有不需要的部分。在分割手部区域之后,我们对视频序列中显示的手指进行计数,以基于手指计数来指示机器人。因此,可以使用2个简单的步骤解决整个问题

  1. 1.从视频序列中找到并分割手部区域。
  2. 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)、肤色检测

在要跟踪用户手部运动的应用程序中,肤色直方图将非常有用。然后,此直方图用于从图像中减去背景,只保留图像中包含肤色的部分。

一种检测皮肤的简单得多的方法是找到某个RGBHSV范围内的像素。上述方法的问题在于,改变光照条件和肤色会确实干扰皮肤检测。另一方面,直方图往往更准确,并考虑了当前的光照条件。

绿色矩形绘制在框架上,用户将手放在这些矩形内。应用程序从用户的手中获取肤色样本,然后创建直方图。

使用以下功能绘制矩形:

这里没有什么复杂的事情。我创建了四个阵列hand_rect_one_xhand_rect_one_yhand_rect_two_xhand_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’ 建立背景模型.

对手指检测时:

  1. 当前帧与背景模型相减,获取到前景(hand)
  2. 对前景进行肤色检测, 获取一个只含肤色区域的框架(hist_mask_image).

 

  • 7
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zpeien

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值