最近想把PC上运行的视频监控的程序移植到嵌入式平台上,所以入手一款 Raspberry Pi 2 Model B。想按交叉编译的方式编译程序下载到树莓派上。我的树莓派安装了Raspbian操作系统,PC机使用了Ubuntu操作系统。
0.为什么要使用交叉编译:
虽然树莓派2的主频可达900MHz,但相比于PC机其性能还是差些,使用交叉工具链可节约开发时间。在编译链接同等规模的代码时,PC机所用的时间应少于树莓派所用时间。而且PC机软件功能更完备,可以使用很多提高效率的插件。所以通过交叉编译的方式能很大程度上提高编码效率。
树莓派中已经安装了gcc工具链,可在树莓派中直接编译源代码生成可执行文件。同时,PC机上也可使用gcc工具链生成可执行代码,但是和树莓派上的gcc工具不同,PC机上的gcc工具生成intel或amd芯片上可执行的代码,但树莓派却是arm系列的芯片,使用的完全不是一个指令集。所以需要使用交叉工具链,在PC机上开发树莓派中可执行程序。
1.如何安装交叉编译工具链
在树莓派中文论坛里已经有人介绍了交叉编译平台的搭建。http://shumeipai.nxez.com/2013/10/08/configure-cross-compiler-platform-raspberry-pi.html按照论坛中的说明即可安装树莓派的编译器。个人认为这种编译器应该针对树莓派本身硬件做过一定优化,比如硬件浮点数运算等,编译效果要好于一般的arm-linux-gcc/arm-linux-g++。
有了这个编译器,编译一般的程序已经不成问题,但是还缺少OpenCV的头文件和连接库,不能交叉编译OpenCV程序。
2.树莓派如何安装OpenCV
网上已经有人介绍了两种在树莓派上OpenCV的方式,源代码方式安装http://blog.csdn.net/xukai871105/article/details/40988101和apt方式安装http://blog.csdn.net/xukai871105/article/details/41084949。这与一般嵌入式平台上的OpenCV移植不同,都是不通过交叉编译(当然树莓派应该也是可以交叉编译移植OpenCV的,但是依赖的各种库有的已经有了,有的还没有,折腾起来会比较麻烦),直接在树莓派上安装OpenCV的方法。如果直接在树莓派上编译和使用OpenCV程序,它们确实非常方便,但是如果搭建交叉编译环境,就要再费些功夫了。考虑到源代码方式安装OpenCV会比较麻烦,我选择了apt方式安装。下载安装了OpenCV 2.4.1 的连接库和一系列和它们有依赖关系的库。
3.PC上OpenCV程序交叉编译环境的搭建
树莓派上已经有了gcc工具链、OpenCV连接库以及一系列它们依赖的库。所以已经可以在上面编译OpenCV程序了。但是我们的PC机上还没有相应的库。需要我们把上一步安装好的库拷贝到PC机上。首先把树莓派接入网络,再给它设置一个固定的IP地址,这样就可以使用ssh通过PC控制树莓派了。在树莓派上先 sudo apt-get install locate,这样定位一些链接库文件就方便多了。当然别忘了updatedb,不然会搜什么都搜不到。使用这个命令不难定位到OpenCV相关的库都在 /usr/lib 中,而头文件在 /usr/include/opencv 和 /usr/include/opencv2 中。使用scp指令,把它们拷贝到PC中保存。
如果这时尝试编译那些使用OpenCV函数的程序,会发现如果程序中调用了OpenCV highgui 模块的函数,就会因为缺少依赖项,有些符号无法解析而编译失败。这是因为libopencv_highgui.so文件又调用了一些有诸如解码ffmeg,解码jpeg,gtk显示等等功能的 .so 文件。这些文件有一些是Raspbian系统自带的,有一些是安装OpenCV时附带安装的。这些文件也需要拷贝到PC机上。经过尝试,发现一部分依赖项也在 /usr/lib 中,有些在 /usr/lib/arm-linux-gnueabihf 中,还有一些在 /lib/arm-linux-gnueabihf 中。拷贝文件时我先把/usr/lib/arm-linux-gnueabihf拷贝到了PC机的home路径下,然后把 /usr/lib 和 /lib/arm-linux-gnueabihf 中的 .so 文件也拷贝到了这个文件夹中,这样,我把所有的OpenCV库函数和头文件放到了raspberryOpenCV文件夹中,把其他依赖项放到了arm-linux-gnueabihf 中,如下图所示(查找这些文件时可以尝试编译调用了OpenCV highgui 模块的函数的程序,arm-linux-gnueabihf-g++ 会提示缺少哪些文件。在树莓派上搜索这些文件并拷贝到主机,按照文章后面的方式指定路径,再次编译,反复几次直到成功为止)
4.程序编译与下载运行
经过上面的步骤我们已经把编译程序所有需要的内容都准备好了。下面就可以开始编译程序了。输入如下命令;
arm-linux-gnueabihf-g++ -I'/home/windfish/raspberryOpenCV/include' -I'/home/windfish/raspberryOpenCV/include/opencv' -I'/home/windfish/raspberryOpenCV/include/opencv2' -L'/home/windfish/raspberryOpenCV/lib' -Wl,-rpath='/home/windfish/arm-linux-gnueabihf' -lopencv_highgui -lopencv_imgproc -lopencv_core CannyDetector_Demo.cpp -o CannyDetector
由于我们没有pkg-config命令,所以需要指定OpenCV头文件和库文件的路径。其他依赖项已经拷贝到 /home/windfish/arm-linux-gnueabihf 文件夹中,可以用
-Wl,-rpath='/home/windfish/arm-linux-gnueabihf'指定(rpath链接选项主要有两个功能:(1)程序运行时,优先到rpath指定的目录去寻找依赖库(2)程序链接时,在指定的目录中,隐式的链接那些动态库所需要的链接库。往往我们都熟知第一个功能,忽略第二个功能。而第二个功能正是此处所需要的)。这样就能编译出我们需要的程序了。
把 CannyDetector 文件和所需图片使用 scp 复制到树莓派中。这时如果在ssh上运行该程序,程序在显示图片的时候会出现问题。而直接在树莓派上操作是可以运行的。这是因为ssh默认是不接受图片显示的。按照文章http://blog.sina.com.cn/s/blog_6a680b8b010136bu.html中的方法进行设置(文章中没有提到主机更改设置后也要重启ssh,这一点也很重要),再次运行,就能看到回传的结果了。
至此,OpenCV程序交叉编译环境搭建完成。