目录
1. 课题背景及分析
2. 算法设计
3. 算法实现与调试
4. 实验结果及分析
5. 今后研究及改进计划
6. 设计总结
7. 主要参考书目
8. 附件
1.1 课题背景
(1)所选课题的应用背景;
伴随着人工智能时代的到来,人机交互的领域也逐渐成为研究的一大方向;其中,手势识别是人机交互领域的一项关键技术,自此手势识别也迎来了一波高潮,近几年无论是在消费领域、电子领域、数码领域、家电领域甚至汽车领域上,都能或多或少的见到手势识别的身影。
手势识别在设计智能高效的人机界面方面具有至关重要的作用, 目前手势识别已应用到手语识别、智能监控、到虚拟现实等各个领域,手势识别的原理都是利用各种传感器(例如红外、摄像头等)对手部的形态进行捕捉并进行建模,形成一个模型信息的序列帧,而后将这些信息序列转换为机器能够识别的相对应指令(例如打开、切换菜单、移动等)来完成控制。
(2)课题的关键技术难点及技术现状;
手势识别是指计算机对人体运动的数学解释,为了提供必要的任务辅助,计算机需要正确地理解人类的手势,并根据手势的预定义指令进行操作。手势识别技术通常有数据采集、数据预处理、特征提取和识别分类几个不同技术阶段。目前手势识别主要有基于计算机视觉、基于超声波和基于惯性传感器三种实现方式
个人在进行手势识别算法设计面临的关键技术难点在于Open CV库的使用不是很熟练,有些Open CV库中的函数使用有很多不理解的地方,因此,本人在进行手势识别算法设计前,需要将所必须要用到的函数先进行温习和学习,才能运用到课题当中,
(3)设计基本思想及设计内容;
由于个人在本次课题之前已经学完HTML5(广义上,HTML5=HTML5本身+CSS3+JavaScript),Python,并可以熟练运用Python的集成开发环境Pycharm进行课题的设计,再加上对Open CV库的学习,(Open CV是一个用于图像处理、分析、机器视觉方面的开源函数库),本次手势识别算法设计将采用Python+Open CV的形式进行算法设计。基本思路及设计内容如下:(HTML5如何运用到手势识别中,本人还未有逻辑思路,因此本次课题设计只采用Python+Open CV的形式进行算法设计,后续本人将继续学习,争取将所学的知识都可以使用上。)
采用Python的集成开发环境Pycharm进行本次课程设计,在Pycharm中进行需要库(模块)的下载,调取电脑摄像头,按帧读取摄像头采集到的头像,形态学处理,图像旋转(由于摄像头采集到的图像是镜像,需要用cv2.flip将摄像头采集到的图像进行处理),选取图片中固定位置作为手势输入,用红线画出手势识别框,基于hsv的肤色检测,进行高斯滤波,找出轮廓,求出图像中手势的凹凸点,手指间角度求取。
手势识别算法设计流程图如下:
第一点:加载图片,无论用cv2导入一张静态手势图片还是用摄像头导入实时图片都可以;这里由于直接调取摄像头方便一些,因此本人在这里直接选取调取摄像头获取实时图片。但是与静态手势图片相比较,静态图片在拍摄时可以防止光线,背景颜色等因素,结果会更具有真实性。
第二点: 肤色检测,基于HSV颜色空间H,S,V范围筛选法 HSV中 7 第三点:进行高斯滤波,通过mask(mask=cv2.inRange)把HSV图片中在颜色范围内的区域变成白色,其他区域变成黑色;设置阈值去除背景部分,得到想要的区域。 第四点:边缘轮廓检测,这里使用Open CV库里的findContours进行查找检测物体的轮廓。 第五点:求出手势的凹凸点,这里采用Open CV库和math库的功能进行凹凸点的计算和求解。 第六点:利用凹凸点个数判断当前手势(例如:0个凹凸点就是拳头,4个凹点就是布也就是5),相比调用“百度云的人体特性识别的库” (即百度AI库),使用条件判断比较落后,但百度AI库上的资源需要付费才可以调用,因此在这里进行比较原始的条件判断识别。 改进一:手势特征条件判断可以修改成调用“百度云的人体特性识别的库” (即百度AI库),但百度AI库上的资源需要付费才可以调用,因此在这里进行比较原始的条件判断识别。 改进二:由于个人的技术的局限性,尝试了多次利用Python的GUI功能编程进行识别窗口的美化和改变视图的大小,但加上后,代码反复报错,不能实现原有的手势识别功能;因此,GUI功能编程这里暂时先不加进去,在以后学习完Python中的GUI功能后,在弥补现有的遗憾。 改进三:在设计源代码的时候,每个代码都是穿插在各个过程中,不容易去观看,因此,在设计初稿(最开始的源代码)上,改进行了代码的注释,尽量将一个过程中的代码放在一起。 1、导入手势识别引用得到的库(模块); 2、调用电脑的摄像头,一般电脑只有一个摄像头,摄像头编号为0; 3、读取摄像头采集到的视频照片,同时设置电脑窗口进行选择手势输入的位置的定义; 4、通过色彩值的不同,进行hsv的肤色检测,使用摄像头可以检测手摆出的手势; 5、对摄像头识别到的手势进行高斯滤波处理; 6、找出经过高斯滤波后手部手势的轮廓; 7、定义和找出手部手势的凹凸点; 8、求出凹凸点 9、手势的条件判断,根据手势的特征进行定义识别指令(识别手势的对应指令,相当于建立了一个手势特征库); 10、设置保存显示和键盘Esc键停止程序的指令; 在调试时,退出指令也可通过停止程序运行的选项卡(红色按钮)进行停止,如下图: (2)实现过程中遇到的问题及解决步骤; 问题一:在编写程序前,下载库和模块就有问题,由于numpy库、Open CV库在Pycharm中不是自带的库,且在Pycharm中不能下载,因此需要通过其他方法进行库的下载;通过win+R调出运行命令窗口,输入cmd进行相应库的安装,但在输入安装指令pip install +对应库的名称后,发现还会出现需要修改电脑的环境变量(百度查找修改方法),最终成功解决库的安装问题,本人安装成功显示的图片如下: 问题二:在进行程序的设计时,由于自己对Open CV库不是很熟练,因此,每遇到需要Open CV库的函数时,都要去学习和了解函数的各个参数的用法和所产生的结果数值(在代码过程中,各个函数的用法都标注出来了,具体详见源代码.py文件上)。 问题三:在用Python的集成开发环境Pycharm编程时,编程的代码没有问题,但程序却是一直报错,无论怎么查阅资料都解决不了,在看到一篇文章时,发现自己的编程的格式出了问题,一个空格导致的报错,因此一定要注意编程格式的问题,有可能就是编程格式的问题,导致问题的出现。 由于格式问题导致的报错截图如下: 问题四:成功下载对应库的时候,却发现自己的代码还是报错显示找不到下载的库,经过自己在网络上差找资料,并且多次重复下载numpy和open cv库,发现还是没有用,但最终发现是下载库的文件夹的位置放错了,应该保持下载的库文件和自己的源代码py文件在同一根目录下,这样代码才可以引用下载的库文件。 问题五:在对求出凹凸点个数的过程中,求得的凹凸点会受到光线,与皮肤同色系物品的影响(图书馆书架是同肤色系的,因此发现这个同肤色系的物品问题)等因素,目前,由于自己的Python技术能力还没有达到进阶等级,故这个问题待解决。(也是整个代码实现最大的劣处) 注意:检测时,注意把手放到红色方框内检测,(图书馆调试发现背景及其强光问题)同时背景颜色要偏暗一些,避免强光的照射,这里的调试结果均在寝室暗处进行调试。 手势“0” 手势“2” 手势“3” 手势“4” 手势“5” (2)实验分析:根据实验结果进行原理分析,找出算法优劣的原因; 算法优点:算法比较简单,逻辑也比较简单,容易设计;这个算法不用提前拍出手势照片,而是通过直接调用摄像头采集视频中的图像,进行图像处理,通过手势特征条件判断进行识别对应手势操作。 算法劣处:受光线影响很大,而且经常受背景干扰。凹凸点也经常显示不准确(用手背测试效果好一些,可能因为颜色变化比较平滑)开始判断条件设置错了,导致没有手的时候也显示出结果。程序无法判断剪刀,因为剪刀和没有手势都是一个凹凸点,可能可以通过是否轮廓封闭来区分?但不会用代码进行区分。中间的凹凸点的实现没有怎么理解。实际中凹凸点很不准确,并且由于手的晃动点的识别更加不准确 手势识别实现了人与计算机的简单交互,使得人们操作计算机变得简单、易用。通过摄像头捕捉手势图像,通过图像预处理(分离HSV通道)获得手的二值图像,通过进一步的图像处理(腐蚀,高光补偿等)获得手的轮廓,然后在针对手的轮廓图像对手进行特征提取,采用模板匹配的方式对手势进行识别。 在未来中,会努力将本次课程设计中想要实现的功能,却因为自己的技术上的有限性,会在以后弥补上,例如消除掉或减小光线或肤色同色系的物体的影响,简化代码,使代码变得更加专业化,目前课程设计的源代码有些复杂,出了Bug难于寻找,努力做到将每一个小过程变的专业化,也便于出现Bug易于寻找。 本次课程设计采用的是Python+Open CV的手势识别算法设计,我会继续加强个人对于视觉图像处理的学习,在技术达标的时候,尽量做到用到Python的GUI编程将识别的窗口变得更加清楚美观,将编写的代码变的更加专业化。 (1)本次设计的经验、教训: 通过本次基于Python+Open CV的手势识别算法设计,让我深刻的认识到数字图像处理在日常生活中使用的如此广泛,对于图像的属性,图像的形态学处理等知识都有了更加深刻的理解和认识;同时对Python的编程吸取到如下经验教训: 首先,任何时候不要想当然,当我在选择做手势识别项目时,自己就已经有思路想用Python去实现功能,甚至自认为这个项目是一个简单的项目,我可能会认为某个部分可以轻松完成。一定不要这样想!除非你拥有一个类、组件、或者一段已经写好的代码,并且这个项目已经有模板,否则一个程序的类的创建,就会搭建很久,不要自以为是,认为这将是很容易的。 其次,在完成这个课程设计时,对Python中的有些函数的使用不够熟练,导致在设计过程中不断的在Python手册中查阅各个函数的使用方法,及其各个函数的参数值的意思。(查阅的函数值和参数的意思可以见源代码中)。 最后,就是自己的技术能力还是有待提高的,有些想要实现的功能由于自己技术能力的问题,目前都无法实现,因此,未来的自己还是要继续学习Python、Open CV库在图像处理方面的知识的使用。 (2)重点结合当前机器视觉技术的发展实际及未来的技术发展趋势,重点论述个人对未来机器视觉、人工智能应用场景创新设计。 手势识别作为一门新兴的技术,在不同领域有着不同的用途。随着研究的深人以及瓶颈技术的不断突破,手势识别的应用将不断被扩展,现阶段手势识别研究取得了蓬勃的发展,目前下游应用市场也在逐渐成熟,现在大部分消费类应用都在试图增加这一识别功能,无论是智能家居,智能可穿戴以及VR等应用领域,增加了手势识别控制功能,必能成为该应用产品的一大卖点。手势识别可以带来很多的好处,功能炫酷,操作方便,在很多应用场合都起到了良好的助力功能;但本人通过查找资料,同时也发现手势识别的缺点还是很多的; 个人目前认为手势识别在实现途径中各自存在一定的优缺点,目前主要存在以下几类问题系统可靠性不足复杂的背景颜色、噪声环境以及空间不足等问题都会直接影响到手势识别系统的可靠性,这一问题直接限制了手势识别技术的应用环境。同时不同人群会有不同的手势习惯,这导致手势模型的描述能力受到约束,在手势预定义动作较多的时候,动作模型的泛化能力需要进一步研究与探讨实时性与小型化的挑战在一定条件下,基于视觉的手势识别技术表现出了最佳识别性能。但该方法需要进行图像获取,且算法复杂度较高,普遍存在硬件要求较高,实时性能不足的问题,这也是该方法在移动智能设备与可穿戴设备中没有得到广泛应用的原因之一。因此,实时性与小型化成为手势识别技术未来发展中的重要挑战。 近年来,由于硬件的不断改善,深度学习在视觉识别等方向有了突破性的进展,具体表现为人机交互行为频繁地出现在日常中,尤其计算机视觉方面的飞速发展导致以人为本的人机交互技术必将取代以计算机为本的人机交互技术。手势识别的研究提供了一种与人类互动的新方式,它符合上述描述的趋势。原始的手势识别方法采用人力提取特征值,费时费力。因此提出了一种新的手势识别算法,该算法基于深度卷积神经网络和深度卷积生成对抗网络,在表情识别、计算和文本输出等方面都可以使用这一方法,效果良好。实验发现该方法识别时只用了较少的样本训练模型,但依然对手势分类和检测产生了重大的影响。此外,该方法不仅可以进行有效地实时识别,而且还不易受到光照和背景干扰的影响。这一点恰恰也是本次课程设计最大的缺陷,极容易受到光照和背景干扰的影响。 相信在未来机器人时代的到来,机器视觉技术的发展将会越来越健全,在家庭娱乐(三星、康佳等电视厂商已经推出带有手势识别的电视机产品,直接用掌心挥动、握拳抓取、左右挥动、双拳合作等手势来完成移动控制)、智能驾驶(在15年的CES展上,宝马 展出了最新iDrive系统,其重要变化之一就是引入了手势识别功能,通过安装在车顶上的3D传感器对驾驶员手势的识别,实现对车辆导航)、智能穿戴(目前微软的全息眼镜hololens)等方面一定会赶超美国、日本等发达国家,成为世界机器视觉处理先进的国家! [1]袁博,查晨东.手势识别技术发展现状与展望[J].科学技术创新,2018,000(032):95-96. [2]梁娜.基于计算机视觉的手势识别技术综述[J].无线互联科技,2014(10):84. [3]袁世涛.基于计算机视觉的手势识别系统研究[D].西安电子科技大学,2011. [4]赵小川,赵继鹏,范炳远,郝丽丽.手势识别技术研究综述与应用展望[C]//第十一届全国信号和智能信息处理与应用学术会议专刊.北京《计算机工程与应用》期刊有限公司(JournalofComputerEngineeringandApplicationsBeijingCo.,2017:304-307. [5]刘长坤,符志强,李舒怡,蒋明亮,宋晓金.基于手势识别的智能控制系统的设计与实现[J].电脑知识与技术,2020,16(16):9-10.DOI:10.14004/j.cnki.ckt.2020.1949. [6]王倩,程荣亮,朱习军.基于Web端舰载机手势识别仿真系统设计[J].自动化与仪器仪表,2017(01):170-173.DOI:10.14016/j.cnki.1001-9227.2017.01.170. [7]张行健,张建新.基于卷积神经网络的手势识别控制系统[J].计算机应用与软件,2020,37(10):220-224. [8]徐林尉.基于OpenCV的视觉手势识别[J].电子技术与软件工程,2016(18):111-112. 程序代码(以下程序为.py文件直接复制过来的程序代码,源代码文件已经附在文件夹里,在pycharm中下载numpy、Open CV库,文件就可以运行,但一定要注意光线及背景颜色的影响!)
3. 算法实现与调试
4. 实验结果及分析
5. 今后研究及改进计划
6. 设计总结
7. 主要参考书目
8. 附件
# _*_ coding: UTF-8 _*_
#1.引用需要的库(模块)
import cv2
import numpy as np
import math
cap = cv2.VideoCapture(0) # 2.打开摄像头 内置摄像头索引为0 ,0是代表摄像头编号,只有一个的话默认为0
'''
cap = cv2.VideoCapture(0)参数0表示默认为笔记本的内置第一个摄像头
如果需要读取已有的视频图像则参数改为图片所在路径路径
例如:cap=cv2.VideoCapture(‘video.mp4’),当然可通过对视频图像的采集
'''
#3.读取照片 选择手势输入的位置
while (cap.isOpened()): #循环,检查是否初始化成功,成功则返回True cap.isOpened()判断视频图像对象是否成功读取,成功读取视频图像对象返回True。
ret, frame = cap.read() # 按帧读取图像,前面结合while循环可以一直读取视频
'''
ret,frame = cap.read()按帧读取视频图像,返回值ret是布尔型,正确读取则返回True,读取失败或读取视频图像结尾则会返回False。frame为每一帧的图像
'''
frame = cv2.flip(frame, 1) #图像旋转,cv2.flip(frame, 1)第一个参数表示要旋转的视频,第二个参数表示旋转的方向,0表示绕x轴旋转,大于0的数表示绕y轴旋转,小于0的负数表示绕x和y轴旋转
kernel = np.ones([2, 2], np.uint8) #矩阵赋值 kernel:卷积核 2*2的卷积核 uint8是专门用于存储各种图像的(包括RGB,灰度图像等),范围是从0–255
roi = frame[100:300, 100:300] # 选取图片中固定位置作为手势输入
cv2.rectangle(frame, (100, 100), (400, 400), (0, 0, 255), 0) # 用红线画出手势识别框; 图片,左上点坐标,右下点坐标,rgb颜色,线的宽度
# 4.基于hsv的肤色检测
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) #将一种色彩空间的输入图像转换为另一种色彩空间
lower_skin = np.array([0, 28, 70], dtype=np.uint8) #查找颜色的低阈值
upper_skin = np.array([20, 255, 255], dtype=np.uint8) #查找颜色的高阈值
# 5.进行高斯滤波
mask = cv2.inRange(hsv, lower_skin, upper_skin) #利用cv2.inRange函数设阈值,去除背景部分
'''
mask = cv2.inRange(hsv, lower_red, upper_red) #lower20===>0,upper200==>0,
第一个参数:hsv指的是原图
第二个参数:lower_red指的是图像中低于这个lower_red的值,图像值变为0
第三个参数:upper_red指的是图像中高于这个upper_red的值,图像值变为0
而在lower_red~upper_red之间的值变成255'''
mask = cv2.dilate(mask, kernel, iterations=4) #opencv可以利用cv2.dilate()函数对图片进行膨胀处处理。
'''
cv2.dilate(img, kernel, iteration)
img – 目标图片
kernel – 进行操作的内核,默认为3×3的矩阵
iterations – 腐蚀次数,默认为1
'''
mask = cv2.GaussianBlur(mask, (5, 5), 100) #高斯滤波GaussianBlur()
'''
其中我们最常用到的参数为:img = cv2.GaussianBlur(src, (blur1, blur2), 0)
其中src是要进行滤波的原图像,(blur1,blur2)是高斯核的大小,blur1和blur2的选取一般是奇数,blur1和blur2的值可以不同。参数0表示标准差取0。
高斯滤波GaussianBlur()中参数详解:
cv2.GaussianBlur( SRC,ksize,sigmaX [,DST [,sigmaY [,borderType ] ] ] )
src –输入图像;图像可以具有任何数量的信道,其独立地处理的,但深度应CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
dst –输出与图像大小和类型相同的图像src。
ksize –高斯核大小。 ksize.width 并且 ksize.height 可以有所不同,但它们都必须是正数和奇数。或者,它们可以为零,然后从计算 sigma*。
sigmaX – X方向上的高斯核标准偏差。
sigmaY – Y方向上的高斯核标准差;如果 sigmaY 为零,则将其设置为等于 sigmaX;
如果两个西格玛均为零,则分别根据ksize.width 和 进行计算 ksize.height(getGaussianKernel()有关详细信息,请参见 link);
完全控制的结果,无论这一切的语义未来可能的修改,建议指定所有的ksize,sigmaX和sigmaY。
borderType –像素外推方法(borderInterpolate()有关详细信息,请参见link )
'''
#6.找出轮廓
contours, h = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #查找检测物体的轮廓
'''
注意的是cv2.findContours()函数接受的参数为二值图,即黑白图(不是灰度图),所以读取的图像要先转成灰度的,再转成二值图
第一个参数是寻找轮廓的图像;
第二个参数表示轮廓的检索模式,有四种:
cv2.RETR_EXTERNAL 表示只检测外轮廓
cv2.RETR_LIST 检测的轮廓不建立等级关系
cv2.RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
cv2.RETR_TREE 建立一个等级树结构的轮廓。
第三个参数method为轮廓的近似办法
cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法
'''
#7.定义、找出凹凸点
cnt = max(contours, key=lambda x: cv2.contourArea(x))
epsilon = 0.0005 * cv2.arcLength(cnt, True) #计算轮廓周长cv.arcLength
'''
InputArray类型的curve,输入的向量,二维点(轮廓顶点),可以为std::vector或Mat类型。
bool类型的closed,用于指示曲线是否封闭的标识符,一般设置为true。
注意:计算轮廓的周长值是按照轮廓的实际长度进行计算的
'''
approx = cv2.approxPolyDP(cnt, epsilon, True)
'''
cv2.approxPolyDP(contour,epsilon,True) 采用Douglas-Peucker算法
第一个参数是轮廓的点集。
第二个参数epsilon的含义如下所述,滤掉的线段集离新产生的线段集的距离为d,若d小于epsilon,则滤掉,否则保留。
第三个参数指示新产生的轮廓是否闭合。
返回的是一些列点组成的多边形。
'''
hull = cv2.convexHull(cnt) #求多边形凸包
'''
在黑色背景图下画出源图像的三种轮廓:
cv2.findContours得到的轮廓
对cv2.findContours得到的轮廓做近似多边形处理cv2.approxPolyDP
对cv2.findContours得到的轮廓做凸包处理cv2.convexHul
'''
areahull = cv2.contourArea(hull) #计算hull图像轮廓的面积
areacnt = cv2.contourArea(cnt) #计算cnt图像轮廓的面积
arearatio = ((areahull - areacnt) / areacnt) * 100
# 8.求出凹凸点
hull = cv2.convexHull(approx, returnPoints=False)
defects = cv2.convexityDefects(approx, hull)
# 定义凹凸点个数初始值为0
l = 0 #定义凹凸点个数初始值为0
for i in range(defects.shape[0]):
s, e, f, d, = defects[i, 0]
start = tuple(approx[s][0])
end = tuple(approx[e][0])
far = tuple(approx[f][0])
pt = (100, 100)
a = math.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2) # math.sqrt 返回不同数的平方根
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)
s = (a + b + c) / 2
ar = math.sqrt(s * (s - a) * (s - b) * (s - c))
# 手指间角度求取
angle = math.acos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) * 57
if angle <= 90 and d > 20:
l += 1
cv2.circle(roi, far, 3, [255, 0, 0], -1)
cv2.line(roi, start, end, [0, 255, 0], 2) # 画出包络线
l += 1
font = cv2.FONT_HERSHEY_SIMPLEX
# 9.条件判断,也就是知道手势后你想实现什么功能,识别什么图案就添加进去,相当于库(根据手势特征进行定义)。
if l == 1:
if areacnt < 2000:
cv2.putText(frame, "put hand in the window", (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
else:
if arearatio < 12:
cv2.putText(frame, '0', (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
elif arearatio < 17.5:
cv2.putText(frame, "1", (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
else:
cv2.putText(frame, '1', (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
elif l == 2:
cv2.putText(frame, '2', (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
elif l == 3:
if arearatio < 27:
cv2.putText(frame, '3', (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
else:
cv2.putText(frame, '3', (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
elif l == 4:
cv2.putText(frame, '4', (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
elif l == 5:
cv2.putText(frame, '5', (0, 50), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
#10.保存显示
cv2.imshow('frame', frame)
cv2.imshow('mask', mask)
k = cv2.waitKey(25) & 0xff
#11.键盘Esc键停止程序
if k == 27:
break
cv2.destroyAllWindows()
cap.release()