ARM开发板OK6410移植opencv-2.4.7库qt界面显示(附加各种问题解决方案)

         请先观看《linuxubuntu12.04上opencv2.4.7 cmake2.8.12.1环境搭建》,对linux上编译opencv有基本了解再来看这篇文章效果最佳

         经过了昨天一天苦逼的研究opencv源码、arm-linux编译器工作原理和坚持不懈的make,我终于移植成功了opencv-2.4.7for arm库到OK6410上,遇到了各种问题,研究了很长时间,连上课时候都在想原因和解决方案,都让我想翘课。。。

         接下去我会简单分析整个移植过程,讲解一些网上常见问题,不过我建议大家还是自己先去试试移植看看,花点时间就能学到很多。

首先介绍我的开发环境:

         主机OS:UBUNTU12.04

         宿主机:飞凌OK6410

         宿主机内核:linux3.6

         opencv版本:opencv2.4.7

         cmake版本:cmake2.8.12.1

         交叉工具链:Sky arm-linux4.3.3 天嵌

接下去还是先开始利用cmake工具定制opencv,cmake的图像界面比较容易上手,所以这里用cmake-gui讲解cmake过程:

         1.虚拟机的童鞋可以先备份虚拟文件

         2.su- root切换到root用户忽略权限问题

         3.mkdir/home/opencv/opencv-arm/  存放makefile和一些相关cmake配置文件

         4.cmake-gui运行cmake gui

         5.跟移植到linux-pc上一样填入sourcecode和build the binaries目标路径

         6.点击Configure,保持unixmakefiles选项,选择specify options for corss-compiling来选择编译器路径

ARM开发板OK6410移植opencv-2.4.7库qt界面显示(附加各种问题解决方案)_第1张图片

         7.operating system填入os名,即编译器名arm-linux  os version这个可以不填,我不清楚这个填内核版本还是编译器版本,compilers C填入编译器arm-linux-gcc的elf路径,C++填入编译器arm-linux-g++的elf路径,target root是寻找lib和include文件的,这些文件都在arm-linux编译器文件路径下,比如我的编译器路径就是/home/arm/Sky/opt/EmbedSky/4.3.3/

ARM开发板OK6410移植opencv-2.4.7库qt界面显示(附加各种问题解决方案)_第2张图片

         8.finish后会提示:error inconfiguration procss,project files may be invalid,指的是它默认配置对你给定的os是不支持的。这是我遇到的第一个问题,究竟什么不支持呢,为了通过配置,我去了解cmake都为opencv配置了些什么(其实看他提示的出错信息就已经知道问题在哪,但是也不能稀里糊涂的配置,我还是决定看看配置项):

         opencv-arm/CMakeCache.txt是cmake记录配置信息的文件,也是makefile重要信息来源,这里的配置选项都有注释,可以方便大家理解配置选项的含义。

         重要选项:

         BUILD开头的都是构建文件,选上则将寻找对应源码然后构建在opencv库中

         WITH开头的都是opencv对相应选项内容的支持,选上则表示opencv库将支持所选内容,所以开发板不支持的选项不要选。

         CMAKE_BUILD_TYPE构建类型,一般填入Release构建发布版本

         CMAKE_INSTALL_PREFIX安装路径,可以指定自己需要安装的路径

                   我的安装路径是usr/local/arm/opencv/-> bin/       存放elf

                                                                                              -> include/    存放opencv opencv2

                                                                                              -> lib/        存放.so .a

                                                                                              -> share/  存放例子中使用的xml资源文件

         CMAKE_EXE_LINKER_FLAGS链接标记,-pthread支持线程,-ldl避免未定义dlopen,-lrt避免未定义clock_gettime。这个要在opencv-arm/CMakeCache.txt中修改。

                   CMAKE_EXE_LINKER_FLAGS:STRING=''

                   替换成:CMAKE_EXE_LINKER_FLAGS:STRING=-pthread-ldl -lrt  全动态链接

         CMAKE_EXE_LINKER_FLAGS是我遇到的第二个问题,不修改这个make编译时会有以下错误:

         1.线程和clock符号错误 解决方法: 添加链接器选项-pthread-lrt

         ../../lib/libopencv_core.so: undefinedreference to `pthread_spin_init'

         ../../lib/libopencv_core.so: undefinedreference to `pthread_spin_unlock'

         ../../lib/libopencv_core.so: undefinedreference to `pthread_spin_lock'

         ../../lib/libopencv_core.so: undefinedreference to `pthread_spin_destroy'

         ../../lib/libopencv_core.so: undefinedreference to `pthread_once'

         ../../lib/libopencv_core.so: undefinedreference to `clock_gettime'

         ../../lib/libopencv_core.so: undefinedreference to `pthread_spin_trylock'

         collect2: ld returned 1 exit status

         make[2]: *** [bin/opencv_perf_core] 错误 1

         make[1]: ***[modules/core/CMakeFiles/opencv_perf_core.dir/all] 错误 2

         make: *** [all] 错误 2

         2.dlopen符号错误  解决方法: 添加链接器选项-ldl

         ../../lib/libopencv_ocl.so: undefinedreference to `dlopen'

         ../../lib/libopencv_ocl.so: undefinedreference to `dlsym'

         collect2: ld returned 1 exit status

         make[2]: *** [bin/opencv_perf_ocl] 错误 1

         make[1]: ***[modules/ocl/CMakeFiles/opencv_perf_ocl.dir/all] 错误 2

        

         理解的差不多了,来看看怎么让cmake过去,首先看错误提示:

         CMake Error at cmake/FindCUDA.cmake:762(if):

  if given arguments:

 

    "CUDA_VERSION""VERSION_GREATER" "5.0" "AND""CMAKE_CROSSCOMPILING" "AND"   "MATCHES" "arm""AND" "EXISTS""CUDA_TOOLKIT_ROOT_DIR-NOTFOUND/targets/armv7-linux-gnueabihf"

 

  Unknown arguments specified

  Call Stack (most recent call first):

  cmake/OpenCVDetectCUDA.cmake:26(find_package)

  cmake/OpenCVFindLibsPerf.cmake:24 (include)

  CMakeLists.txt:423 (include)

         这个CUDA有问题,看看WITH_CUDA默认确实是选中的,来到CMakeCache.txt查看发现这个选项是显卡NVidiaCuda Runtime support的支持,我也很希望开发板能支持显卡- -,还是把WITH_CUDA去掉,顺便去掉WITH_TIFF以免编译时报tiff error。

         总结一下修改的地方:

         去掉WITH_TIFF  WITH_CUDA

         修改CMAKE_BUILD_TYPE为Release

         修改CMAKE_INSTALL_PREFIX  路径可以参考我的想法,而且千万不要跟pc的库重叠

         到opencv-arm/CMakeCache.txt下找到CMAKE_EXE_LINKER_FLAGS:STRING=''

         替换成:CMAKE_EXE_LINKER_FLAGS:STRING=-pthread-ldl -lrt 

ARM开发板OK6410移植opencv-2.4.7库qt界面显示(附加各种问题解决方案)_第3张图片
ARM开发板OK6410移植opencv-2.4.7库qt界面显示(附加各种问题解决方案)_第4张图片
ARM开发板OK6410移植opencv-2.4.7库qt界面显示(附加各种问题解决方案)_第5张图片

         9.再次configurate 这次还会有许多不支持的选项,但是可以generate,我们就忽略它们,但是其中有一个我可以改 PYTHON_PACKAGES_PATH可以修改路径,到/usr/local/lib下找到这个包,我没试过,但是pkg-config的寻路功能对我们来说还是很有用的。

         10.点击generate,如果提示generatedone说明可以拿去make了。

         11.进入构建的目录,我的是opencv-arm目录下,运行make,各忙各的思密达。

         12.终于100%了,然后还在这个目录下运行makeinstall,如果安装成功不会报错,到安装目录下看lib下是否有.so文件,运行file xxxxxx.so看看是不是支持arm的共享库,是的话编译就基本成功了。

         这里我再提个我遇到的问题,我原本以为opencv的gui可以依赖qtgui运行在arm板子上,所以我在配置时选了WITH_QT和WITH_OPENGL,把qt for arm的qmake路径填上,结果编译报错,看到i386字样我心头一紧,赶紧跑去看CMakeCache.txt,结果一搜QT,显示出满屏幕的i386的qt库路径,看看cmake貌似没这配置还是我没找到怎么的,这事情我还是以后再弄吧,opencv的gui貌似需要gtk或qt的支持才能用highgui里的功能,这么一来highgui库就没用了,不知道有没有人可以让highgui在arm板上用起来,我挺喜欢用这里面的功能。我有空也会去看看WITH_QT该怎么去支持。那显示的工作还是让用户主动让opencv移交给qt去做吧。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

移植和测试:

         移植也是比较麻烦的事,过程讲解后会谈谈我遇到的问题

         测试没问题的移植过程:

         1.将安装目录下/lib/*所有文件拷到开发板/lib下,不要改路径,必须在/lib下。容量不足的可以只拷运行需要的文件

         2.把安装目录下/bin/*拷到开发板/bin下,这一步可以不要

         3.新建qt工程,使用dialog界面,在.pro文件中加入

	INCLUDEPATH+=   /usr/local/arm/4.4.3/opencv/include/opencv     \
               		 /usr/local/arm/4.4.3/opencv/include/opencv2    \
               		 /usr/local/arm/4.4.3/opencv/include
	LIBS+= /usr/local/arm/4.4.3/opencv/lib/libopencv*

         4.新建switch.cpp源文件,复制上IplImage与QImage间转换用代码:

#include "switch.h"

ImageCVtoQT::ImageCVtoQT(IplImage *_srcImage)
    :srcImage(_srcImage)
{
    assert(srcImage != NULL);
    width = srcImage -> width;
    height = srcImage -> height;
    channel = srcImage -> nChannels;
}

ImageCVtoQT::~ImageCVtoQT()
{
    cvReleaseImage(&srcImage);
}

const QImage ImageCVtoQT::getQtImage()
{
    QImage desImage = QImage(width, height, QImage::Format_RGB32);
    for(int i=0; i<height; i++)
    {
        for(int j=0;j<width; j++)
        {
            int r,g,b;
            if(RGB_TYPE == channel)
            {
                b = (int)CV_IMAGE_ELEM(srcImage, uchar , i, j*3+0);
                g = (int)CV_IMAGE_ELEM(srcImage, uchar , i, j*3+1);
                r = (int)CV_IMAGE_ELEM(srcImage, uchar , i, j*3+2);
            }
            else if(GRAY_TYPE == channel)
            {
                b = (int)CV_IMAGE_ELEM(srcImage, uchar, i, j);
                g = b;
                r = b;
            }
            desImage.setPixel(j, i, qRgb(r, g, b));
        }
    }
    return desImage;
}
/////////////////////////////////////////////////////////////////////

ImageQTtoCV::ImageQTtoCV(QImage _srcImage)
:srcImage(_srcImage)
{
    assert(!srcImage.isNull());
    width=srcImage.width();
    height=srcImage.height();

}
ImageQTtoCV::~ImageQTtoCV()
{
}

IplImage *ImageQTtoCV::getCvImage()
{
    IplImage *desImage=cvCreateImage(cvSize(width,height),8,3);
    for(int i=0;i<height;i++)
    {
        for(int j=0;j<width;j++)
        {
            QRgb rgb=srcImage.pixel(j,i);
            CV_IMAGE_ELEM(desImage,uchar,i,j*3+0)=qBlue(rgb);
            CV_IMAGE_ELEM(desImage,uchar,i,j*3+1)=qGreen(rgb);
            CV_IMAGE_ELEM(desImage,uchar,i,j*3+2)=qRed(rgb);
        }
    }
    return desImage;
}

         5.新建switch.h头文件供调用:

#ifndef SWITCH_H
#define SWITCH_H

//#include "highgui.h"
#include "cv.h"
#include "cxcore.h"

#include <QImage>


#define RGB_TYPE  3
#define GRAY_TYPE 1

class ImageCVtoQT
{
public:
    ImageCVtoQT(IplImage *_srcImage);
    ~ImageCVtoQT();
    const QImage getQtImage(void);
private:
    IplImage *srcImage;         

    //QImage desImage;          
    int width;
    int height;
    int channel;
};

class ImageQTtoCV
{
public:
    ImageQTtoCV(QImage _srcImage);
    ~ImageQTtoCV();
    IplImage *getCvImage(void);
private:
    QImage srcImage;
    int width;
    int height;
    //int channel;
};


#endif // SWITCH_H

         上述两个类非常棒,感谢网上牛人,我也为了解这两个类的实现而看了半天的源码。QT和OPENCV源码间看的我比较晕。

         6.在界面文件中拉入一个lable,将其展开与窗体同大小,我没有太多qt编写经验,显示图只会lable显示,而且画图的效果- -,就不多说了,等这个移植好后看看qt的编程吧。。。

         7.在dialog的构造函数中进行图像的导入和转换,过程是QImage导入图片-> 原始IplImage->opencv对原始IplImage进行处理->处理后IplImage->QImage->使用QImage借助qt窗体上显示图片。

         dialog.cpp要贴的内容:
#include "dialog.h"
#include "ui_dialog.h"
#include "switch.h"
#include "QtGui"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    //声明IplImage指针
    IplImage *pImg = NULL;
    QImage *qImg = new QImage;

    //载入图片
    if(!(qImg->load("/home/project/sao22.bmp")))  // 我的开发板支持bmp格式,小心路径
    {
        return;
    }

    //switch
    ImageQTtoCV qtc(*qImg);
    pImg = qtc.getCvImage();
    if(!pImg)
        return;
    IplImage *pGrayImg = NULL;
    pGrayImg = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1);
    cvCvtColor(pImg, pGrayImg, CV_BGR2GRAY);

    ImageCVtoQT ctq(pGrayImg);
    *qImg = ctq.getQtImage();
    if(!qImg)
        return;

    ui->label->setPixmap(QPixmap::fromImage(*qImg));
}

Dialog::~Dialog()
{
    delete ui;
}

         8.qt用qmake for arm构建工程,完成后将elf文件从debug文件夹中拷贝到开发板中(千万不要在第三级目录以上,否则会报错),将图片也拷到对应路径上

         9.写好启动脚本后运行,就可以看到屏幕上显示处理后的gray图片(爱图)了:

ARM开发板OK6410移植opencv-2.4.7库qt界面显示(附加各种问题解决方案)_第6张图片

         这说明opencv库可以正常工作,其他功能我还没试,但基本的创建图片和颜色处理是没问题的,至此opencv2.4.7库移植到arm开发板ok6410成功。

         接下来我再来说说我遇到的问题:

         1. :-1: 警告:../../lib/libopencv_core.so,needed by       /usr/local/arm/4.4.3/opencv/lib/libopencv_calib3d.so,not found (try using -rpath or -rpath-link)

         :-1:警告:../../lib/libopencv_flann.so,needed by /usr/local/arm/4.4.3/opencv/lib/libopencv_calib3d.so, not found (tryusing -rpath or -rpath-link)

         先是在qt上警告,后在开发板上运行时也报错:

error while loading shared libraries:../../lib/libcxcore.so: cannot open shared object file: No such file ordirectory

         还好我那时还冷静,看到了../../lib/这个提示,感觉这个库是不是只能在特定的路径下呢?假设当前运行路径是/home/qt/sd11/,../../所指的文件夹是qt/,但qt/下没有lib文件夹,这时我把运行目录换成/home/,../../所指的文件夹是根目录,根目录下有lib文件夹,而且里面放着libcxcore.so,这样elf就能找到共享文件了。所以这问题连带着qt编译时的报错一起解决。

         第一种方案,编译qt的工程也要在二级目录下,不过这样是很难做到的,应为这样会使第二级目录变得很混乱,但是这些警告对产生elf是没影响的,忽略了吧。elf的运行目录在第二级目录下倒是还算没问题。

         第二种方案,编译qt的目录可以随意,在../../下建立一个lib文件夹,里面放入对应.so库,运行时也这么做。这么做貌似更好。

         2. [root@lin/home]#./test11

OpenCV Error: Unspecified error (The functionis not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbonsupport. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config,then re-run cmake or configure script) in cvNamedWindow, file/home/opencv/opencv-2.4.7/modules/highgui/src/window.cpp, line 483

terminate called after throwing an instanceof 'cv::Exception'

 what(): /home/opencv/opencv-2.4.7/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-devand pkg-config, then re-run cmake or configure script in function cvNamedWindow

         出现这个的原因是因为用户使用了highgui中的功能,比如cvloadiamge之类的。GTK是开源gui,但是开发板应该是很难搭建起这个gui的,arm下qt的gui貌似也很难让opencv依赖,所以还是不要使用highgui的功能,就乖乖进行opencv和qt的转换吧。。。

         这个转换的问题我很感激学长的一席话,我本来为了解决这个问题还想移植GTK上去呢- -,当他一说不要移植GTK的时候我就突然想到以前做过qt和cv的转换,竟然qt能显示那就让qt去显示吧,哎,茅塞顿开。。。

         突然想想写博文好累啊,自己理解了不简单,让别人也理解那就更难了,但是写博文的时候我也学到了很多,我也会继续把我的学习所得分享出来,大家也要多多和别人交流哦,否则就是闭门造车。

         今天就到这里,米娜桑,我要回去过清明小长假咯,下次见。


你可能感兴趣的:(linux,qt,opencv,cmake,OK6410)