前言
这是我第一篇公开的文章,也是我第一次尝试交叉编译的成果,可能过程有不足,文章也可能写得不全面,请多见谅。不足请指出,我每天都会看的。希望大家多多交流学习。
环境与相关准备工作
主机平台:Ubuntu 16.04(64 bit)
硬件平台:TI公司的OMAPL138LCDK
交叉编译工具链:arm-linux-gnueabi-gcc-5(及其g++)
OpenCV源码:3.1.0版本(加contrib也可)及官网列出的依赖包
FFMPEG:2.8.17
CMAKE:cmake-qt-gui
注:
- 工具链可到linaro网站下载,也可apt-get install下载。TI的产品,官方都有提供对应的工具链,我图方便直接用apt-get install下载。交叉编译工具链应对应硬件平台arm芯片的架构。本平台为ARM9处理器,为V5架构,属于soft float类型。其他架构有对应的hf类型和64bit的工具链。
- OpenCV版本选太新,编译器有可能不支持(一开始直接上手4.5.1的教训),最好选择编译器发布日期比OpenCV版本发布晚的吧。已经测试过,最高支持版本3.4.1。
- FFMPEG版本,我是自己在Ubuntu上下了一个是2.8.17,因此采用2.8.17,其他尚未尝试。同时本次仅采取FFMPEG一个包,其他依赖包尚未加入,后续再添加功能。
编译FFMPEG
终端进入源码目录利用
#若需要xvid和x264
#编译x264
CC=arm-linux-gnueabi-gcc-5 ./configure --enable-shared \
--host=arm-linux-gnueabi --disable-asm \
--prefix=/usr/local/opencv_ffmpeg_arm
make
sudo make install
#编译xvid
#进入xvid源码目录下的build/generic目录
CC=arm-linux-gnueabi-gcc-5 ./configure \
--prefix=/usr/local/opencv_ffmpeg_arm --host=arm-linux-gnueabi \
--disable-assembly
#编译ffmpeg
./configure --help #查看所有参数 以下为本人配置参数
./configure --prefix=/usr/local/opencv_ffmpeg_arm \
#opencv和ffmpeg的生成文件都放一个文件夹,方便后续工作
--enable-gpl --enable-nonfree --disable-static --enable-shared \
#建议都是用动态库 一开始觉得用静态库可以直接一个可执行程序拉到板子上方便
#实际上到后面编译应用程序时会一直失败,这是由于opencv中依赖很复杂
#除非你自己去修改后面配置文件,根据依赖关系调整静态库链接顺序吧
--enable-avresample #默认不生成的,但编译opencv需要这个
--arch=arm #直接写arm configure文件都可以识别到armv5架构,其他未知
--cross-prefix=arm-linux-gnueabi- --enable-cross-compile \
--target-os=linux --cc=arm-linux-gnueabi-gcc-5
#ffmpeg是c代码,不用c++编译器
#曾出现过找不到nm的情况,后用--nm=arm-linux-gnueabi-nm解决
--disable-asm #交叉编译可能不支持某些代码的汇编优化
#以下为xvid和x264需要项
--enable-libx264 --enable-libxvid --disable-stripping \
--extra-cflags=-I/usr/local/opencv_ffmpeg_arm/include
--extra-ldflags=-L/usr/local/opencv_ffmpeg_arm/lib
FFMPEG的编译工作会比OpenCV顺利些。等一会configure,弹出很多配置信息后可下一步。有可能会有一些警告,除了上述关于nm的警告情况导致失败,别的警告都编译成功,因此我也没留意。
make #也可make -j2 数字代表调用cpu核数还是线程数没详细研究,反正快点
#编译完成后
sudo make install #生成文件会安装到prefix的目录下
编译OpenCV
准备工作
进入到/usr/local/opencv_ffmpeg_arm/lib目录下,执行以下命令
sudo ln -s ./libavcodec.so ./libavcodec-ffmpeg.so
sudo ln -s ./libavformat.so ./libavformat-ffmpeg.so
sudo ln -s ./libavutil.so ./libavutil-ffmpeg.so
sudo ln -s ./libavresample.so ./libavresample-ffmpeg.so
sudo ln -s ./libswscale.so ./libswscale-ffmpeg.so
这一步是我搞了很多天才弄懂的操作,到csdn、opencv论坛和stackoverflow找了很多帖子也没有人提到,自己也发起帖子(虽然发布这篇文章时仍然没人回我)。
编译opencv时,链接器一直报错找不到以上带有"-ffmpeg"的库。但其实在安装opencv官网列出的依赖包后,这些库是连带安装在usr/lib/x86_64-linux-gnu目录下。尝试过复制这些库到查找路径下,opencv编译成功了,但是编译应用程序时会报错(文件格式不匹配)。
通过以下命令可了解到那些库都是基于x86或i386架构的,并不符合我们arm架构。同时以上也是64位库,我的硬件平台是32位。
objdump -f 文件名
但无论是ffmpeg官网还是别的地方,都没有提供这种带有"-ffmpeg"的库下载,可是你到usr/lib/x86_64-linux-gnu目录ls一下,会发现其实"-ffmpeg"库其实只是软链接文件,链接的都是如libavformat.so*(*代表版本号)的文件。这些文件恰恰就是我们编译ffmpeg所生成的文件。
因此就有了以上的建立软链接工作。
cmake-gui配置
终端输入cmake-gui打开cmake配置工具
- 分别指定源码目录和build的目录,两者不要相同。
- 点击configure。
- 选择Specify options for cross-compiling。
填好操作系统、处理器、C和C++编译器和编译器的目录。
编译和链接时会采用编译器目录内对应文件和库。其实如果ffmpeg的生成文件目录指定为编译器目录的话,功夫会少一点,但就是不好移植。
得到这样的界面,这时我们根据需要选择组件,然后一直点configure,直到全部红色项变为白色即配置完毕。以下介绍我的配置项。
cmake-gui配置项
1.CMAKE_INSTALL_PREFIX
改为/usr/local/opencv_ffmpeg_arm
2.BUILD_SHARED_LIBS
与上面选择生成ffmpeg动态库同理
3.OPENCV_EXTRA_MODULES_PATH
contrib文件夹中modules文件夹的位置。
/home/rookie/opencv_contrib-3.1.0/modules
4.所有CXX_FLAGS
这里要加入-std=c++11,不然编译时会出现"exception_ptr"未定义的问题。是一些头文件包含问题,进入过相关.h文件中你会发现有个宏定义决定是否包含,一直不通过(我还试过直接包含…)。在stackoverflow上看到是与c++11相关,同时也有可能是编译器不支持对应一些代码的原因,因此才选择3.1.0版本(牛人还是多) 。至于编译器和板子是否支持c++11,可在网上找找测试代码,是通过输出c++11发布年份判断的。
还有-I/usr/local/opencv_ffmpeg_arm/include
和-L/usr/local/opencv_ffmpeg_arm/lib 。这个参数也要加在所有C_FLAGS上。编译器会去找对应头文件和以上"-ffmpeg"的库。
在所有C/CXX_FLAGS上加参数,我就是图方便。至于LINKER_FLAGS要不要加上库的路径,我忘了。可以试试。
5.组件配置
我是想用来处理图片、视频和摄像头。所以与图片格式相关选了,FFMPEG,然后WITH_V4L。(V4L暂时没有摄像头,测试不了)不过我发现选了FFMPEG和V4L,就编译失败。留下其中任何一个就能成功,目前就只留了FFMPEG版本OpenCV。同时选FFMPEG和V4L的话,会出现一个"impossible constraint in asm"这样的错误,目前我还无法解决,希望可以指教。应该可以编译一个带FFMEPG的,一个带V4L的,有摄像头后试试。
WITH_PTHREADS_PF,看官网描述是对应一些算法能加速处理。
关于BUILD_opencv_*这些选项,可以先去官网看看哪些是你需要的,然后进行选择。要留意configure后出现的信息,会出现一些not found,或者Build_opencv无法生成(因为你没选它所依赖的build_opencv项,根据警告选上就可以解决了)。信息中那一栏应该像下图。
比如这个not found问题,要是C_FLAGS部分没指定include目录就会出现。
编译
同样
make 或 make -j2
sudo make install
/usr/local/opencv_ffmpeg_arm目录复制到/usr/local/下
测试
CMakeLists.txt
程序都是通过cmake生成Makefile来生成可执行文件的。
因此还要写CMakeLists.txt文件。
1 set(tool_path "/usr/bin")
2 set(CMAKE_C_COMPILER ${tool_path}/arm-linux-gnueabi-gcc-5)
3 set(CMAKE_CXX_COMPILER ${tool_path}/arm-linux-gnueabi-g++-5)
4 set(CMAKE_CXX_FLAGS "-std=c++11")
5 #指定编译器
6
7
8
9 #以下是参考OpenCV官网的
10 cmake_minimum_required(VERSION 2.8)
11 project( video_frame ) #跟随工程改名
12 find_package(OpenCV REQUIRED)
13 include_directories( ${OpenCV_INCLUDE_DIRS} )
#link这一行一定要加 官网是没有的 不然找不到所需要的库
14 link_directories("/usr/local/opencv_ffmpeg_arm/lib")
#add_executable(可执行文件名 源文件名)
15 add_executable( video_frame video_frame.cpp )
#target_link_libraries( 可执行文件名 ${OpenCV_LIBS} )
16 target_link_libraries( video_frame ${OpenCV_LIBS} )
在应用程序目录下写好CMakeLists.txt文件后
cmake . #有个点跟在cmake后 输出信息应该是交叉编译工具链
make
file 可执行文件 #看看是不是32bit的ARM架构
图片处理
选了WITH_JPEG,才可处理".jpeg"文件。能生成变灰的图就成功。
1 #include <opencv2/opencv.hpp>
2
3 using namespace cv;
4
5 int main(int argc,char** argv)
6 {
7 char* imageName=argv[1];
8 Mat image;
9 printf("imageName:%s\n",imageName);
10 image=imread(imageName,1);
11 if(!image.data){
12 printf("read error\n");
13 return -1;
14 }
15
16 Mat gray_image;
17 cvtColor(image,gray_image,COLOR_BGR2GRAY);
18 imwrite("./gray.jpeg",gray_image);
19
20 return 0;
21 }
读取视频
检验我们的FFMPEG。能生成视频中第一帧的图片就成功。
1 #include <iostream>
2 #include <string>
3 #include <iomanip>
4 #include <sstream>
5
6 #include <opencv2/core/core.hpp>
7 #include <opencv2/imgproc/imgproc.hpp>
8 #include <opencv2/videoio/videoio.hpp>
9 #include <opencv2/highgui/highgui.hpp>
10 #include <opencv2/opencv.hpp>
11
12 using namespace std;
13 using namespace cv;
14
15 int main(int argc,char** argv)
16 {
17 if(argc != 2){
18 cout<<"parameter not enough"<<endl;
19 return -1;
20 }
21 const string video_name=argv[1];
22 VideoCapture video(video_name);
23
总结
- 在实验和测试前,应先写清楚方案并记录实验结果,不然会做很多重复的无用功。
- 沉下心去看文档,练好英语。
- 搜索资料平台要多渠道,csdn、官方论坛、stackoverflow、google、bing,对百度凉了心。
- 如果不是很喜欢嵌入式,就不要选嵌入式。