OpenCV中文網站

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
熱搜: 安裝 配置
查看: 322|回復: 3
打印 上一主題 下一主題

卡昂休闲女鞋: 搭建Android+QT+OpenCV環境,實現“單色圖片著色”效果

[復制鏈接]
跳轉到指定樓層
1#
發表于 2019-9-25 20:18:25 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式

OpenCV是我們大家非常熟悉的圖像處理開源類庫;在其新版本將原本在Contrib分庫中的DNN??槿諍系攪酥骺庵?,并且更新了相應文檔。這樣我們就能夠非常方便地利用OpenCV實現一些屬于DeepLearning范疇的效果,比如“超級分辨率”“單色圖片著色”“色彩遷移”等。當我們想把軟件處理的平臺由PC機轉移到嵌入式平臺和手機上的時候,QT也是能和OpenCV配合地非常好的平臺。在這里,我具體研究了如何搭建Android+QT+OpenCV環境,實現“單色圖片著色”效果;并將相關內容整理如下,希望能夠對有這方面需求的工程師提供幫助。
一、環境配置
        首先我們面臨的問題是工具版本的選擇,雖然我們已經確定了Android+QT+OpenCV的基本軟件結構,但是在每一個環節都需要選擇具體的版本。
        Android需要選擇的是sdk和ndk的版本,我這里使用的是Android10(API29)+android-ndk-r20的組合,基本上是現在(2019年9月)最新的組合了;
QT需要選擇的是QT和QT Creator,我這里選擇的是QT 5.13.1+QT Creator 4.10.0,同樣是現在(2019年9月)最新的組合;

        OpenCV用于Android的話,官方有Prebuild版本,我這里采用的是opencv-4.1.0-android-sdk。
1、SDK的下載和配置
       首先我們正確安裝JDK并且將其目錄放入PATH中,而后需要下載android-sdk、android-ndk-r20、OpenCV-android-sdk,并且分別解壓放置在非中文無空格的目錄中。(下載地址看文末)
2、QT的安裝和配置
       下載QT在線安裝程序直接安裝,安裝過程中除了默認選中的“Developer and designer Tools”以外,只需選中QT5.13.1下的“Android Armv7”即可。


完成后主要是做一個配置“工具”->"選項“中”設備“欄目"JDK""SDK""NDK"都配置到正確的目錄下


這里容易出現各種錯誤,盡可能保證使用我推薦的軟件版本,避免錯誤影響進度。
此時,你應該就已經可以在Android上運行QT自帶的例子。


         任意選擇一個例子,比如“Qt 3D: Audio Visualizer Example ”,選擇之前配置好的Kits,連接好實體手機或者模擬器(參考文末鏈接),點擊“運行”,稍等一會,即可出現效果。


        這里需要注意,第一次運行可能需要從網絡上下載一些東西,所以請保證網絡順暢。
3、OpenCV環境的引入
  
  下面我們想辦法將OpenCV環境引入進來,之前已經下載了“OpenCV-android-sdk",它的文件目錄是這樣:


這時,需要我們配置QT項目的.pro文件,最為重要的就是在.pro文件中添加這個???br />   
    android {
ANDROID_OPENCV = D:/OpenCV-android-sdk/sdk/native
INCLUDEPATH += \
$$ANDROID_OPENCV/jni/include/opencv2 \
$$ANDROID_OPENCV/jni/include \


LIBS += \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_ml.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_objdetect.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_calib3d.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_video.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_features2d.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_highgui.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_flann.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_imgproc.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_dnn.a \
$$ANDROID_OPENCV/staticlibs/armeabi-v7a/libopencv_core.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/libcpufeatures.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/libIlmImf.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/liblibjasper.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/liblibjpeg-turbo.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/liblibpng.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/liblibprotobuf.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/liblibtiff.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/liblibwebp.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/libquirc.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/libtbb.a \
$$ANDROID_OPENCV/3rdparty/libs/armeabi-v7a/libtegra_hal.a \
$$ANDROID_OPENCV/libs/armeabi-v7a/libopencv_java4.so

}


  
這里就是告訴QT到哪里去尋找OpenCV-android-sdk的include文件和libs文件,最后,還需要將libopencv_java4.so添加到項目中
  


  
  
方法是對于當前項目,點擊“項目”->“詳情”->"add"將這個libopencv_java4.so加進去,需要注意這里有bug,添加完成后,需要手動修
  
改.pro文件這個部分至正確:
  
  
    contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
ANDROID_EXTRA_LIBS = \
D:/OpenCV-android-sdk/sdk/native/libs/armeabi-v7a/libopencv_java4.so




  
  4、DNN模型的引入
  
       由于所有的DNN模型都需要調用模型文件(.pb等),而這些文件都必須預先編譯到APK中去。使用 Qt 如何來做了?還是在.pro文
件上下功夫。
  
   打開 Qt 工程文件pro,并添加如下代碼
  
    data.files += images/*.*
data.files += dnn/*.prototxt
data.files += dnn/*.caffemodel
data.path = /assets/dnn
INSTALLS += data




  
  
注意,這里只是我的示例寫法,images和dnn是我手動添加的和工程文件 pro 同級目錄的文件夾


里面分別包含了圖片和模型文件:



  
再來看.pro中添加的這個部分
  
   data.files += images/*.*
data.files += dnn/*.prototxt
data.files += dnn/*.caffemodel
data.path = /assets/dnn
INSTALLS += data


  
其中data字段是可以隨便定義的,首先指定data.files 文件目錄,然后將images目錄下所有的文件,dnn目錄下所有的.prototxt和.caffemodel
  
全部加入其中。最后制定data.path為/assets/dnn
  
這樣編譯出來的 apk 中,加壓后會發現已經生成一個assets文件夾,并且在改文件夾中存放了我們已經添加的文件。
  


  
我們可以通過winrar打開apk,發現這些文件。


  
那么到目前為止,所有需要準備的東西都已經停當,我們開始編碼。
  

二、代碼編寫
這里我給出的例子是一個非常簡單的widget程序(截圖可能和題圖有所不同,以這里的為準)


包含1個textbox和2個button按鈕。我們直接按照從上到下的順序來看代碼。
首先是"讀取Lena并顯示“,這個按鈕的功能比較存粹,就是使用OpenCV從前面保存的assets目錄中讀出lena.jpg,并且最終利用QT顯示出來。
void MainWindow:n_pushButton_2_clicked()
{
QFile::copy("assets:/dnn/lena.bmp", "lena.bmp");
Mat src = imread("lena.bmp");
cvtColor(src,src,COLOR_BGR2GRAY);
QPixmap qpixmap = Mat2QImage(src);
// 將圖片顯示到label上
ui->label->setPixmap(qpixmap);
}




逐句來看,首先使用QFile::copy函數將"assets:/dnn/lena.bmp"拷貝到根目錄下的"lena.bmp"處,這樣OpenCV就能夠使用絕對路徑來讀??;
接下來讀入這個圖片,轉換為灰度圖片,這些都是基本OpenCV函數。然后我們使用了Mat2QImage函數將Mat格式的數據轉換成為了QPixmap格式,并且使用label顯示出來。
那么Mat2QImage是一個我們自己實現的函數,功能就是將Mat格式轉換為QImage格式,這樣QT就能夠顯示。
   //格式轉換
QPixmap Mat2QImage(Mat src)
{
QImage img;
//根據QT的顯示方法進行轉換
if(src.channels() == 3)
{
cvtColor( src, tmp, COLOR_BGR2RGB );
img = QImage( (const unsigned char*)(tmp.data), tmp.cols, tmp.rows, QImage::Format_RGB888 );
}
else
{
img = QImage( (const unsigned char*)(src.data), src.cols, src.rows, QImage::Format_Grayscale8 );
}
QPixmap qimg = QPixmap::fromImage(img) ;
return qimg;
}





其次是“調用著色算法”,這個函數就是在前面的基礎上添加了較多功能。
void MainWindow:n_pushButton_clicked()
{
QFile::copy("assets:/dnn/lena.jpg", "lena.jpg");
QFile::copy("assets:/dnn/colorization_deploy_v2.prototxt", "colorization_deploy_v2.prototxt");
QFile::copy("assets:/dnn/colorization_release_v2.caffemodel", "colorization_release_v2.caffemodel");
Mat src = imread("lena.jpg");
cvtColor(src,tmp,COLOR_BGR2GRAY);
cvtColor(tmp,src,COLOR_GRAY2BGR);


string modelTxt = "colorization_deploy_v2.prototxt";
string modelBin = "colorization_release_v2.caffemodel";
bool useOpenCL = true;

// fixed input size for the pretrained network
const int W_in = 224;
const int H_in = 224;
Net net = dnn::readNetFromCaffe(modelTxt, modelBin);
if (useOpenCL)
net.setPreferableTarget(DNN_TARGET_OPENCL);

// setup additional layers:
int sz[] = { 2, 313, 1, 1 };
const Mat pts_in_hull(4, sz, CV_32F, hull_pts);
Ptr<dnn:ayer> class8_ab = net.getLayer("class8_ab");
class8_ab->blobs.push_back(pts_in_hull);
Ptr<dnn:ayer> conv8_313_rh = net.getLayer("conv8_313_rh");
conv8_313_rh->blobs.push_back(Mat(1, 313, CV_32F, Scalar(2.606)));

// extract L channel and subtract mean
Mat lab, L, input;
src.convertTo(tmp, CV_32F, 1.0 / 255);
cvtColor(tmp, lab, COLOR_BGR2Lab);
extractChannel(lab, L, 0);
cv::resize(L, input, Size(W_in, H_in));
input -= 50;

// run the L channel through the network
Mat inputBlob = blobFromImage(input);
net.setInput(inputBlob);
Mat result = net.forward();

// retrieve the calculated a,b channels from the network output
Size siz(result.size[2], result.size[3]);
Mat a = Mat(siz, CV_32F, result.ptr(0, 0));
Mat b = Mat(siz, CV_32F, result.ptr(0, 1));
cv::resize(a, a, src.size());
cv::resize(b, b, src.size());

// merge, and convert back to BGR
Mat color, chn[] = { L, a, b };
merge(chn, 3, lab);
cvtColor(lab, color, COLOR_Lab2BGR);

color.convertTo(tmp,CV_8UC3,255);

QPixmap qpixmap = Mat2QImage(tmp);
// 將圖片顯示到label上
ui->label->setPixmap(qpixmap);
}





這個代碼比較長,我們一塊一塊地來講,首先仍然是將assets目錄中的文件拷貝到絕對地址下面;
然后這個比較長的代碼具體實現的功能就是調用模型實現著色效果,這里我整編一些之前寫的東西。
目前使用的這個模型來自Richard Zhang,原始論文:


目前算法能夠實現較好的灰度圖片作色效果,他所采用的方法是基于大量圖片的訓練來“預測”灰色圖片中對應的彩色效果。下圖是論文中的對比。


為了程序的成功運行,需要先前往
//eecs.berkeley.edu/~rich.zhang/projects/2016_colorization/files/demo_v2/colorization_release_v2.caffemodel
https://raw.githubusercontent.com/richzhang/colorization/master/colorization/models/colorization_deploy_v2.prototxt
下載caffeemodel和prototxt文件。整個過程中很多代碼,只有幾行是核心的:


其他的代碼都是為了能夠將各種文件轉換成forward支持的格式。其中調用了一個大的常量:
   static float hull_pts[] = {
-90., -90., -90., -90., -90., -80., -80., -80., -80., -80., -80., -80., -80., -70., -70., -70., -70., -70., -70., -70., -70.,
-70., -70., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -60., -50., -50., -50., -50., -50., -50., -50., -50.,
-50., -50., -50., -50., -50., -50., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -40., -30.,
-30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -30., -20., -20., -20., -20., -20., -20., -20.,
-20., -20., -20., -20., -20., -20., -20., -20., -20., -10., -10., -10., -10., -10., -10., -10., -10., -10., -10., -10., -10., -10.,
-10., -10., -10., -10., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 10., 10., 10.,
10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20.,
20., 20., 20., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 30., 40., 40., 40., 40.,
40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 40., 50., 50., 50., 50., 50., 50., 50., 50., 50., 50.,
50., 50., 50., 50., 50., 50., 50., 50., 50., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60., 60.,
60., 60., 60., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 70., 80., 80., 80.,
80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 80., 90., 90., 90., 90., 90., 90., 90., 90., 90., 90.,
90., 90., 90., 90., 90., 90., 90., 90., 90., 100., 100., 100., 100., 100., 100., 100., 100., 100., 100., 50., 60., 70., 80., 90.,
20., 30., 40., 50., 60., 70., 80., 90., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., -20., -10., 0., 10., 20., 30., 40., 50.,
60., 70., 80., 90., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., -40., -30., -20., -10., 0., 10., 20.,
30., 40., 50., 60., 70., 80., 90., 100., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., -50.,
-40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100., -60., -50., -40., -30., -20., -10., 0., 10., 20.,
30., 40., 50., 60., 70., 80., 90., 100., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90.,
100., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., -80., -70., -60., -50.,
-40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., 90., -90., -80., -70., -60., -50., -40., -30., -20., -10.,
0., 10., 20., 30., 40., 50., 60., 70., 80., 90., -100., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30.,
40., 50., 60., 70., 80., 90., -100., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70.,
80., -110., -100., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., -110., -100.,
-90., -80., -70., -60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., 80., -110., -100., -90., -80., -70.,
-60., -50., -40., -30., -20., -10., 0., 10., 20., 30., 40., 50., 60., 70., -110., -100., -90., -80., -70., -60., -50., -40., -30.,
-20., -10., 0., 10., 20., 30., 40., 50., 60., 70., -90., -80., -70., -60., -50., -40., -30., -20., -10., 0.
};



這些數據的產生都和作者原始采用的模型有密切關系,想要完全理解Dnn的代碼就必須了解對應模型的訓練過程。

三、參考和技巧
1、看到我這里使用“夜神”模擬器來調試Android程序是不是很感興趣?具體使用起來是有技巧滴,請參考
如何使用”夜神“作為虛擬機來進行程序調試2、在QTCreator的“工具->外部”選項下,可以配置一些外部程序,比如我把“夜神”和"SDK Manger"配置在這里,方便使用


3、發現Qt Creatror使用designer修改了界面但是編譯無反應的解決方法,請具體參考
Qt Creatror使用designer修改了界面但是編譯無反應的解決方法

4、配置過程的參考建議。
        這里分為3個步驟,首先是使用QT編寫Android程序,然后是實現Android+OpenCV,最后是Android+OpenCV+DNN,應該說是漸進方式的,每個步驟都有不同的參考資料。
        step1:配置QT編寫Android程序
https://blog.csdn.net/yongheng0852/article/details/78875855
https://www.cnblogs.com/MakeView660/p/11206268.html
https://www.cnblogs.com/jsxyhelu/p/8286476.html
         step2:Android上運行OpenCV
  https://blog.csdn.net/u012230798/article/details/86620400
  https://www.cnblogs.com/jsxyhelu/p/8449222.html
  https://blog.csdn.net/tututuo/article/details/83419612

          step3:Android+OpenCV+DNN

https://blog.csdn.net/m0_38133212/article/details/88032546
https://blog.csdn.net/m0_38133212/article/details/87979923
https://blog.csdn.net/luoyayun361/article/details/84800539
5、各個軟件下載地址,注意優先選擇X86_64版本
  
Android SDK https://www.androiddevtools.cn/
  
Android NDK https://developer.android.google.cn/ndk/downloads/index.html
  
Qt+QTCreator https://www1.qt.io/download-open-source-access/
  
OpenCV4Android https://sourceforge.net/projects/opencvlibrary/files/4.1.0/opencv-4.1.0-android-sdk.zip/download
  
6、最后,提供完整的代碼。但是你需要根據機器的實際情況進行修改
  鏈接:https://pan.baidu.com/s/1oYo4iTihkKuG8eneBV7tmQ
提取碼:00k9
  


           總體感覺,開發基于Android的圖像處理程序,是一件比較繁瑣的事情,可能出現問題的地方比較多,特別是QT的資料相對較少;但是一旦配置成功、摸清楚其中的原理之后,就能夠非常方便地將桌面圖像程序算法移植過來,但是也需要注意算法移植過程中的一些小技巧。
  感謝閱讀至此,希望有所幫助!


分享到:  QQ好友和群QQ好友和群
收藏收藏
2#
發表于 2019-10-3 09:46:58 | 只看該作者
不錯!
另外,代碼的地方建議用tag標簽,否則看起來會出現一大堆圖標。
3#
 樓主| 發表于 2019-10-9 21:44:22 | 只看該作者
OK, 現在論壇里面優質和原創資料太少,如何創建合理的環境吸引更多人將原創資料發布過來,值得思考。
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|卡昂瘦身鞋  

GMT+8, 2019-10-19 22:38 , Processed in 0.052150 second(s), 16 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回復 卡昂瘦身鞋 返回列表