深入理解OpenCV:实用计算机视觉项目解析(原书第3版)
上QQ阅读APP看书,第一时间看更新

1.4.2 在嵌入式设备上安装OpenCV

有一种非常简单的方法可以在基于Debian的嵌入式设备(如树莓派)上安装OpenCV及其所有依赖项:

不过,这可能会安装来自一两年前的老版本。

要在树莓派等嵌入式设备上安装最新版的OpenCV,需要从源代码上构建OpenCV。首先,安装编译器并构建系统,然后是OpenCV的依赖库,最后安装OpenCV本身。请注意,无论是为桌面系统还是针对嵌入式系统进行编译,在Linux上从源代码编译OpenCV的步骤都是相同的。本书提供Linux脚本:install_opencv_from_source.sh。建议你将该文件复制到树莓派上(例如,使用USB闪存)并运行脚本来下载、构建和安装OpenCV,包括可能的多核CPU和ARM NEON SIMD优化(取决于硬件支持):

注意:如果出现错误,例如,没有接入互联网或依赖包与已经安装的其他东西发生冲突时,脚本将停止。如果脚本因错误而停止,请尝试使用WEB上的信息来解决错误,然后再次运行脚本。脚本将快速检查前面的所有步骤,然后从上次完成的地方继续。注意,根据你的硬件和软件,它可能花费20分钟乃至12小时!

强烈建议在每次安装OpenCV时构建和运行一些OpenCV示例,这样当在构建自己的代码出现问题时,至少会知道是OpenCV的安装问题还是自己的代码问题。

让我们来试着构建简单的edge示例程序。若尝试用以下的Linux命令从OpenCV 2构建它,将会得到以下错误提示:

该错误消息的倒数第二行告诉我们命令行中缺少一个库,因此只需要在链接到的其他OpenCV库旁边的命令中添加-lopencv_imgcodecs。现在,你知道如何在编译OpenCV 3程序时解决问题,并且去查看该错误消息了!正确做法如下:

成功啦!那么,现在你可以运行该程序:

按<Ctrl+C>退出程序。注意,如果是在SSH终端运行该命令,且没有将窗口重定向到设备的LCD屏幕上显示,则edge程序可能会崩溃。因此,若你使用SSH远程运行程序,请在命令前添加DISPLAY=:0:

把USB网络摄像头插入设备,并测试它是否工作:

注意:如果你没有USB摄像头,可用视频文件测试:

现在OpenCV已成功安装在设备上,你可以运行之前开发的Cartoonifier应用程序。将Cartoonifier文件夹复制到设备上(例如,使用USB闪存或使用scp通过网络复制文件夹)。然后,就像在桌面那样构建代码:

运行:

如果一切正常,我们将看到一个运行应用程序的窗口,如下所示:

1.4.2.1 使用树莓派相机模块

虽然在树莓派这样的嵌入式设备上使用USB摄像头,可以方便得如同在桌面上一样,支持相同的行为和代码,但你仍可以考虑使用一个官方的树莓派相机模块(称为Raspberry Pi Cam)。与网络摄像头相比,这个相机模块有一些优缺点。

Raspberry Pi Cam采用特殊的MIPI CSI相机格式,专为智能手机相机设计,能耗更低。与USB摄像头相比,它具有更小的物理尺寸,更快的带宽,更高的分辨率,更高的帧速率和更低的延迟。大多数USB 2.0摄像头只能提供640×480或1280×720每秒30帧的视频,因为USB 2.0对于要求更高速度的摄像头来说太慢了(除了执行板载视频压缩的一些昂贵的USB摄像头),而USB 3.0价格仍然昂贵。然而,智能手机相机(包括Raspberry Pi Cam)可提供1920×1080每秒30帧,甚至Ultra HD(超高清)/4K分辨率。事实上,由于使用了MIPI CSIMIPI CSI:即MIPI Camera Serial Interface(MIPI相机串行接口),是由MIPI联盟下的Camera工作组指定的接口标准。——译者注、兼容ISP的视频处理和GPU硬件,Raspberry Pi Cam v1甚至可以在一个5美元的树莓派Zero上支持高达2592×1944每秒15帧或1920×1080每秒30帧。Raspberry Pi Cam在每秒90帧模式下也支持640×480(例如慢动作)捕获,这对于实时计算机视觉非常有用,因此你可以在每一帧看到非常细微的运动,而不是难以分析的大运动。

但是,Raspberry Pi Cam的电路板很普通,对电子干扰、静电或物理损坏非常敏感(只需用手指触摸小而扁平的橙色电缆就会造成视频干扰甚至永久性损坏相机!)。大扁平白色电缆的灵敏度要低得多,但它仍然对电噪声或物理损坏非常敏感。Raspberry Pi Cam配有一根15cm的非常短的电缆。可以在eBay网站上购买长度在5cm到1m之间的第三方电缆,但50cm或更长的电缆不太可靠,而USB摄像头可以使用2m到5m长的电缆,可插入USB集线器或有源延长电缆,以获得更长的距离。

目前有几种不同的Raspberry Pi Cam型号,特别是没有内部红外滤光片的NoIR版本,因此,NoIR相机可以在黑暗中轻松夜视(如果有一个看不见的红外光源),或者看红外激光或信号的时候也远比内部包含红外滤光片的普通相机更清晰。还有两个不同版本的Raspberry Pi Cam:Raspberry Pi Cam v1.3和Raspberry Pi Cam v2.1,其中v2.1使用更大的广角镜头和索尼800万像素传感器,而非500万像素的OmniVision传感器,它可在低照明条件下更好地支持运动,并且增加了对15FPS的3240×2464视频的支持,在720p时可能支持高达120FPS的视频。不过,USB摄像头有数千种不同的形状和版本,可以很容易地找到专门的摄像头,如防水或工业级摄像头,而你也无须为Raspberry Pi Cam创建自己的定制外壳而发愁。

IP相机也是相机接口的另一种选择,可以向树莓派提供1080p或更高分辨率的视频。而且,IP相机不仅支持非常长的电缆,甚至可以在有互联网的世界任何地方工作。但与调用USB摄像头或Raspberry Pi Cam不同,调用IP相机的OpenCV接口要困难一些。

以前,Raspberry Pi Cam和官方驱动程序与OpenCV不直接兼容。经常需要使用自定义驱动程序并修改代码,以便从Raspberry Pi Cam中抓取帧,但现在可以用以同USB摄像头完全相同的方式访问OpenCV中的Raspberry Pi Cam!由于v412驱动程序的最新改进,一旦加载v412驱动程序,Raspberry Pi Cam就会像普通的USB摄像头一样以/dev/video0或/dev/videol文件的形式出现。因此,传统的OpenCV摄像头代码,如cv::VideoCapture(0)将能够像摄像头一样使用它。

安装树莓派相机模块驱动程序

首先,让我们临时加载Raspberry Pi Cam的v412驱动程序,以确保相机插入正确:

如果命令报错(控制台打印了一条错误信息,它将被冻结或返回除0之外的数字),那么可能是你的相机没有正确插入。关掉再拔掉树莓派电源,再试着接上白色的扁平电缆,对照网上的图片确保插入方式正确。如果方法正确,那么有可能是没有完全插入电缆就关闭树莓派上的锁定卡舌。另外,使用sudoraspi-config配置命令检查之前配置树莓派时是否忘记单击Enable Camera(启用摄像头)。

如果命令成功(命令返回0且控制台无错误打印信息),那就可以将Raspberry Pi Cam的v412驱动程序添加到/etc/modules文件底部,确保启动时始终加载该驱动程序:

保存文件,重新启动树莓派,运行ls/dev/video*查看可用的相机列表。如果Raspberry Pi Cam是唯一插入主板的摄像头,则把它当作默认摄像头(/dev/video0),如果还插入了另一个USB摄像头,那么它要么是/dev/video0,要么是/dev/video1.

使用之前编译的starter_video示例程序来测试Raspberry Pi Cam

若显示相机错误,尝试DISPLAY=:0./starter_video 1。

现在了解了OpenCV中Raspberry Pi Cam的工作,让我们尝试Cartoonifier:

或者另一个相机使用DISPLAY=:0./Cartoonifier 1。

1.4.2.2 全屏运行Cartoonifier

在嵌入式系统中,总是希望应用程序是全屏且隐藏Linux GUI和菜单。OpenCV提供了一个简单的方法来设置全屏窗口属性,但是要确保创建窗口时使用了NORMAL标志:

1.4.2.3 隐藏鼠标光标

即使你不想在嵌入式系统中使用鼠标,鼠标光标也会显示在窗口顶部。要隐藏鼠标光标,可使用xdotool命令将其移动到屏幕最右下角,这样它就不会被注意到,但是若想偶尔插入鼠标来调试设备,它仍然可用。安装xdotool并创建一个简短的Linux脚本在Cartoonifier之前运行它:

在安装xdotool后,创建脚本,用你喜欢的编辑器创建一个名为runCartoonifier.sh的新文件,其内容如下:

最后使脚本可执行:

尝试运行你的脚本,确保其能工作:

1.4.2.4 在启动后自动运行Cartoonifier

通常,在构建嵌入式设备时,你会希望在设备启动后自动执行应用程序,而不是要求用户手动运行应用程序。要在设备完全启动并登录到图形界面后自动运行应用程序,需创建一个autostart文件夹,其中包含以下内容,包括脚本或应用程序的完整路径:

现在,无论何时打开设备或重启设备,Cartoonifier都会开始运行!

1.4.2.5 在桌面与嵌入式系统上运行Cartoonifier的速度比较

代码在树莓派上运行的速度要比在桌面上慢得多!到目前为止,使运行速度更快的两种最简单的方法是使用速度更快的设备或使用较小的相机分辨率。下表展示了Cartoonifier在桌面、树莓派1、树莓派2、树莓派3和Jetson TK1上,素描和绘画两种模式下的一些帧速率和每秒帧数(FPS)。注意速度没有任何额外优化,只在单个CPU内核上运行,时间包括将图像渲染到屏幕的时间。使用的USB摄像头是以640×480运行的快速PS3Eye摄像头,因为它是市场上最快的低成本摄像头。

值得一提的是,虽然Cartoonifier只用了一个CPU内核,但所有列出设备都有四个CPU内核,但树莓派1例外,它只有一个内核。很多x86计算机都有超线程,可以提供大约8个CPU内核。因此,可编写代码来有效地利用多个CPU内核(或GPU),速度可能比单线程图形显示的速度快1.5到3倍:

注意在树莓派上运行代码非常慢,特别是在绘画模式下,因此,我们会简单地尝试改变相机和相机的分辨率。

改变相机和相机分辨率

下表显示了树莓派2在使用不同类型的相机和不同分辨率下素描模式的速度比较:

正如你所看到的,当使用320×240的Raspberry Pi Cam时,效果较好,即使它仍达不到理想的20~30FPS范围内。

1.4.2.6 桌面与嵌入式系统上运行的Cartoonifier的功耗对比

我们已经看到各种嵌入式设备比台式机慢,树莓派1耗时大约比桌面多20倍,而Jetson TK1耗时比桌面多约1.5倍。但对于某些任务,低速是可以接受的,这意味着电池消耗也会大大降低,从而允许小型电池或服务器的全年低电费或低发热量。

即使对于相同的处理器,树莓派也有不同的型号,例如树莓派1B、Zero和1A+,它们都以相似的速度运行,但具有明显不同的功耗。像Raspberry Pi Cam这样的MIPI CSI相机也比摄像头使用更少的电力。下表显示了运行相同Cartoonifier代码的不同硬件使用了多少电力。树莓派的功率测量如下图所示,使用简单的USB电流监视器(例如,售价5美元的J7-T Safety Tester(http://bit.ly/2aSZa6H))和用于其他设备的DMM万用表:

空闲功率测量计算机运行但没有使用主要的应用程序时的功率,Cartoonifier功率测量Cartoonifier程序正在运行时的功率。效率表示在640×480的素描模式下的Cartoonifier功率/Cartoonifier速度:

从表可知,树莓派1A+功率最小,但是最节能的选择是Jetson TK1和树莓派3B。有趣的是,最初的树莓派(树莓派1B)的效率和x86笔记本电脑差不多。所有后来的树莓派都比原来(树莓派1B)更节能。

免责声明:作者是NVIDIA(它生产Jetson TK1)的前雇员,但结果和结论被认为是真实的。

让我们来看看与树莓派配合使用的不同相机的功耗:

从表中可看到Raspberry Pi Cam v2.1比Raspberry Pi Cam v1.3功效略高,且显著高于USB摄像头。

将视频从树莓派流式传输到功能强大的计算机

得益于所有现代ARM设备包括树莓派都采用了硬件加速视频编码器,因此,在嵌入式设备上执行计算机视觉的有效替代方案是,使用该设备捕获视频,并通过网络将其实时传输到PC或服务器机架上。所有树莓派型号都包含相同的视频编码器硬件,因此带有Pi Cam的树莓派1A+或树莓派Zero对于低成本、低功耗的便携式视频流服务器来说是一个非常好的选择。树莓派3添加了Wi-Fi以增加便携功能。

有很多方法可以从树莓派中流式传输实时摄像视频,例如使用官方的树莓派V4L2相机驱动程序,让Raspberry Pi Cam看起来像摄像头,然后使用GStreamer、liveMedia、netcat或VLC通过网络流式传输视频。但是,这些方法通常会有一到两秒的延迟,并且通常需要自定义OpenCV客户端代码或者学习如何有效地使用GStreamer。因此,以下部分将展示如何使用一个名为UV4L的替代相机驱动程序来执行相机捕获和网络流传输:

1. 根据http://www.linux-projects.org/uv4l/installation/的介绍,在树莓派上安装UV4L:

2. 手动运行UV4L流媒体服务器(在树莓派上),检查是否工作:

3. 从桌面测试相机的网络流,按照以下步骤检查是否所有工作正常:

●安装VLC媒体播放器

●导航到Media|Open Network Stream,进入http://192.168.2.111:8080/stream/video.mjpeg

●将URL调整为树莓派的IP地址。在树莓派上运行hostname-I,找到IP地址

4. 启动时自动运行UV4L服务器:

5. 编辑uv4l-raspicam.conf中所需的UV4L服务器设置(例如分辨率和帧速率)以自定义流:

需要重启才能使所有更改生效。

6. 告诉OpenCV使用网络流,就好像它是一个摄像头一样。只要你安装的OpenCV可以在内部使用FFMPEG模块,OpenCV就能像摄像头一样从MJPEG网络流中获取帧:

现在你的树莓派使用UV4L将640×48024FPS的实时视频传输到一台PC上,PC在素描模式下运行Cartoonifier,大约可以达到19FPS(延迟为0.4s)。注意,这与直接使用PS3Eye摄像头(20 FPS)的速度几乎相同!

请注意,当你将视频流式传输到OpenCV时,它将无法设置相机分辨率,你需要调整UV4L服务器设置来更改相机分辨率。还要注意,我们可以使用较低带宽的H.264视频流而不是流式传输MJPEG格式的视频,但某些计算机视觉算法不能很好地处理H.264等视频压缩问题,所以MJPEG会比H.264引起更少的算法问题。

注意:如果你同时安装了官方的树莓派V4L2驱动程序和UV4L驱动程序,那么两者都可以作为0和1号相机(devices/dev/video0和/dev/video1)使用,但是一次只能使用一个相机驱动程序。

1.4.2.7 定制你的嵌入式系统

现在你已经创建了一个完整的嵌入式Cartoonifier系统,并且了解了它的工作原理以及哪些部分可以做什么,你应该尝试定制它!使视频全屏,更改GUI,更改应用程序行为和工作流程,更改Cartoonifier滤波器的参数或皮肤检测算法,使用自己的项目创意替换Cartoonifier代码,或者将视频流传输到云端处理!

你可以通过多种方式改进皮肤检测算法,例如使用更复杂的皮肤检测算法(例如,使用最近在http://www.cvpapers.com网站上的许多CVPR或ICCV会议论文中训练过的高斯模型),或者添加人脸检测(见第5章的人脸检测章节)到皮肤检测器中,因此它可以检测用户脸部的位置,而不是要求用户将他们的脸部放在屏幕的中央。注意,在某些设备或高分辨率相机上,人脸检测可能要花费许多秒,因此它们可能会受限于当前的实际使用情况。但是嵌入式系统平台每年都在发展,随着时间的推移,这可能不再是一个问题。

加速嵌入式计算机视觉应用程序的最有效的方法是尽可能地降低相机分辨率(例如,采用50万像素而不是500万像素),尽可能少地分配和释放图像,尽可能少地执行图像格式转换。在某些情况下,可能会有某些优化的图像处理或数学库,或者来自CPU设备供应商的OpenCV的优化版本(例如Broadcom、NVIDIA Tegra、Texas Instruments OMAP或Samsung Exynos),或者针对你的CPU系列的专门优化(例如,ARM Cortex-A9)。