《Arduino计算机视觉编程》一1.2 解决计算机视觉问题-阿里云开发者社区

开发者社区> 华章出版社> 正文

《Arduino计算机视觉编程》一1.2 解决计算机视觉问题

简介:

####本节书摘来自华章出版社《Arduino计算机视觉编程》一书中的第1章,第1.2节,作者[土耳其] 欧森·奥兹卡亚(zen zkaya),吉拉伊·伊利茨(Giray Yilliki),更多章节内容可以访问云栖社区“华章计算机”公众号查看。

1.2 解决计算机视觉问题

解决任何复杂的问题,比如计算机视觉问题,非常重要的一点就是通过理解每一步的目的来把问题分解成简单和可实现的子步骤。本章的目的是向你展示如何解决计算机视觉问题,以及如何用一个通用模型来对问题建模。
本书讲解的实用计算机视觉系统的架构,由Arduino系统和OpenCV系统组合而成,如下图所示:


7410cbd60b07fe25d2c4078713be6eddb79eb15b

Arduino只负责从环境中收集感官信息,比如温度、湿度,然后把这些信息发给视觉系统控制器的OpenCV系统。视觉系统控制器和Arduino之间的通信可以是有线的,也可以是无线的,Arduino对于这两种方式处理起来都很容易。视觉系统处理完从Arduino和网络摄像头传过来的数据后,会检测或者识别出一个结论。比如,它设置可以识别出你的脸。下一步是根据这个结论来给Arduino系统发送指令,让Arduino采取合适的动作。这些动作可能是开风扇来让环境冷却,移动机械臂来给你递咖啡等。
视觉控制器可以是台式电脑、笔记本电脑、手机,甚至是树莓派或者Beaglebone这样的迷你电脑!OpenCV可以在所有这些平台上运营,所以基本原则在这些平台上都是有效的。迷你电脑也可以做部分Arduino的工作。
任何计算机视觉系统都由一系列边界清晰的设计模块组成,它们依次是数据采集、预处理、图像处理、后置过滤、识别(检测)和驱动。本书将针对这些步骤介绍一些详细实用的方案。我们把这些步骤对应到平台上具体实现,就可以得到一个计算机视觉系统的通用流程图。在下图中,你可以看到计算机视觉系统的通用处理流程:


01e6b08cacf2694cbef7844b85090ae671eab1cd

1.2.1 数据采集

可以看到,视觉系统处理的第一步是数据采集,通常是收集来自环境的感官信息。从视觉控制器的角度来看,主要有两个数据源:相机和Arduino系统。
相机是模仿人类视觉系统的终极传感器并与体系中的视觉控制器直接相连。通过使用OpenCV的数据采集功能,视觉控制器可以从相机中读取视觉数据。数据可以是快照图片或者由一帧帧数据按时间组成的视频。相机的种类并没有什么限制。
最根本区分相机类型的方法是根据输出信号是模拟信号还是数字信号进行区分。本书例子中所采用的相机都是数码相机,因为处理环境和处理操作本身都是数字的。图片的基本组成元素被称为像素。在一张数码图片中,一个像素或者说图片元素是光栅化图片上的一个物理点,或者是全屏光点式显示设备上的最小寻址单位。所以它是屏幕上图片的最小控制单位。
相机还可以按颜色感应能力进行分类。RGB相机既能感觉主要颜色成分也能感应这些主要颜色的混合。灰度相机能感应到的场景都是灰色的。因此,这种相机提供的不是颜色信息,而是场景的形状信息。最后,二进制摄像机识别的场景只有黑色和白色。顺便说一下,二进制相机的一个像素只有2个值,即黑色和白色。
相机的另外一种分类方法是基于它们的通信接口。比如USB相机、IP相机、无线相机,等等。相机的通信接口也直接影响相机的可用性和功能。在家里我们一般用带USB接口的网络摄像头。在使用时通常不需要外部电源或者其他外部设备,所以它很适合用于图像处理。相机也有分辨率等属性,我们会在后面的章节处理相机属性。
最常部署为网络摄像头的USB相机提供的是2D图片。除了2D相机系统,我们现在有可以检测场景中每个元素深度的3D相机系统。三维摄像机系统中最著名的可能是Kinect,如下图所示:


994054e0ec4e32acd6434773348c09735527e328

OpenCV支持各种类型的相机,并且可以通过非常简单的接口从这些相机中读取视觉信息。在随后的章节我们将介绍相关的例子。请记住,图像采集是视觉处理流程最基本的步骤,我们有很多选择。
一般来说,我们还需要获取相机以外的信息来分析我们周围的环境。其中一些信息是和其余四个感官相关的。此外,有时我们需要超出人体感知能力的额外信息。我们可以通过Arduino传感器来获得这些信息。
想象下你要构建一个面部识别自动开关门的项目。系统可能会由敲门声或者门铃触发。你需要一个声音传感器来对敲门声或者门铃声做反应。这些信息很容易由Arduino收集到。让我们添加一个指纹传感器,使其更加安全!通过这种方式,视觉系统可以结合Arduino和相机的数据来得出关于场景的结论。
总之,视觉系统控制器可以通过相机和Arduino(使用传感器)来获取详细的环境信息。

1.2.2 预处理

预处理的意思是把东西准备好以便进行处理。它可以包含各种各样的子步骤,但是基本原理是一样的。我们现在开始解释什么是预处理以及它的重要性。
首先,让我们明确一件事。这一步的目的是把收集到的视觉数据整理好准备进行处理。计算机视觉系统需要预处理的原因是,原始的数据一般会有很多噪音。图片数据是从相机得到的,里面有很多区域是不需要的,有时候由于振动、运动等因素会得到一个模糊的图像。在任何情况下,最好都过滤一下图片来让它对我们的系统更加有用。比如,如果你想检测图像中的一个大红球,你就可以删除那些小点,你甚至可以移除那些不是红色的部分。所有这些过滤操作都会让后续操作更简单。
一般来说,相机都在数据获取的时候做了过滤,但是每一个相机都有不同的预处理功能,甚至有一些相机做了防振动处理。但要注意的是内置功能的增加也会带来成本的增加。所以最好在内部通过OpenCV进行这些过滤处理。顺便说一句,即使使用的是廉价的设备比如网络摄像头,也能设计出一个鲁棒的视觉系统。
同样的处理也适用于传感器数据。在真实环境中我们得到的总是有噪音的数据,所以噪音应该从传感器的真实数据中移除。这些噪音部分是由环境引起的,部分是由传感器的内部结构引起的。在任何情况下,数据应该被准备好以便进行处理。本书将给出实际可行的方法来达到这一目标。
图像数据的复杂性远远超过任何常规的传感器,比如温度传感器、湿度传感器,这很好理解。用来表征信息的数据维度也是不同的。RGB图片的每个像素包含三个颜色组件:红色、绿色和蓝色。为了用分辨率640×480来表征一个场景,一个RGB相机需要640×480×3 = 921?600字节。乘以3的原因是每个像素有三个维度。每个像素对应3个字节的数据,1个字节代表一个颜色。为了表征房间的温度,我们一般需要4个字节的数据。这也解释了为什么我们需要更强的设备来处理图像。此外,图像过滤的复杂性也和简单的传感器过滤不同。
但这并不意味着不可以用一个简单的方法来进行复杂的过滤。如果我们知道过滤的目的和过滤参数的含义,就可以更加容易地使用它们。这本书的目的是让你了解过滤的过程和如何更轻松地使用先进的过滤技术。
所以过滤的目的是为了从数据中获取真实的数据信息,这是计算机视觉计算过程中不可或缺的一步。许多计算机视觉项目在开发阶段失败了,就是因为缺少过滤这一层。即使是最好的识别算法,遇到充满噪音和不准确的数据也会失败。所以,请重视数据过滤和预处理。

1.2.3 图像处理的特征提取

计算机视觉项目最让人激动的部分大概就是对场景的自动化解释。为了从图像中提取含义,我们应用了各种各样的图像处理技术。有时候一张图片的信息并不够。在这种情况下,图像帧之间的关系就非常重要。如果这种帧与帧之间的信息会被提取出来,这种处理通常被称为视频处理。许多视频处理应用也包括了对声音信号的处理。因为采用相同的基本原则,视频处理和图像处理区别不大。
理解本章的重点在于逻辑地去看待真实生活中的应用。想象一下你在建一个沿着线行走的视觉机器人。机器人中间上方会有一个相机,它会在白色地板上沿着黑线行走。为了实现这个目标,你需要检测黑线,并找出黑线现在是在机器人的左边还是右边。如果黑线出现在图片的左边部分,你应该让机器人往左走让黑线在中间。同样,如果黑线出现在图片的右边部分,你应该让机器人往右走。如果黑线差不多在图片的中间,你就该让机器人往前走。你也可以检测黑线的方向来提前规划机器人的行进,以便让它的移动更加聪明合理。
在这个例子中,你应该使用图像处理技术来检测图像中的线。你将在本书中看到一系列技术方案,在你解决问题时,这些技术方案将为你指引方向。使用这些技术方案,可以在图像中得到一些可能是线的候选区域。为了有效找到线的候选,你需要在这些候选区域上使用特征提取。通过对特征(属性)的对比,你就可以把真正的线从诸如阴影等噪音中分离出来。
特征提取是一个模式识别和分类的术语,它意味着提取一些可以代表更大数据集的小数据。通过处理图像,我们提取了长度、位置、图像区域等特征。在后面的章节里,我们将用这些特征来检测和识别物体。
从图像中提取有用的小集合数据有一些主要的方法。分割就是针对这种操作的一个术语。
图像分割是把一个数码图像分成多个点集的过程。分割的目的是为了简化问题以及改变图像的表示方式,以一种更容易处理也更有意义的方式表示出来。
更多信息可以在http://en.wikipedia.org/wiki/Image_segmentation找到。
在我们的例子中,线段的候选就是这些图像的分割。
blob分析是对图像分割进行标记的好方法。它对于找到图像中的闭环非常有用。闭环一般对应着图像中的物体。blob分析也是一种图像处理技术,我们会在后面讲到。现在最重要的是理解特征拾取的目的。
从图像提取的信息将会用于计算机视觉系统的下一步流程中。因为这一步将对图像进行抽象概括,所以它对整个计算机视觉系统是否能正确工作非常重要。再一次强调,你不需要了解底层所涉及的复杂计算。相反,你要了解的是何时以及如何使用图像处理技术从场景中得到有价值的小信息块。这正是本书后面章节的专注点。

1.2.4 后处理和后置滤波

在从图像提取出一些有用的信息以后,有时需要做一些更高层次的滤波。从属性的角度出发去除不必要的部分就是一种更高层次的滤波。通常情况下,如果你了解相关项目的需求,这种滤波很容易。
因为这一部分非常简单,通常我们会把它视为图像处理的一部分。因为图像处理的目的是给识别或者检测模块提供一些清晰小块的数据,所以这种处理比较合适。
OpenCV有一个非常好的后处理机制,理解了它的意义我们可以很容易地将其应用在实际场景的例子中。理解后处理的目的更重要。

1.2.5 识别或检测

计算机视觉系统的主要目的是通过解释图像或者图像序列来得到结论。得到结论所使用的方法是识别或者检测。
检测可以被看作识别的一种基本形式。它的目的是检测一个对象或者物体。会有两种类型的结论。一个物体或者时间存在或者不存在。因为结论的二进制本质,使得检测是一个只有两类的特殊分类过程。第一个类别是存在,第二个类别是不存在。“生存还是毁灭,这是个问题。”
识别是一个更复杂的术语,也被称为分类,它的目的是在一个识别过程里将物体分成几个预先分好的类,或者通过学习将物体分类。人脸识别是这方面很好的一个例子。计算机视觉系统通过识别你的脸来确认是不是你。这是一个有多个类别的复杂分类过程。在这个例子中,每张脸是一个类别,所以它非常复杂。但是,感谢OpenCV,我们有很多简单易用的识别机制,即使是处理复杂问题也很方便。
有时执行复杂的算法需要花费大量的时间。但有些时候,需要快速完成,特别是在有实时要求的情况下。在这些情况下,我们会采用一些简单但是有效的决策算法。正如列奥纳多•达•芬奇说,“大道至简,至繁归于至简”。本书还将讲述如何用简单的设计模块设计出健壮的识别系统。
再次重申,你应该牢记识别或者分类的目的,这方面的意识将导引你走向成功。

1.2.6 在现实世界中行动

每个计算机视觉系统都有它的目的。有一些场景是“如果你发现了这个事件(或者物体),那么就执行这个动作”。计算机视觉系统在结束了长而有趣的决策过程后,下一步就是根据结论执行一个动作。这就是计算机视觉系统存在的目的。到目前为止所做的一切都是为了让我们能执行正确的动作。
让我们回忆下寻线行走机器人的例子。机器人检测到线以及线在它的视野中的位置。它还需要判断线的方向。如果机器人仅仅是知道该往哪个方向走但是根本不动,那有什么意义呢?这个例子还展示了决策以后行动的重要性。
视觉控制器管理的物理行动用物理的方式来影响真实世界。这样的例子包括:驱动汽车移动、加热环境、打开一扇门、触发一个设备,等等。要做这些需要依赖Arduino。它有庞大的社区支持,许多设备上开发了很多库并且它真得非常简单易用。也许对于工业设计,你有更好的选择,但是对于概念设计,Arduino非常适合用来执行最后的物理行动。Arduino是一个嵌入式系统,能让困难的工业内容简单易用。我们应该喜欢它!
嵌入式系统最激动人心的是可以用相同的软件开发出不同的物理效果。嵌入式系统会在多个不同的目的中使用矩形波信号。你会在后面的章节里具体了解矩形波信号,现在先认为它是一种调光功能。当你用50%的占空比产生了矩形波信号,这意味着产生了有限时间t以内为逻辑高然后在有限时间t以内为逻辑低的脉冲。该软件将应用相同的调光原理到完全不同的设备上。如果你把这个矩形波信号应用到电动机上,它会以自身一半的最大速度运转。同样,如果你把这个矩形波信号应用到LED上,它的亮度会是最大亮度的一半。即使是在完全不同的物理设备上,我们用相同的软件能够得到相同的行为。所以我们看到了这些用来与世界交互的设备让人激动的特质。如果我们知道如何将它们连接到我们的系统上,一切都没问题了。
本书提出了一种与硬件无关的用软件与世界交互的方法。所以,即使我们遇到的情况是与设备有关的,你也可以在任意的嵌入式设备上应用相同的原则。本书中也有一些非常先进的用Arduino与世界交互的技巧。

1.2.7 连接子模块

在我们提出的方法中,视觉处理过程被划分为一系列独立易实现的子模块。因为每一小块在整个系统的性能表现中都扮演了一个关键角色,每个子模块都应该基于一些简单的规则进行设计开发,这样整个系统才能坚如磐石。
解决任何视觉问题的时候,首先要对问题有个全局的考虑,然后把问题分解成一系列有意义、内部独立的子模块。这种解决方法能让你考虑到问题的细节,并能不受干扰地解决一些子问题。对于建立未来的可视化视觉系统,这是最关键的第一步。下一步就只是把这些子模块连接起来享受你的成果。
本章给出的方法适用于任何类型的计算机视觉系统。但是你应该去不停地实践以便让解决方案落地。让我们来对一个现实生活的例子做一个头脑风暴,这个例子是手势控制的门禁系统。
入口的地方应该有个相机,在门上,这样可以看到任何客人的动作。为了更实用,只有按门铃才会触发运动检测系统。游客按下门铃,展示一个正确的手势,视觉控制器将自动打开门。如果手势错误,则门不会打开。
第一步是数据采集,因为我们需要看到手势,用一个每秒30帧分辨率为1024×768的网络相机就可以实现。
我们把图像转化为二进制格式,然后把图像中比较小的物体都过滤掉。手势会以二进制表示。这样过滤就完成了。
然后我们将执行特征提取来找到图像中手的可能位置。这个问题可以用凸包方法或blob分析来解决,我们稍后来解释这些算法。最后,我们得到了一个带手势候选的图像,如下图所示:


30b0e4ab9a38af364eb7dd884b52755d76879c7c

下一步需要一个手势检测器。我们可以对手指进行骨骼分析比较手指的位置,这样可以对手势分类。
如果是正确的手势,我们会给Arduino门禁控制器发信息,然后它就按限定的时间打开门以便欢迎授权游客!
你可以将这些原则应用到任何问题上以便来熟悉它们。现在不要去关注算法的细节。仅仅是把问题分块然后决定哪些属性可以用来解决问题。
只要你熟悉这套解决方法,本书将告诉你如何实现每一步以及如何找到合适的算法来解决问题。所以,继续用这套方法来解决一个可以识别你的汽车牌号的车库门禁系统。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:

华章出版社

官方博客
官网链接