基于Python实时图像获取及处理软件设计
基于Python实时图像获取及处理软件设计
- 绪论 1.1 课题背景及研究的目的和意义 本课题旨在利用Python语言,提取USB摄像头相关参数及图像,并对数字图像进行灰度化、直方图绘制、边缘检测以及人脸检测和识别等处理。通过在Windows操作系统下使用Python语言编写的可视化软件,用户可以方便的查看和设置USB摄像头的主要参数,并实时监控、保存图像的各特征,着力提高摄像头获取图像的便捷性和实用性,而人脸识别技术的应用,更大大扩展了该软件的应用空间。 1.2 课题国内外研究概况 20世纪20年代,由英国的伦敦到美国的纽约通过海底电缆采用数字压缩技术传输了第一幅数字图片,这样数字图像处理技术便由此起源。而1964年美国“喷气推进实验室”处理了由太空“徘徊者七号”发回的月球图片,这也是一个里程碑式的开端,标志着自第三代计算机问世后,数字图像处理技术开始得到普遍应用。 最后,本课题采用的软件技术也已相当成熟。Python语言经过近30年的发展,目前官方网站版本已经更新至Python 3.6.4和Python 2.7.14,强大的标准库奠定了Python发展的基石,丰富的第三方库保证了Python不断发展的。成千上万的第三方库资源,为编程提供了极大的便利,如与本课题相关图像处理和计算机视觉库OpenCV和GUI库Tkinter、wxPython、PyQT等。 1.3 摄像头图像获取及人脸检测与识别的应用 目前人脸识别技术已广泛应用于各个行业,如:楼宇人脸门禁、人脸考勤系统;亘联网移动支付终端、交友、相亲终端APP系统等。打开摄像头,刷一下脸,便可以完成支付;从大量的人脸数据库中,公安部门通过人脸识别系统更轻松地找出嫌疑人,如近日警方接二连三的在张学友演唱会中通过人脸识别系统抓获犯罪嫌疑人,如此壮举举国瞩目。这些从侧面反映出这些人脸识别技术如科幻电影一样,已经变成现实。 当然在当下极为火热的人脸考勤系统中,进行“刷脸”考勤,而目前考勤正确率已经达到很高的级别,最典型的就是“刷脸”考勤机,这其实就是一种新型的存储类考勤机,在这之前首先只需以员工人脸图像作为采集对象建立起训练数据库,当员工在上下班考勤时,只需要站在考勤机的识别区域内,考勤机上就会根据输入的图像与自身的训练数据库作为比对,同时也将记录此时的人脸数据并存储。 人脸识别在安防系统中也扮演着不可忽视的作用与价值。人脸识别门禁系统在住所、办公大楼等重要场所也发挥着作用,它利用着人脸识别技术相当于一把“钥匙”作为通行证,这项技术的关键是通过扫描设备将所扫描的人脸图像作为输入人脸图像与预先录入的人脸库比对,如果比对一致将使门禁系统打开,否则关闭,这其实就是“刷脸”来开启或关闭建筑物内的人脸识别门禁系统。同样的近年来许多火车站进站口也改用了人脸识别来代替人工核验身份证。 而从去年iPhone X发布以后,更是引爆人脸识别技术在手机等科技产品,人脸识别解锁几乎成了今年旗舰设备的标准配置。 由此可见人脸识别技术前景之广阔。 1.4 本文研究内容及组织结构
- 实时图像获取及处理的相关原理 2.1 实时图像获取设备 图像采集与处理在实时图像处理系统占有重要地位,是数字图像处理的一个关键的前提。只有实现目标场景图像的视频捕获显示及其数据获取,才能对之进行相应的分析与处理。视频采集是将一个视频流数字化,然后储存在硬盘或其它存储介质上形成一个整块集中的数据块,以供进一步处理。所以本文将首先介绍图像获取的相关内容。 2.1.1 USB摄像头图像采集原理 当前,几乎所有的图像都是通过光学镜头获取的,而我们更关心的是对图像的数字化采集。捕获图像可以采用视频采集卡,也可使用 USB 接口的数码摄像头,视频采集卡一般提供了特定品牌和型号的动态连接库和开发工具包,价格相对较贵,USB 接口的数码摄像头价格适中,性能尚可。另外,采用 USB 接口的数码摄像头,系统的硬件体系结构比较简洁,无需再配图像采集卡上位机便可直接进行图像数据处理。基于对课题需求的分析,显然USB摄像头是最合适的选择。 数字摄像头其实是把感光器件和视频捕捉器件做到了一起,一般是由镜头、感光器件、A/D(模/数转换器)、微处理器、内置存储器和接口(计算机接口、电视机接口)等部件组成。 其中感光器件一般有CCD和CMOS两种。而USB技术由于其便捷的操作, 热插拨形式的支持, 可以实现即用即连, 在多个领域有着广泛应用。 不同品牌不同型号的摄像头功能和性能是各不相同的。在与软件交互、实现对摄像头图像采集的控制时,实际是一操作系统(驱动层)为中介完成的(如右图)。因此我们必须关注USB摄像头的驱动。 2.1.2 Windows操作系统下摄像头的驱动 在本课题中,选择了基于 USB 的普通摄像头,上位机采用 PC 机。在上位机中,系统采用 Windows 操作系统,在 Windows 操作系统下USB设备的驱动和视频应用开发都是一项非常复杂的工作。幸运的是,Windows内核承担了大部分的工作。为了提高系统的稳定性,Windows操作系统对硬件操作进行了隔离;应用程序一般不能直接访问硬件,程序开发者是通过接口在应用层面,而非硬件层面,来完成相关软件开发。 根据使用驱动程序的类型不同,目前市场上的图像获取设备大致分为两大类:VFW(Video for Windows)和WDM(Windows Driver Model)。前者是一种趋于废弃的驱动模型,而后者是前者的替代模型。 VFW 是 Microsoft 1992 年推出的关于数字视频的一个软件包。在 Windows 9x 及以上版本系统中,当用户在安装VFW时,安装程序会自动地安装配置视频所需要的组件,如设备驱动程序、视频压缩程序等。VFW 软件开发工具包为在 Windows 系统中实现视频捕获提供的标准接口可以被大多数视频采集卡支持,并有多种视频压缩驱动供选择。 现在许多新的视频捕捉设备都采用的是WDM驱动方法(Windows Driver Model(WDM)的缩写,中文意思是“视窗驱动程序模块”),在WDM机制中,微软提供了一个独立于硬件设备的驱动,称为类驱动程序。驱动程序的供应商提供的驱动程序称为Minidrivers。Minidrivers提供了直接和硬件打交道的函数,在这些函数中调用了类驱动。 操作系统仍然支持VFW驱动程序,但是依赖于VFW的开发将逐渐减少。 从编程实现的角度看,对WDM卡选择视频输入端子、设置采集输出的图像格式、设置图像的对比度、亮度、色调、饱和度等显示参数,都是通过COM接口IAMCrossbar、IAMStreamConfig和IAMVideoProcAmp来实现的。但对于VFW卡,我们却不能编程实现上述设置,而必须将驱动程序定制的设置对话框直接显示给用户(让用户在这些对话框上做出选择);VFW驱动程序定制的设置对话框包括:Video Source(设置图像源属性)、Video Format(设置图像输出格式)和Video Display(设置图像显示参数)。
表 WDM驱动下常用接口 DirectShow 接口 相关属性 IAMTuner PROPSETID_VIDCAP_TUNER IAMTVAudio PROPSETID_VIDCAP_TVAUDIO IAMCrossbar PROPSETID_VIDCAP_CROSSBAR IAMVideoProcAmp PROPSETID_VIDCAP_VIDEOPROCAMP IAMAnalogVideoDecoder PROPSETID_VIDCAP_VIDEODECODER IAMAnalogVideoEncoder PROPSETID_VIDCAP_VIDEOENCODER IAMCameraControl PROPSETID_VIDCAP_CAMERACONTROL
对于应用程序开发人员来说,以上内容原理不可以不知,但也没必要研究得太透彻,而只需有一个总体的认识、作为背景知识了解一下就够了。 2.2 数字图像处理与人脸识别原理 数字图像处理是一个宽泛的概念。从图像源角度看,视觉图像是最符合人类认知的一种图像,因为视觉在人类感知中扮演着最重要的角色;然而,人类的感知仅限于电磁波谱的视觉波段,与人类不同,成像机器几乎可以覆盖从伽马射线到无线电波的整个电磁波谱,它们可以对非人类习惯的那些图像源进行加工,这些图像包括超声波、电子显微镜和计算机产生的图像。而从处理角度来看,图像处理止于哪些或其他相关领域(如图像分析和计算机视觉)从哪里开始,目前也并没有一致的看法。从图像处理到计算机视觉的这个连续的统一体内并没有明确的界限。不过、如果从低级、中级和高级处理三个角度来考虑的话,低级处理往往涉及初级操作如降低噪声的图像预处理、对比度增强和图像尖锐化等。低级处理以输入、输出都为图像为特征。中级处理涉及诸多任务,譬如图像分割、边缘检测等。中级图像处理以输入为图像但输出是从这些图像中提取的特征为特点。最后,高级处理涉及“理解”已识别目标的总体,以及在连续统一体的远端执行与视觉相关的认知功能。 就本课题而言,图像源已确定为从USB摄像头获取的图像,故为视觉图像。而在图像处理方面,在摄像头获取的彩色图像的基础上,进行初级的灰度化处理、中级的边缘检测、灰度直方图和高级的人脸检测和识别。 2.2.1图像处理基础 彩色空间与灰度化 图像获取是图像处理的第一步,通过USB摄像头获取的图像一般是与人类视觉图像相仿的彩色图像。彩色模型(也成为彩色空间或彩色系统)的目的是在某些标准下用通常可以接受的方式方便地对彩色加以说明。本质上,彩色模型是坐标系统和子空间的说明,其中,位于系统中的每种颜色都由单个点表示。 在数字图像处理中,实际中最通用的面向硬件的模型是RGB(红、绿、蓝)模型,该模型用于彩色监视器和大多数彩色视频摄影机。本课题需要处理的图像即RGB彩色模型的数字图像。 在RGB模型中表示的图像由3个分量图像组成,每种原色一幅分量图像。当送入RGB显示器时,这三幅图像在屏幕上混合生成一幅合成的彩色图像。在RGB空间中,用于表示每个像素的比特数称为像素深度。考虑一幅RGB图像 ,其中每一幅图像都是8比特图像,在这种条件下,可以说每个RGB彩色像素有24比特的深度。 而很多图像处理操作是以灰度图像为基础的,因为将各种格式的图像转变成灰度图多通道的彩色图像变换为单通道的灰度图像后,计算量会少得多。 一幅图像可以定义为一个二维函数f(x,y),其中x和y是空间(平面)坐标,而在任何一对空间坐标(x,y)处的幅值f称为图像在该点处的强度或灰度。一般有分量法、最大值法平均值法加权平均法四种方法对彩色图像进行灰度化。 灰度变换是直接以图像中的像素操作为基础的空间域处理。空间域就是简单的包含图像像素的平面,某些图像处理任务在空间域执行更容易或者更有意义,而且通常空间域技术在计算上更有效,且在实行上需要较少的处理资源。 灰度变换是所有图像处理技术中最简单的技术。 直方图 一幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的一个重要特征。图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少。图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。 具体的说:灰度级范围为[0,L-1]的数字图像的直方图是离散函数h(rk)= nk,其中rk是第k级灰度值,nk是图像中灰度为rk的像素个数。在实践中,经常用成绩MN表示的图像像素的总数除它的每个分量来归一化直方图,通常M和N是图像的行和列的维数。因此,归一化后的直方图由h(rk)= nk/MN给出,其中k=0,1,…,L-1。简单地说p(rk)是灰度级rk在图像中出现的概率的一个估计。 直方图是多种空间域处理技术的基础。直方图在软件中计算简单,而且有助于商用硬件实现,因此已经成为实时图像处理的一种流行工具。 边缘检测 边缘检测是基于灰度突变来分割图像的最常用方法。我们从介绍一些边缘建模的方法开始,讨论一下边缘检测的原理和几种方法。 边缘模型根据它们的灰度剖面来分类,一般可以分为台阶、斜坡和屋顶三种模型。下图展示了这三种模型的灰度剖面和理想表示:
实际中。虽然噪声和模糊会导致与理想模型有偏差,但类似与这三种模型的边缘图像并不罕见。因此我们进行边缘检测时,能够根据这几种模型写出边缘数学表达式,这些算法的性能将取决于实际边缘和算法开发过程中所用模型之间的差别。 观察理想斜坡模型及其各阶导数,如右图所示。很容易看出,在斜坡开始和斜坡上各个点处,一阶导数为正。而在灰度区域一阶导数为零。在斜坡开始时,二阶导数为正;在斜坡结束处,二阶导数为负;在斜坡上和恒定灰度区域的各点二阶导数均为零。于是我们可以得出结论,一阶导数的幅值可用于检测图像中的某个点处是否存在一个边缘,二阶导数的符号可用于确定边缘像素位于该边缘亮的一侧还是暗的一边,同时二阶导数零交叉点可用于定位粗边缘的中心。类似的结论可以适用于图像中任何区域的边缘。 根据以上结论,可以得出边缘检测的三个基本步骤: 1、平滑降噪; 2、边缘点检测; 3、边缘定位。 最通用的方法是使用一阶和二阶导数来检测。检测灰度值的不连续性。从梯度来看,根据其微分特性,在恒定灰度区域的值为零,且其梯度值与灰度变化值变化程度相关。要得到一幅图像的梯度,则要求在图像的每个像素位置计算偏导数,当对对角线方向的边缘感兴趣时,我们需要一个二位模板。常用的模板有Sobel模板、Prewitt模板等。使用模板求得各方向响应,再结合合适的阈值,便能够找到图像的边缘。 一些更为先进的边缘检测技术尝试考虑诸如图像噪声和边缘本身特性的因素改进简单的边缘检测,以获得更好的效果。成功的尝试有Marr-Hildreth边缘检测器、Canny边缘检测等。大量的计算机视觉库都有相关算法的集成,在使用时直接调用即可。
2.2.2 基于机器学习的人脸检测与识别 人脸识别技术,作为一种典型的模式识别问题,简而言之,这是首先利用计算机分析人脸图像,进而从中提取有效的识别信息,最后用来辨认身份的一门技术。模式识别主要分为两大领域:决策理论方法和结构方法。第一类方法处理的是定量描绘子来描述的各种模式。第二类方法处理的是由定性描绘子来描述的各种模式。下文所述为本课题所要实现的基于机器学习的人脸检测与识别原理。 机器学习本质是将数据转换为信息——通过从数据中提取规则或模式来把数据转换为信息。在学习了一系列数据之后,我们需要机器能够回答与这些数据有关的问题。就人脸识别而言,假如我们有一个数据库,它是对10000张人脸图像进行边缘检测,然后收集特征,如边缘方向、边缘长度、边缘相对脸中心的偏移度。我么从每张脸中获得一个含有500个数据和500项特征向量。然后我们通过机器学习技术根据这些特征数据创建某种模型。如果我们仅仅想把这些数据分成不同的类(如检测判断是否为人脸),一个“聚类”算法就足够了。如果想学习从人脸的边缘的模式测算他的年龄,甚至识别出他是谁的话,我们则需要一个“分类”的算法。为了达到这个目的,机器学习算法分析我们收集的数据,分配权重、阈值和其他参数来提高性能。这个调整参数来达到目的的过程被称为“学习”(learning)。 机器学习用到的大量的原始数据一般会分为三部分使用,即训练集、验证集和测试集。我们利用训练集来训练我们的分类器,学习人脸模型,训练结束后,我们用测试集来测试检测识别人脸。验证集常常在开发训练分类系统时使用。有的时候测试整个系统是一个太大的工作。我们需要在提交分类器进行最终测试之前调整参数。即当训练完之后,我们尝试性的提前用验证集来测试分类器效果。只有对分类器性能感到满意,才用测试集做最后的判断。 基本上,所有机器学习算法都使用特征构成的数据向量作为输入。在本课题中,人脸识别的最终目标是能够从摄像头获取的图像中检测人脸,并最终识别出作者本人。因此所有的训练集、验证集和测试集数据都是通过摄像头获取,并通过必要的预处理工作,提取出高质量的人脸数据用于训练和测试。 数据准备好后,下面就是选择分类器了。分类器不存在“最好”,但如果给定了特定的数据分布的话,通常存在一个最好的分类器。一般分类器的选择需要考虑计算速度、数据形式和内存大小。对于人脸检测和识别这类不需要很快训练而需要准确度高、判断快的任务,神经网络可以满足要求,但性能更好的选择是boosting和随机森林算法。 Boosting是多个分类器的组合。最终的分类决策是由各个子分类器的加权组合来决定的。在训练时,逐个训练子分类器,且每个子分类器是一个弱分类器(只是优于随机选择的性能)。这些弱分类器由单变量决策树组成,被称为树桩,而且还根据识别精度学习“投票”的权重。当逐个训练分类器的时候,数据样本的权重被重新分配,使之能够给与分错的数据更多的注意力。训练过程不停地执行,直到总错误低于某个已经设置好的阈值。为了达到好的效果,这种方法需要很大数据量的训练数据。 综上所述:人脸识别由图像获取、人脸检测部位、图形预处理、特征提取和选择、训练和识别六大功能模块组成。 本课题用到的Haar人脸检测分类器便是巧妙地使用了boosting算法,建立了boost筛选式级联分类器。具体实现方法将在第三章相关章节介绍。通过调用训练的到的xml文件,人脸识别的难题便迎刃而解了。 2.3 本章小结 本章总体介绍了本次毕业设计中绝大多数内容的基本原理,是编程实现各功能的理论基础。首先着眼于图像获取功能,比较了目前常用的图像获取技术的特定,从而的得出应选用USB摄像头完成本课题的图像获取部分。接下来,从USB设备与上位机(PC)的通信的角度入手,介绍了Windows操作系统下,如何驱动USB摄像头,以获取高质量的数字图像。最后介绍了一些图像处理操作,如灰度化、直方图边缘检测等,的基本原理。着重介绍了人脸识别功能。 接下来,我们将在本章原理的基础上,设计软件实现本课题的所有功能。
- 基于Python的软件设计与编程 本课题使用Python作为编程语言。诞生于1989年的Python语言,作为第四代计算机编程语言 ,具有卓越的通用性高效性、平台移植性和安全性,同时又因其功能强大的解释性、交互性和面向对象编程的特性,既简单易学、又清晰高效,成为当下极为流行的编程语言之一。 Python代码很容易阅读和编写,并且非常清晰没有什么隐秘的。Python是一种表达能力非常强的语言, 这意味着, 在设计同样的应用程序时, 使用Python进行编码所需要的代码量远少于其他语言的代码量。目前Python官方网站版本已经更新至Python 3.6.4和Python 2.7.14,强大的标准库奠定了Python发展的基石,丰富的第三方库保证了Python不断发展的,其开源特性和活跃的社区更是提供了强大的发展动力。 Python自带的IDLE,精简又方便,不过一个好的编辑器能让python编码变得更方便,更加优美些。常用的Python编译器有PyCharm、Sublime等。不过本课题选用Visual Studio Code作为编译器。这是微软公司发布的一款跨平台编辑器,轻便又易用。 当我们搭建好Python开发环境,安装好编译器以后,就可以着手开始软件编写了。接下了一整章的内容,我们将详细介绍如何基于Python语言实现本课题的所有功能。
3.1 图形用户界面设计 图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。在目前的软件设计过程中,用户界面的设计是相当重要的部分,美观、实用、大方的用户界面,能够极大的提高用户体验和软件亲和力。 本课题的所有功能,最终都将呈现在GUI上,所以在软件总体设计阶段,对GUI界面的设计是首当其冲的。本次毕业设计软件界面的主要功能结构设计如下图所示:
作为一款成熟的软件,标题栏、菜单栏、中心窗口是必不可少的。图像获取和处理的结果将直接在窗口中展示,实时参数、实时图像、灰度图像、边缘检测图像和灰度直方图等。而各种功能的调用除了可以在菜单栏找到外,在中心窗口的合适位置也将放置部分按钮以方便用户操作。而相对复杂的设置等,会通过弹出对话框的形式处理。同时,状态栏将会实时展示程序的各种运行状态。具体实现见3.5节。 3.2 程序结构设计 图形用户界面设计与程序结构设计是互为表里的。或者出,程序结构设计是软件设计最本质、最核心的内容。徒有界面而内部逻辑结构混乱的软件一无是处。 程序框图是展现程序结构最直观、最清晰的方式,所以我首先给出该软件总体的结构框图如下:
本程序充分继承了Python语言面向对象编程的优势,各模块之间相互独立又彼此联系,同时GUI编程是采用了界面显示与业务逻辑分开的思想,既结构清晰又便于软件维护更行。为了使条例更清晰、也限于篇幅,上图仅着重展现了程序各模块之间的相互关系。各模块内部逻辑,将在下文分别给出。
3.3 利用OpenCV获取图像 3.3.1 从摄像头获取图像 如2.1节所述,在Windows操作系统下调取摄像头是一件牵涉到应用程序、驱动程序、硬件接口等的相当复杂的事情,但使用OpenCV让它变的简单起来。 OpenCV在HigeGUI模块中做了很多工作,整合了DirectShow等等,使我们在获取摄像头图像时不需要考虑这些问题,只需要调用其封装好的接口,便能获取摄像机图像序列,像一般的图片或视频文件一样进行处理。 本次毕设中用到的VideoCapture类,便是OpenCV的HigeGUI中的获取视频图像的常用工具。在Python中的调用方式主要有一下两种: cv2.VideoCapture(filename) → cv2.VideoCapture(device) → 前者用于从文件中获取视频图像,”filename”即视频文件获取路径及名称。后者即我们需要用到的读取摄像头视频的形式,”device”是已加载的摄像头设备的ID,如果仅仅连接了一个摄像头设备的话,只需输入“0”即可默认选中。如果我们想要允许用户自主选择的话,可以输入参数“-1”,这样在程序运行时会自动弹出一个对话框,列出所有可供选用的摄像头设备。 本课题中,切换摄像头功能的实现是通过循环输入设备ID的列表来实现的,其程序程序框图如右图所示。这样的话,我们需要判断使用该ID的设备是否存在。于是用到了VideoCapture类如下方法: cv2.VideoCapture.isOpened() → flag 该方法的返回值是一个布尔值,即当摄像头成功开启的话,返回True,否则返回False。 之后,我们只需要再次调用VideoCapture中的另一个方法: cv2.VideoCapture.read([image]) → successFlag, image 便能够从所选中的摄像头中获取当前帧了。 当然,从摄像头获取图像时有诸多属性参数是有必要进行一些调节的,这个操作我们同样可以使用OpenCV来完成。 在此之前,有一点还是需要明确的:OpenCV虽然十分强悍,但它本质上仍是计算机视觉库,而不是视频流编码器或者解码器。之所以将视频获取这一部分做的强大一些,只是为了更方便后续的处理。而我选用OpenCV一方面是因为其方便易用的特点,更重要的是因为它能够满足本次毕业设计对摄像头操作的需求。如果想要突破限制实现功能更强大的多媒体功能的话,OpenCV并不是一个好的选择。 3.3.2 摄像头相关参数获取与设置 我们在使用USB数字摄像头获取图像的时候,在不同的外部环境条件下,有一些属性参数——如亮度、对比度等——是需要随时做出调整的。当然,目前多数摄像头都是可以自动调节的,但是针对不同的图像获取需求,对属性参数进行手动设置还是不可或缺的。 不同型号摄像头可调节的参数是各不相同的,有些高端摄像头可调参数甚至多达上百个。就一般需求而言,最常用到的属性参数,无非就是亮度、对比度、饱和度、增益、锐度、白平衡、色调、灰度系数等等。对于这些参数,我们同样可以通过OpenCV的VideoCapture类来获取和设置: cv2.VideoCapture.get(propId) → retval cv2.VideoCapture.set(propId, value) → retval 前者用于参数值获取,后者用于设置。其中,”propID”即属性标识符(Property identifier),部分可选项及其含义列于下表:
cv.CAP_PROP_FRAME_WIDTH Width of the frames in the video stream. cv.CAP_PROP_FRAME_HEIGHT Height of the frames in the video stream. cv.CAP_PROP_FPS Frame rate. cv.CAP_PROP_BRIGHTNESS Brightness of the image (only for those cameras that support). cv.CAP_PROP_CONTRAST Contrast of the image (only for cameras). cv.CAP_PROP_SATURATION Saturation of the image (only for cameras). cv.CAP_PROP_HUE Hue of the image (only for cameras). cv.CAP_PROP_GAIN Gain of the image (only for those cameras that support). cv.CAP_PROP_EXPOSURE Exposure (only for those cameras that support). cv.CAP_PROP_CONVERT_RGB Boolean flags indicating whether images should be converted to RGB.
不过对于属性参数可调的范围,OpenCV并未给出确定的方法。不过我们可以通过循环设置参数值的方法,找到上下限。 摄像头参数设置的功能通过程序弹出对话框的方式实现,因为涉及到GUI编程的知识,更详细介绍和程序结构示意图将在3.5.3节中呈现。
3.3.3 保存图像和视频 将从摄像头获取到的图像保存到本地相对来说就容易多了,再次仅给出所使用的OpenCV方法: retval, buf = cv.imencode(ext, img[, params]) 具体的用法读者可以从OpenCV的官方文档中找到详尽的叙述。 保存视频则用到了一个新的类: cv2.VideoWriter([filename, fourcc, fps, frameSize[, isColor]])→ 使用所要保存的视频的文件名、格式、帧率、画幅、色彩的创建一个VideoWrite类后,再按照帧率读取摄像头图像存入即可。如3.3.1节末尾所述,在Windows系统下,其本质是集成了FFMPEG和VFW来实现时候视频操作,局限颇多,比如视频格式有限且不能收取音频等。但对于图像获取的需求来说已经足够了。 关于定时将读取当前帧并存取,用到的是GUI编程多线程中QTimer模块,同样的,将留待3.5.4节中再做详述。 3.4 使用OpenCV进行图像处理 在第二章中,我们已经详细的讨论过了需要进行的图像处理及其原理,本节内容则是在实际编程过程中,如何使用OpenCV来便捷高效的完成这些操作。其中,灰度化、直方图、边缘检测等相对基础的操作不会占用太多篇幅,重点将会放在第二部分人脸检测与识别上。 3.4.1 基本图像处理 色彩空间变换与灰度化 灰度化是彩色空间变换的一种。在OpenCV中,函数cv2.cvtColor可以将图像从一个颜色空间(通道的数值)转换到另一个,其用法如下: dst=cv.cvtColor(src, code[, dst[, dstCn]]) 其返回值为转换后的图像,具体转换操作由参数code来制定,下表列出了此参数的部分取值: Code 解释 cv.COLOR_BGR2BGRA 在RGB或BGR图像中加入alpha通道 cv.COLOR_RGB2BGRA cv.COLOR_RGB2BGR 在RGB或BGR色彩空间之间转换 cv.COLOR_BGR2RGB cv.COLOR_RGB2GRAY 转换RGB或者BGR色彩空间为灰度空间 cv.COLOR_BGR2GRAY 灰度化过程中用到了cv2.COLOR_BGR2RGB、cv2.COLOR_BGR2GRAY,即将摄像头获取到的BGR彩色空间的帧图像转换至OpenCV图像处理常用的RGB空间后,再转换至灰度空间,完成灰度化。灰度化效果如下图所示:
灰度化是图像处理最基础的工作,接下来的边缘检测、直方图,甚至人脸检测与识别,都将在灰度化得到的灰度图像的基础上进行。
边缘检测 OpenCV中常用于边缘检测的是Canny边缘检测法。Canny算子首先使用高斯平滑滤波器卷积降噪;接着在x和y方向求一阶导数,按照sobel滤波器的步骤来操作,计算梯度幅值和方向,梯度方向一般取0度、45度、90度、135度这4个可能的角度之中达到局部最大值的点组成边缘候选点;最后,Canny算法最重要的一点就是运用滞后阈值来试图将独立边的候选像素拼装成轮廓,这需要两个阈值(高阈值和低阈值):若某一像素位置的幅值超过高阈值,该像素被保留为边缘像素;若某一像素位置的幅值小于低阈值,该像素被排除;若某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高阈值的像素时被保留。 因此,Canny()函数通过如下格式调用: edges = cv.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]) 其中,threshold1为第一个滞后性阈值,用于边缘连接;threshold2为第二个滞后性阈值,用于控制强边缘的初始段;高低阈值比在2:1到3:1之间。 当高低阈值分别取不同值时,从下图可以看出边缘检测的不同效果:
灰度直方图 直方图的计算是很简单的,无非是遍历图像的像素,统计每个灰度级的个数。在OpenCV中封装了直方图的计算函数calcHist,为了更为通用该函数的参数有些复杂,其声明如下: hist=cv.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) 该函数能够同时计算多个图像,多个通道,不同灰度范围的灰度直方图。使用该函数可以得到一个数组列表,包含所求灰度级范围内不同灰度级的像素个数,进而可以有多种方式使用这些数据绘制直方图,我们将会在3.5.5节中再做讨论。 3.4.2 人脸检测与识别 人脸检测与识别是数字图像处理中比较高级的玩法,且目前十分流行。从第二章可以看到,其原理是相当复杂的。不过,如果借用强大的计算机视觉库OpenCV的话,实现起来会容易的多。 人脸检测与人脸识别 OpenCV的CV库提供的机器学习算法“Hear分类器”可以用于人脸检测。这个物体检测方法巧妙的使用了Boosting算法。OpenCV提供正面人脸检测器,它的检测效果非常好。 Haar分类器是一个基于树的技术,它是首先由Paul Viola和Michael Jones设计的boost筛选式级联分类器,又称为Viola-Jones检测器。它使用Haar特征,更准确的描述是类Haar的小波特征,该特征由矩形图像区域的加减组成。 OpenCV包含一系列预先训练好的物体识别文件,存储于OpenCV安装目录的如下路径:…\opencv\sources\data\haarcascades,其中本次毕业设计中使用的是正面人脸识别效果最好的模型文件”haarcascade_frontalface_alt2.xml”。
以上我们已经知道怎么加载和运行一个预先训练并存储在xml文件中的沉降分类器以实现人脸检测的功能。现在我们转到怎么训练分类器来进行人脸识别。我们可以使用OpenCV的Haartraining应用程序,它从给定的训练集训练出分类器。训练一个分类器的4个步骤如下:
1、收集打算学习的物体数据集——在这里,指的就是大量的鄙人正面人脸图片了。如果希望分类器充分发挥作用,则需要手机很多高质量的数据(1000—10000个正样本)。高质量指已经把所有不需要的变量从数据中除掉。将它们存储在一个或多个目录下面,并通过一个文本文件以固定形式建立索引。 2、使用辅助工具createsamples来建立正样本的向量输出文件。通过这个文件,便可以重复训练过程,使用同一个向量输出文件。通过这个文件,便可以重复训练过程,使用同一个向量输出文件尝试各种参数。 3、Viola-Jones级联是一个两类分类器:它只判断图像中的物体“是”或者“否”与训练集相似。我们已经说明怎么收集和处理正样本。现在我们说明怎样收集和处理反样本。任何没有我们感兴趣的物体的图像都可以作为反样本。最好从我们需要测试的数据中选取反样本图像。比如,本次毕业设计将要从摄像头获取的图像中识别的是作者本人,故可以使用摄像头图像中不包含作者的帧作为反样本。同样的,我们把反样本放在一个或几个路径下面,并建立索引文件。 4、训练。使用OpenCV命令行训练得到xml分类器。根据数据集的大小,即使在速度比较快的计算机上面,训练也可能会花费几个小时甚至更多的时间。
FaceRecognizer这个类目前包含三种人脸识别方法:基于PCA变换的人脸识别(EigenFaceRecognizer)、基于Fisher变换的人脸识别(FisherFaceRecognizer)、基于局部二值模式的人脸识别(LBPHFaceRecognizer)。也可以用save 和load对已经训练好的数据进行储存和读取。
3.5 PyQt 5和GUI编程 在软件设计过程中,图形用户界面(GUI:Graphical User Interface)的设计相当重要。美观、易用的用户界面能相当大的提升软件质量和使用量。Python最初作为一门脚本开发语言,并不具备GUI功能。但由于其自身的良好的扩展性,目前已经有相当多的GUI控件集可以在Python中使用了,经常用到的有PyQt、Tkinter、wxPython等,其中PyQt是Qt框架专门为Python提供的GUI控件集,兼具C++的高效和Python的优雅,同时因其开源的特性,受到越来越多软件开发者的青睐。因此,本次毕业设计选用PyQt目前的最新版本PyQt 5来进行图形用户界面的编写。 下面将对本次毕业设计中用到的PyQt 5控件和在GUI上实现各功能的方法一一介绍。 3.5.1 QMainWindow窗口控件 PyQt 5中的窗口类有QMainWindow、QWidget和QDialog等,可以直接使用,也可以继承后再使用。 QMainWindow主窗口最常用的窗口类。如果一个窗口包含一个或多个窗口,那么这个窗口就是父窗口,被包含的窗口就是子窗口,没有父窗口的窗口就是顶层窗口,QmainWindow就是一个顶层窗口,它包含很多界面元素,如菜单栏、工具栏、状态栏、中心窗口等,如右图所示。QmainWindow不能设置布局,而是通过setCentralWidget()函数来设置中心窗口。 在本次毕业设计中,QMainWindow是实现3.1中所设计的图形用户界面的基础,而具体控件的绘制,我们将使用Qt Designer来完成,它提供了一个可视化的GUI编程方式,可以通过拖曳的方式加入标签、按钮、文本框等各个控件并设置相关属性和布局。进而实现显示与业务逻辑的分离,相关内容将在3.5.6节中详述。 而PyQt中对象之间的通向使用的是信号(Signal)与槽(Slot)的方式。我们只需在逻辑文件中为菜单、按钮等关联对应的槽函数即可。 3.5.2 在PyQt界面上显示实时画面 在用户界面上显示实时画面是本次毕业实际GUI编程的核心功能。 PyQt 5中有显示视频的模块QMovie,但更多的是用与加载GIF动画效果的,对于从摄像头获取的实时图像显然不是一个好的选择。而显示图片则相对简单的多——使用最常用到的标签对象QLabel类中的setPixmap()方法即可。从图片和视频的关系上,我们很自然的可以想到,如果按照一定的时间间隔不断刷新同一标签上显示的画面,岂不是就实现了实时画面的显示了么?而且这与前文所述的从摄像头获取图像的操作也是一致的,刷新图像的频率也即视频的帧率,故此二者可同步进行。 一般情况下,应用程序都是单线程运行的,但是对于GUI程序来说,单线程有时候满足需求。比如在实现实时图像显示时,主窗口循环相应菜单、按钮等操作占用了主线成,而我们想要按一定频率刷新画面,也是需要不断运行的,这样的话在执行过程中整个程序就会卡顿甚至被Windows系统关闭。要解决这种问题就涉及多线程的知识了。 PyQt多线程技术涉及三种方法,其中一种是使用计时器模块QTimer;一种是使用多线程模块QThread;还有一种是使用事件处理的功能。对于在应用程序中周期性地执行某项操作,定时器QTimer是一个好的选择。 QTimer的使用也非常简单:在引入QTimer类,实例化一个QTimer对象,将超时信号timeout连接到对应的槽函数,最后根据帧率设置时间间隔并启动定时器即可,即: self.timer = QTimer(self) #实例化一个定时器 self.timer.timeout.connect(self.CameraPicture) #超时信号连接至槽函数 self.timer.start(30) #按照帧率设置定时并启动 类似的,实时处理过的灰度图像和边缘检测图像也可以在同一个定时器的控制下显示在界面上。而视频录制的功能则需要实例化一个新的定时器来完成,方式类似。 更关键的问题在于该定时器所对应的槽函数self.CameraPicture()。每次定时器调用槽函数后,需要完成获取摄像头帧、灰度化、直方图、边缘检测、人脸识别等一系列图像获取和处理的工作,这对各部分算法的效率有一个较高的要求。所幸,OpenCV足够高效的完成了这个任务,相关算法已在对应章节讨论过了,下图给出了从摄像头获取当前帧到界面显示当前画面之间的程序结构框图:
3.5.3 弹出对话框的使用 为了更好的实现人机交互,一些不适合堆在主界面上的功能往往会使用对话框来完成。本次毕业设计有多处用到了弹出对话框: 一是对摄像头参数进行设置;因为需要设置的参数较多,如果放在主界面上的话,一来显得拥挤凌乱,二来也不方便参数调整,故选用对话框实现。对话框与QmainWindow主窗口本质是一样的,因此也是使用Qt Designer完成界面文件的设计,然后通过继承、实例化,并在主窗口类中将该窗口中调节参数用的滑动条与对应槽函数连接即可。该对话框流程图如下:
只需要将对话框槽函数与对应的信号(如按钮、菜单等)相连,当该信号发出时,就会弹出对话框进入该窗口循环。 二是对图像获取设置对话框,该对话框实现了对拍照、录像设置,包括对图片和视频的保存位置的设置、使用复选框供用户自主选择是否保存实时图像、灰度图像或边缘检测图像以及对拍摄视频的帧率设置等。具体实现和调用的方法与摄像头参数设置对话框类似,不再赘述。 另外,在PyQt 5中还定义了一系列的标准对话框来完成特定场景下的功能,主要有QMessageBox、QFontDialogg、QFontDialog、QInputDialog等。比如用于打开和保存文件的标准对话框QFileDialog,在图像获取设置对话框中对图像视频的保存位置进行设置时就用到了它来获取文件目录: self.filenameImage = QFileDialog.getExistingDirectory(self,None) 返回值为字符串格式的文件目录,使用非常方便。而QMessageBox是一种通用的弹出式对话框、用于显示消息,允许用户通过点击不同的标准按钮对消息进行反馈。在本毕业设计中,提示、关于、警告、报错等功能都使用其来进行交互。 3.5.4 利用按钮实现暂拍照、录像和暂停功能 基于前文的分析,拍照、录像和暂停功能的实现方法其实都已经交待清楚了。简单总结一下:它们是使用按钮的控件的控制下,通过对定时器启停的控制来控制录像和实时画面的开始和结束(仅录像)、暂停和继续,通过对从摄像头获取的当前帧的操作,来完成图像的保存和视频帧的保存的。在本节,我们主要从编程逻辑的角度,给出拍照和录像方法的程序框图如下:
3.5.5 在PyQt中应用Matplotlib绘制灰度直方图 在3.4.1节中我们介绍了如何使用OpenCV统计灰度图像的灰度直方图,得到的是一个包含256个成员的一维数组,每个数据对应该灰度级的像素个数。那么,该如何利用此数据在我们的用户界面上呈现出直方图来呢?在这里,我们用到了一个Python的绘图模块Matplotlib。 Matplotlib是Python最著名的绘图库,它提供了一整套和MATLAB相似的命令API,十分适合交互进行制图。它提供了上百种类型的绘图源代码,这些图像基本可以满足我们日常的绘图需求。将Matplotlib嵌入到PyQt中后,我们便无需通过底层方式手动实现PyQt的绘图功能了。 直方图是非常基础的图像,只许在创建的画布中调用函数: axes.plot(histr) 其中变量histr是我们如前文所述计算获得的直方图数据,便可以绘制出如右图所示的直方图图像了。接着3.5.2节中显示实时画面同样的方法不断重绘,即可得到与实时画面同步的灰度直方图了。 更值得关注的是如何将Matplotlib图像嵌入到PyQt 5界面中。我们用到的“设置提升的窗口控件”的方法。 具体来说,我们需要将绘图函数封装为一个绘图类,然后调用该接口,传入相应参数即可。过程如下图所示: “设置提升的窗口控件”可以使用Qt Designer完成,而Qt Designer的相关知识将在下一节介绍。
3.5.6 使用Qt Designer实现界面显示与业务逻辑的分离 在PyQt 5使用前文介绍的各中控件制作UI界面一般有两种方法:纯代码编写方式和使用UI制作工具。 Qt Designer,即Qt设计师,是一个专门用来制作PyQt程序中UI界面的强大的、灵活的可视化GUI设计工具,它生成一个扩展名为.ui的UI界面文件,并可以通过命令将.ui文件转换成.py格式的文件,并被其它Python文件调用和继承。由于此.py文件是由.ui文件编译而来的,因此当.ui文件变化时,.py文件也会随之变化。我们把这个由.ui文件编译生成的.py文件称为界面文件,而调用该界面文件的.py文件称为逻辑文件或业务文件。这样一来,我们的程序代码便被清晰的区分为了界面文件和逻辑文件两部分,即所谓实现了“界面与逻辑的分离”(或称之为“显示和业务的分离”)。 界面与逻辑分离最大的好处就是当我们想要更新界面时,只需对.ui文件进行更新并编译成对应的.py文件;而逻辑文件只需视情况做出少量的调整即可。这无疑极大的便利了程序的编写与维护。不过,想要做出华丽的界面还是需要一些代码的。因此在本次毕业设计中,采用了Qt Designer为主,纯代码编写为辅的GUI制作方式。 Qt Designer使用起来非常简单,只需通过简单的拖曳和点击,加入我们用到的控件并设置相应的布局等,即可完成复杂的界面设计。如下图所示: 接下来,将.ui文件编辑为.py文件可以使用PyQt 5提供的命令行工具pyuic5轻松实现。例如在本次毕业设计中,需要将名为“CIAP_GUI.ui”的文件编译成名为“CIAP_GUI.py”的文件,则我们要在当前文件夹下进入命令提示符窗口,并输入命令: pyuic5 -o CIAP_GUI.py CIAP_GUI.ui 便可以在同一文件夹下获得对应的.py界面文件了。 3.6软件打包与测试 我们开发的软件不只是给自己使用的,当我们将软件提供给用户的时候,使用者可能并不清楚如何运行.py文件,这时就有了把.py文件编译成.exe文件的以便在未配置Python环境的PC上运行的需求。在此,我们是使用PyInstaller打包项目生成EXE文件的,其原理其实就是把Python解释器和脚本打包成一个可执行文件。 PyInstaller的使用非常简单。因为PyInstallerjin已经在Scripts目录下生成了可执行的pyinstaller.exe文件,所以在命令行窗口中进入需要打包的代码所在的目录下,然后运行下面的命令: Pyinstaller [opts] yourprogram.py 可选的参数有: -F,-onefile,打包生成一个EXE文件。 -D,-onedir,创建一个目录,包含EXE文件,但会依赖很多文件(默认选项) -c,-console,-nowindowed,使用控制台,无窗口(默认) -w,-windowed,-noconsole,使用窗口,无控制台。 输入指令后,首先PyInstaller会分析该脚本所依赖的其它依赖,然后进行查找,并复制,把所有相关的依赖都收集起来并进行加密处理,包括Python解释器,最后把这些文件放在一个目录下,或者打包一个可执行文件中。然后就可以直接运行所生成的可执行文件了。 于是根据课题需求,对于本次毕业设计名为CIAP.py的文件,我们可以使用命令: pyinstaller -D -w CIAP.py 来打包生成EXE文件。 需要注意的是,程序需要的一些资源文件有时候需要我们手动添加至程序目录下。移植到其它设备上时,有时候难免会因为缺少某些文件不能运行。因此我们需要不断测试,以修改完善程序。 3.7 本章小结 本章从软件的整体设计到各部分功能能具体实现方案详细的记述了使用Python语言完成整个软件设计的主要内容。主要部分为计算机视觉库OpenCV和GUI库PyQt 5的使用。其中,OpenCV是实现各功能模块的主要工具,从图像获取,到基本图像处理再到人脸检测识别都离不开它。PyQt 5则是GUI编程的主要工具,串联和整合了各个模块,通过图形界面呈现给用户并供其使用。最终经过测试、打包,生成可执行的EXE文件。 4. 结论
参考文献 致谢