ARM开发板6410移植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来选择编译器路径


         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/

         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 



         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文件中加入

  1. INCLUDEPATH+=   /usr/local/arm/4.4.3/opencv/include/opencv     \  
  2.                      /usr/local/arm/4.4.3/opencv/include/opencv2    \  
  3.                      /usr/local/arm/4.4.3/opencv/include  
  4. LIBS+= /usr/local/arm/4.4.3/opencv/lib/libopencv*  
	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间转换用代码:

  1. #include "switch.h"   
  2.   
  3. ImageCVtoQT::ImageCVtoQT(IplImage *_srcImage)  
  4.     :srcImage(_srcImage)  
  5. {  
  6.     assert(srcImage != NULL);  
  7.     width = srcImage -> width;  
  8.     height = srcImage -> height;  
  9.     channel = srcImage -> nChannels;  
  10. }  
  11.   
  12. ImageCVtoQT::~ImageCVtoQT()  
  13. {  
  14.     cvReleaseImage(&srcImage);  
  15. }  
  16.   
  17. const QImage ImageCVtoQT::getQtImage()  
  18. {  
  19.     QImage desImage = QImage(width, height, QImage::Format_RGB32);  
  20.     for(int i=0; i<height; i++)  
  21.     {  
  22.         for(int j=0;j<width; j++)  
  23.         {  
  24.             int r,g,b;  
  25.             if(RGB_TYPE == channel)  
  26.             {  
  27.                 b = (int)CV_IMAGE_ELEM(srcImage, uchar , i, j*3+0);  
  28.                 g = (int)CV_IMAGE_ELEM(srcImage, uchar , i, j*3+1);  
  29.                 r = (int)CV_IMAGE_ELEM(srcImage, uchar , i, j*3+2);  
  30.             }  
  31.             else if(GRAY_TYPE == channel)  
  32.             {  
  33.                 b = (int)CV_IMAGE_ELEM(srcImage, uchar, i, j);  
  34.                 g = b;  
  35.                 r = b;  
  36.             }  
  37.             desImage.setPixel(j, i, qRgb(r, g, b));  
  38.         }  
  39.     }  
  40.     return desImage;  
  41. }  
  42. /   
  43.   
  44. ImageQTtoCV::ImageQTtoCV(QImage _srcImage)  
  45. :srcImage(_srcImage)  
  46. {  
  47.     assert(!srcImage.isNull());  
  48.     width=srcImage.width();  
  49.     height=srcImage.height();  
  50.   
  51. }  
  52. ImageQTtoCV::~ImageQTtoCV()  
  53. {  
  54. }  
  55.   
  56. IplImage *ImageQTtoCV::getCvImage()  
  57. {  
  58.     IplImage *desImage=cvCreateImage(cvSize(width,height),8,3);  
  59.     for(int i=0;i<height;i++)  
  60.     {  
  61.         for(int j=0;j<width;j++)  
  62.         {  
  63.             QRgb rgb=srcImage.pixel(j,i);  
  64.             CV_IMAGE_ELEM(desImage,uchar,i,j*3+0)=qBlue(rgb);  
  65.             CV_IMAGE_ELEM(desImage,uchar,i,j*3+1)=qGreen(rgb);  
  66.             CV_IMAGE_ELEM(desImage,uchar,i,j*3+2)=qRed(rgb);  
  67.         }  
  68.     }  
  69.     return desImage;  
  70. }  
#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头文件供调用:

  1. #ifndef SWITCH_H   
  2. #define SWITCH_H   
  3.   
  4. //#include "highgui.h"   
  5. #include "cv.h"   
  6. #include "cxcore.h"   
  7.   
  8. #include <QImage>   
  9.   
  10.   
  11. #define RGB_TYPE  3   
  12. #define GRAY_TYPE 1   
  13.   
  14. class ImageCVtoQT  
  15. {  
  16. public:  
  17.     ImageCVtoQT(IplImage *_srcImage);  
  18.     ~ImageCVtoQT();  
  19.     const QImage getQtImage(void);  
  20. private:  
  21.     IplImage *srcImage;           
  22.   
  23.     //QImage desImage;             
  24.     int width;  
  25.     int height;  
  26.     int channel;  
  27. };  
  28.   
  29. class ImageQTtoCV  
  30. {  
  31. public:  
  32.     ImageQTtoCV(QImage _srcImage);  
  33.     ~ImageQTtoCV();  
  34.     IplImage *getCvImage(void);  
  35. private:  
  36.     QImage srcImage;  
  37.     int width;  
  38.     int height;  
  39.     //int channel;   
  40. };  
  41.   
  42.   
  43. #endif // 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要贴的内容:
  1. #include "dialog.h"   
  2. #include "ui_dialog.h"   
  3. #include "switch.h"   
  4. #include "QtGui"   
  5.   
  6. Dialog::Dialog(QWidget *parent) :  
  7.     QDialog(parent),  
  8.     ui(new Ui::Dialog)  
  9. {  
  10.     ui->setupUi(this);  
  11.   
  12.     //声明IplImage指针   
  13.     IplImage *pImg = NULL;  
  14.     QImage *qImg = new QImage;  
  15.   
  16.     //载入图片   
  17.     if(!(qImg->load("/home/project/sao22.bmp")))  // 我的开发板支持bmp格式,小心路径   
  18.     {  
  19.         return;  
  20.     }  
  21.   
  22.     //switch   
  23.     ImageQTtoCV qtc(*qImg);  
  24.     pImg = qtc.getCvImage();  
  25.     if(!pImg)  
  26.         return;  
  27.     IplImage *pGrayImg = NULL;  
  28.     pGrayImg = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1);  
  29.     cvCvtColor(pImg, pGrayImg, CV_BGR2GRAY);  
  30.   
  31.     ImageCVtoQT ctq(pGrayImg);  
  32.     *qImg = ctq.getQtImage();  
  33.     if(!qImg)  
  34.         return;  
  35.   
  36.     ui->label->setPixmap(QPixmap::fromImage(*qImg));  
  37. }  
  38.   
  39. Dialog::~Dialog()  
  40. {  
  41.     delete ui;  
  42. }  
#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图片(爱图)了:


         这说明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去显示吧,哎,茅塞顿开。。。

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

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

 

这篇博客有个小错误。

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

这里少写了一个字母改完

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

就可以编译成功了谢谢原作者


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值