1. 程式人生 > >ARM開發板OK6410移植opencv-2.4.7庫qt介面顯示(附加各種問題解決方案)

ARM開發板OK6410移植opencv-2.4.7庫qt介面顯示(附加各種問題解決方案)

轉載:http://blog.csdn.net/jiebaoabcabc/article/details/22935185

         經過了昨天一天苦逼的研究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*  

         4.新建switch.cpp原始檔,複製上IplImage與QImage間轉換用程式碼:

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

         5.新建switch.h標頭檔案供呼叫:

  1. #ifndef SWITCH_H
  2. #define SWITCH_H
  3. //#include "highgui.h"
  4. #include "cv.h"
  5. #include "cxcore.h"
  6. #include <QImage>
  7. #define RGB_TYPE  3
  8. #define GRAY_TYPE 1
  9. class ImageCVtoQT  
  10. {  
  11. public:  
  12.     ImageCVtoQT(IplImage *_srcImage);  
  13.     ~ImageCVtoQT();  
  14.     const QImage getQtImage(void);  
  15. private:  
  16.     IplImage *srcImage;           
  17.     //QImage desImage;          
  18.     int width;  
  19.     int height;  
  20.     int channel;  
  21. };  
  22. class ImageQTtoCV  
  23. {  
  24. public:  
  25.     ImageQTtoCV(QImage _srcImage);  
  26.     ~ImageQTtoCV();  
  27.     IplImage *getCvImage(void);  
  28. private:  
  29.     QImage srcImage;  
  30.     int width;  
  31.     int height;  
  32.     //int channel;
  33. };  
  34. #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. Dialog::Dialog(QWidget *parent) :  
  6.     QDialog(parent),  
  7.     ui(new Ui::Dialog)  
  8. {  
  9.     ui->setupUi(this);  
  10.     //宣告IplImage指標
  11.     IplImage *pImg = NULL;  
  12.     QImage *qImg = new QImage;  
  13.     //載入圖片
  14.     if(!(qImg->load("/home/project/sao22.bmp")))  // 我的開發板支援bmp格式,小心路徑
  15.     {  
  16.         return;  
  17.     }  
  18.     //switch
  19.     ImageQTtoCV qtc(*qImg);  
  20.     pImg = qtc.getCvImage();  
  21.     if(!pImg)  
  22.         return;  
  23.     IplImage *pGrayImg = NULL;  
  24.     pGrayImg = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1);  
  25.     cvCvtColor(pImg, pGrayImg, CV_BGR2GRAY);  
  26.     ImageCVtoQT ctq(pGrayImg);  
  27.     *qImg = ctq.getQtImage();  
  28.     if(!qImg)  
  29.         return;  
  30.     ui->label->setPixmap(QPixmap::fromImage(*qImg));  
  31. }  
  32. Dialog::~Dialog()  
  33. {  
  34.     delete ui;  
  35. }  

         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. [[email protected]/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去顯示吧,哎,茅塞頓開。。。

         突然想想寫博文好累啊,自己理解了不簡單,讓別人也理解那就更難了,但是寫博文的時候我也學到了很多,我也會繼續把我的學習所得分享出來,大家也要多多和別人交流哦,否則就是閉門造車。

         今天就到這裡,米娜桑,我要回去過清明小長假咯,下次見。