欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

移植opencv到嵌入式arm详细过程

程序员文章站 2022-07-14 11:32:08
...

你好!这里是风筝的博客,

欢迎和我一起交流。


看了好几篇一直opencv的文章,都是几年前的,而且版本比较旧,对着弄会发现有的地方是和现在是有改动的。所以,2017年末,记录了此次移植过程,移植版本比较新的可以看过来,可以让你少走弯路。
为了这东西,逃了两次云计算的课,都被抓到了。伤,,,,,,

废话不多说,开搞:
opencv,计算机视觉库。
openCV 2.2以后版本需要使用Cmake生成makefile文件,因此需要先安装cmake。
怎么确保自己的Ubuntu下有没有安装cmake呢?
cmake –version
就可以看到已安装的cmake版本号,如果提示cmake命令未知,则没有安装。
当然,Ubuntu下安装软件一向很简单:
sudo apt-get install cmake-gui
之后,可以cmake-gui –version看看cmake安装成功与否:
移植opencv到嵌入式arm详细过程
这里我是在线安装,是3.5.1版本

接下来就是下载opencv了:
下载地址:http://blog.csdn.net/yanzi1225627/article/details/47668021
这是一个博主的帖子,里面是opencv下载地址,
我怕这个帖子那天就挂了,我自己也放一个吧,是opencv2.4.11版本:
http://download.csdn.net/download/guet_kite/10137838

下载好之后解压:unzip opencv-2.4.11.zip
cd opencv-2.4.11.zip
建两个文件夹来存放配置和安装路径:
sudo mkdir /usr/local/opencv/install_opencv -d
sudo mkdir /usr/local/opencv/config_opencv -d

然后用cmake配置:
sudo cmake-gui
移植opencv到嵌入式arm详细过程
在where is the source code:里写上opencv的源文件路径
在where to build the binaries:里面写上作为cmake编译arm版本的工作目录
然后点击configure
移植opencv到嵌入式arm详细过程
这里generator保持为Unix Makefiles,然后选择第四个选项:Specify options for cross-compiling
最后点击Next

移植opencv到嵌入式arm详细过程
这里Targeting System选的是Linux(之前我选的是arm-linux,有点坑,选这个没有V4L支持),
接着就是选择工具链了,我用的是友善的4.4.3的工具链,Compliers写的是交叉编译工具 arm-linux-gcc、arm-linux-g++
Target Root写的是交叉编译工具 arm-linux-g++/gcc 的所在包含文件夹
最后点击 Finish即可

移植opencv到嵌入式arm详细过程
然后中间红色的配置里:
取消WITH_GTK
取消WITH_TIFF
选择WITH_QT
GTK配置比较麻烦,我Ubuntu之前就配置好有QT了,所以我们取消掉,直接用QT最GUI。如果没有配置有QT,那还是不选吧。
最后点击Configure,会发现有错误:Error in configuration process,project files may be invalid
CMake Warning at cmake/OpenCVFindLibsGUI.cmake:18 (find_package):
By not providing “FindQt5Core.cmake” in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by “Qt5Core”, but
CMake did not find one.

Could not find a package configuration file provided by “Qt5Core” with any
of the following names:
Qt5CoreConfig.cmake
qt5core-config.cmake
第一个是一个warning,不管,下一个是error,说的是”Qt5Core”没找到。
我的QT安装路径是:/work/qt/my_qt/
所以直接把/work/qt/my_qt/lib/cmake/Qt5Core 填到Qt5Core_DIR选项即可,
同理,底下几个选项也要填上,Qt5Gui_DIR、Qt5Test_DIR等…….
移植opencv到嵌入式arm详细过程
最后点击Configure无误后,点击Generate按钮就会在/usr/local/opencv/install_opencv目录生成Makefile

cd /usr/local/opencv/config_opencv
修改安装opencv的路径:
sudo vi CMakeCache.txt
找到:CMAKE_INSTALL_PREFIX:PATH=/usr/local
修改为:CMAKE_INSTALL_PREFIX:PATH=/usr/local/opencv/install_opencv
这是我自己的安装路径。
当然,之间填写的QT的的路径也可以在这写,找到Qt5Core_DIR:PATH=
写为Qt5Core_DIR:PATH=/work/qt/my_qt/lib/cmake/Qt5Core 即可

接着sudo make编译,但是可能会出现一个错误:
具体错误忘记记录了,就是说libv4l1.so没找到,
所以在网上下载个libv4l-0.6.3.tar.gz,解压后进入,mkdir tmp && make && make install PREFIX=$PWD/tmp进行交叉编译与安装即可,安装目录在当前目录下的临时目录tmp下。然后把库和头文件复制到交叉编译链里相应的路径中。
但是make安装时出现提示:
libv4l1.c:53:28: fatal error: linux/videodev.h: No such file or directory
这是因为在新的版本里,已经不用videodev.h这个文件了。
然后我照着网上的文章改:
sudo ln -s /usr/include/libv4l1-videodev.h /usr/include/linux/videodev.h
呵呵,没有用,会提示缺少一些定义。
所以这里我们用另一个方法:
在老的机器里复制一份videodev.h文件出来,放到/usr/include/linux/目录下,就ok了。
videodev.h下载地址

继续回到opencv那里,sudo make,发现还有错误:

../../lib/libopencv_ts.a(ts_gtest.cpp.obj): In function `testing::internal::UnitTestImpl::~UnitTestImpl()':
ts_gtest.cpp:(.text._ZN7testing8internal12UnitTestImplD1Ev+0xa4): undefined reference to `pthread_getspecific'
ts_gtest.cpp:(.text._ZN7testing8internal12UnitTestImplD1Ev+0xc0): undefined reference to `pthread_key_delete'
ts_gtest.cpp:(.text._ZN7testing8internal12UnitTestImplD1Ev+0x22c): undefined reference to `pthread_getspecific'
ts_gtest.cpp:(.text._ZN7testing8internal12UnitTestImplD1Ev+0x248): undefined reference to `pthread_key_delete'
../../lib/libopencv_core.so: undefined reference to `pthread_spin_init'
../../lib/libopencv_core.so: undefined reference to `pthread_spin_unlock'
../../lib/libopencv_core.so: undefined reference to `pthread_spin_lock'
../../lib/libopencv_core.so: undefined reference to `pthread_spin_destroy'
../../lib/libopencv_core.so: undefined reference to `pthread_once'
../../lib/libopencv_core.so: undefined reference to `clock_gettime'
../../lib/libopencv_core.so: undefined reference to `pthread_spin_trylock'
collect2: ld returned 1 exit status
modules/core/CMakeFiles/opencv_test_core.dir/build.make:387: recipe for target 'bin/opencv_test_core' failed
make[2]: *** [bin/opencv_test_core] Error 1
CMakeFiles/Makefile2:1437: recipe for target 'modules/core/CMakeFiles/opencv_test_core.dir/all' failed
make[1]: *** [modules/core/CMakeFiles/opencv_test_core.dir/all] Error 2
Makefile:160: recipe for target 'all' failed
make: *** [all] Error 2

解决办法:
sudo vi CMakeCache.txt
找到:CMAKE_EXE_LINKER_FLAGS:STRING=
修改为:CMAKE_EXE_LINKER_FLAGS:STRING=-lpthread -ldl -lrt
意思是:-lpthread支持线程,-ldl避免未定义dlopen,-lrt避免未定义

最后sudo make编译成功,在sudo make install安装即可。
这样,就会在/usr/local/opencv/install_opencv出现文件:
移植opencv到嵌入式arm详细过程

最后把/usr/local/opencv/install_opencv/lib下文件移植到开发板根文件lib下
即可
当然,不复制也行,后面再说

好了,我们测试下:
从网上找到一个测试例子,然后修改下,test.cpp:

#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <iostream>

using namespace std;

int main(int argc, char **argv)
{
         CvCapture* capture = NULL;
         IplImage* frame = NULL;
         if(!(capture = cvCaptureFromCAM(0))) {
                 cout<<"Can not open camera.\n"<<endl;
                 return -1;
         }
         cvNamedWindow("video", 1);
         while(frame = cvQueryFrame( capture )){
                  cvShowImage("video",frame);
                  cout<<"have capture\n"<<endl;
         }

         cout<<"no have capture\n"<<endl;
         cvDestroyWindow("video");
         cvReleaseCapture(&capture);
         return 0;
}

编译:

arm-linux-g++ -I/usr/local/opencv/install_opencv/include/opencv/ -L/usr/local/opencv/install_opencv/lib/ -lcv -lcxcore -lhighgui -lpthread -lrt -o test test.cpp

这是网上找到文章的编译方法,好几年了,那么问题来了:
In file included from opencv.c:1:/usr/local/arm/lib/opencv/include/opencv/cv.h:63:33: error: opencv2/core/core_c.h: No such file or directory
因为这些文件是在opencv2下的,解决办法:

sudo cp /usr/local/opencv/install_opencv/include/opencv2 /usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/arm-none-linux-gnueabi/include -r -d

那么继续上面的编译,又出现:
test.cpp:21: note: the mangling of ‘va_list’ has changed in GCC 4.4
在GCC 4.4里,’va_list’已经被改变了,所以我们编译时,要加上 -Wno-psabi选项:

arm-linux-g++ -Wno-psabi -I/usr/local/opencv/install_opencv/include/opencv/ -L/usr/local/opencv/install_opencv/lib/ -lcv -lcxcore -lhighgui -lpthread -lrt -o test test.cpp

那么,这样可以了吗?
不行!出现:
/usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.3/../../../../arm-none-linux-gnueabi/bin/ld: cannot find -lcv
collect2: ld returned 1 exit status
这里提示lcv找不到,为什么呢?
还是我之前说的,网上的文章都是几年前的了,好老了。
打开我们opencv的lib可以看下,根本没有这些个库了,
移植opencv到嵌入式arm详细过程
所以提示自然找不到,所以要改成我们现在opencv的库:

arm-linux-g++ -Wno-psabi -I/usr/local/opencv/install_opencv/include/opencv/ -L/usr/local/opencv/install_opencv/lib/ -lopencv_core -lopencv_highgui -lpthread -lrt -o test test.cpp

这会行了吧?
很遗憾,还没有,出现两个warning:
/usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.3/../../../../arm-none-linux-gnueabi/bin/ld: warning: ../../lib/libopencv_imgproc.so, needed by /usr/local/opencv/lib_opencv/lib//libopencv_highgui.so, not found (try using -rpath or -rpath-link)
/usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.3/../../../../arm-none-linux-gnueabi/bin/ld: warning: ../../lib/libopencv_core.so, needed by /usr/local/opencv/lib_opencv/lib//libopencv_highgui.so, not found (try using -rpath or -rpath-link)

这是链接库的问题,我在网上找了好多办法:
办法一:

sudo vi /etc/ld.so.conf.d/opencv.conf

再文件里写上库文件路径:/usr/local/opencv/install_opencv/lib/
接着

sudo ldconfig

很遗憾,没有用。。。。

办法二:

sudo vi bash.bashrc

在最后写上:

PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/opencv/install_opencv/lib/pkgconfig
export PKG_CONFIG_PATH

也没用!!!

办法三:
网上找到说,cmake下make出来的.so 文件 arm-linux-gcc-4.3.2不识别。。。。。
当然,我的编译时是arm-linux-4.4.3,也是一样的,
他说,在Makefile里将LFLAGS中添加了:-Wl,-rpath-link -Wl,/。。、。。。/…..(lib的目录)就可以了。
特么我在Makefile里根本没找到LFLAGS,,,失败。

办法四:
将需要到的那三个.so文件:libopencv_core.so libopencv_highgui.so libopencv_imgproc.so复制到系统默认的链接库路径中,

sudo cp libopencv_core.so libopencv_highgui.so libopencv_imgproc.so /usr/lib

还是不行。。。。

最后,终于找到了办法:
将这些库复制到编译器的lib中:

sudo cp -d *libopencv_core* *libopencv_highgui* *libopencv_imgproc*  /usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/arm-none-linux-gnueabi/lib

终于可以顺利编译出可执行文件了。。。。。。
所以,如果之前把/usr/local/opencv/install_opencv/lib下文件移植到开发板根文件lib下,就不会出现这个问题了。
当然,此时,我移植opencv时并没有选择选择WITH_QT,而是选择WITH_GTK,后来我选择WITH_QT时,在用这个编译就会出现一个问题:

/usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.3/../../../../arm-none-linux-gnueabi/bin/ld: warning: libQt5Widgets.so.5, needed by /usr/local/opencv/install_opencv/lib//libopencv_highgui.so, not found (try using -rpath or -rpath-link)
/usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.3/../../../../arm-none-linux-gnueabi/bin/ld: warning: libQt5Gui.so.5, needed by /usr/local/opencv/install_opencv/lib//libopencv_highgui.so, not found (try using -rpath or -rpath-link)
/usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.3/../../../../arm-none-linux-gnueabi/bin/ld: warning: libQt5Core.so.5, needed by /usr/local/opencv/install_opencv/lib//libopencv_highgui.so, not found (try using -rpath or -rpath-link)
/usr/local/arm/opt/FriendlyARM/toolschain/4.4.3/bin/../arm-none-linux-gnueabi//sys-root/lib/libQt5Concurrent.so.5: undefined reference to `QFutureInterfaceBase::isPaused() aaa@qq.com_5'

估计就是选择QT作为GUI的后遗症了,所以要把一些QT的库,如:libQt5Widgets.so.5,libQt5Gui.so.5,libQt5Core.so.5等库移到交叉编译链的lib目录中,所以编译命令更改为:

arm-linux-g++ -Wno-psabi -I/usr/local/opencv/install_opencv/include/opencv/ -L/usr/local/opencv/install_opencv/lib/ -L/work/qt/my_qt/lib -lQt5Widgets -lQt5Gui -lQt5Core -lpthread -lopencv_core -lopencv_highgui -lpthread -lrt -o test test.cpp

然后把编译出来的test文件放到开发板上执行:

如果是选择了WITH_GTK而不是选择WITH_QT的,会出现:
HIGHGUI ERROR: V4L/V4L2: VIDIOC_S_CROP

OpenCV Error: Unspecified error (The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script) in cvNamedWindow, file /usr/local/opencv/opencv-2.4.11/modules/highgui/src/window.cpp, line 483
terminate called after throwing an instance of ‘cv::Exception’
what(): /usr/local/opencv/opencv-2.4.11/modules/highgui/src/window.cpp:483: error: (-2) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function cvNamedWindow

Aborted

意思是开发板上缺少GTK/QT 这类图形显示功能。毕竟GTK不好搞。

如果是选择了WITH_QT而不是选择WITH_GTK的,会出现:
HIGHGUI ERROR: V4L/V4L2: VIDIOC_S_CROP
init done
have capture
have capture

这说明,应该是有数据通过摄像头进来了,因为有了have capture打印输出,但是我们现在是看不到图像的,因为没有平台输出,没有用QT编译。

但是,我们可以看到是有一个error的:HIGHGUI ERROR: V4L/V4L2: VIDIOC_S_CROP
看了些网上的方法,有人是是因为没有安装libv4l-dev,然而,之前我自己编译安装了libv4l-0.6.3……
而且,sudo apt-get install libv4l-dev的话,把opencv按之前的再安装一遍,opencv反而make编译不过,会报错:
libv4l1.so.1: could not read symbols: File in wrong format
所以pass掉,sudo apt-get remove libv4l-dev

然后我在opencv源码找到:

/* set the crop area, but don't exit if the device don't support croping */
        if (ioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop) < 0) {
            fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: VIDIOC_S_CROP\n");
        }

这说的是:设置剪裁面积,如果不能设置,也不退出,我想了下,应该没事吧……
毕竟我都能打印出have capture了。而且我拔掉摄像头的话,就会提示Can not open camera.说明打开摄像头失败。

如果不信?那我们试一下opencv的威力:
我在网上找了一篇opencv的教程, 浅墨博主的文章:
opencv.cpp:

#include<opencv2/core/core.hpp>  
#include<opencv2/highgui/highgui.hpp>  
#include<iostream>

using namespace cv;  
using namespace std;

int main( )  
{   
    //载入图片  
    Mat image= imread("girl.jpg");  
    Mat logo= imread("fly.jpg");   
    //定义一个Mat类型,用于存放,图像的ROI  
    Mat imageROI;

    imageROI= image(Rect(10,10,logo.cols,logo.rows));//定义一个左上角点坐标为(_x, _y)的cols*rows矩形窗口

    //将logo加到原图
    //参数:图、权重、图、权重、添加的常数项、输出图
    addWeighted(imageROI,0.5,logo,0.3,0.,imageROI);     

    cout << "start add picture......\n" << endl;    
    //输出一张jpg图片到工程目录下  
    imwrite("fly_girl.jpg",image);  

    waitKey();  

    return 0;  
}  

Makefile:

CC  = arm-linux-g++
LFLAGS  = -Wno-psabi
LIBS    = -L/usr/local/opencv/install_opencv/lib/ -L/work/qt/my_qt/lib
CPPFLAGS    = -lQt5Widgets -lQt5Gui -lQt5Core -lpthread -lopencv_core -lopencv_highgui -lpthread -lrt
LINC     += -I/usr/local/opencv/install_opencv/include/opencv/
objs := open
out := open

$(out):$(objs).cpp
    ${CC} ${LFLAGS} ${LIBS} ${LINC} ${CPPFLAGS} -o aaa@qq.com $^

clean:
    rm $(out)

还是那个老话,如果没有选择WITH_QT的话,
-lQt5Widgets -lQt5Gui -lQt5Core和-L/work/qt/my_qt/lib
可以不需要。
这是girl.jpg图:
移植opencv到嵌入式arm详细过程
这是fly.jpg图:
移植opencv到嵌入式arm详细过程

这是使用opencv合成的效果图:
移植opencv到嵌入式arm详细过程
效果非常棒,不愧是opencv!!!

最后,QT+opencv的例子:opencv+QT在嵌入式arm下显示图片

PS:不知道能不能帮到大家,有照着文章做成功的小伙伴吗?