如何用源碼編譯包含有opencl的opencv

在opencv的sdk裏面拷貝一個include和lib庫,結構如下

~/opencl_sdk
├── include
│   └── CL
│       ├── cl_d3d10.h
│       ├── cl_d3d11.h
│       ├── cl_dx9_media_sharing.h
│       ├── cl_egl.h
│       ├── cl_ext.h
│       ├── cl_gl_ext.h
│       ├── cl_gl.h
│       ├── cl.h
│       ├── cl.hpp
│       ├── cl_platform.h
│       └── opencl.h
├── lib
│   └── libOpenCL.so

在~下創建一個opencv目錄,然後將我們的opencv的源碼拷貝進去

mkdir opencv

cd opencv

cp -a  ~/opencv-3.3.0 .

mkdir build

在~/.bashrc裏面加上ndk和cmake的環境變量

export ANDROID_NDK=/opt/android-ndk-r14b

export PATH=$PATH:/opt/android-ndk-r14b:/opt/arm-linux-androideabi/bin:~/android/prebuilts/sdk/tools/linux/bin:/usr/bin/:/usr/local/cmake-3.0.1/bin

export OPENCL_SDK=~/opencl_sdk
保存後source一下

source ~/.bashrc

然後進入到build目錄下進行配置

cd ~/opencv/build

cmake -Wno-dev \

-DCMAKE_CXX_FLAGS=-std=c++11 \
-DCMAKE_TOOLCHAIN_FILE=../opencv-3.3.0/platforms/android/android.toolchain.cmake \
-DANDROID_ABI="arm64-v8a" \
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
-DBUILD_ANDROID_EXAMPLES=OFF \
-DBUILD_SHARED_LIBS=ON \
-DINSTALL_ANDROID_EXAMPLES=OFF \
-DWITH_OPENCL=YES \
-DANDROID_OPENCL_SDK=$OPENCL_SDK \
-DANDROID_NATIVE_API_LEVEL=14 \
-DANDROID_SDK_TARGET=24 \

../opencv-3.3.0

配置完後編譯

make -j8

最後安裝

make install

在~/opencv/build/install/sdk/native/libs/arm64-v8a下就會生成動態庫

但是生成的動態庫裏面並沒有發現libopencv_java3.so

在CMakeLists.txt裏面查看Java的部分如下

# ========================== java ==========================
status("")
status("  Java:")
status("    ant:"           ANT_EXECUTABLE      THEN "${ANT_EXECUTABLE} (ver ${ANT_VERSION})"                    ELSE NO)
if(NOT ANDROID)
  status("    JNI:"         JNI_INCLUDE_DIRS    THEN "${JNI_INCLUDE_DIRS}"                                       ELSE NO)
endif()
status("    Java wrappers:" HAVE_opencv_java                                                            THEN YES ELSE NO)
status("    Java tests:"    BUILD_TESTS AND opencv_test_java_BINARY_DIR                                 THEN YES ELSE NO)

這裏可以知道編譯生成libopencv_java.so需要滿足ANT_EXECUTABLE      

究其原因是因爲我們沒有安裝ant

安裝ant比較簡單我就不介紹了

裝好後查看一下ant版本號,一定要大於1.09

archermind@flm:~/test/jni$ ant -version
Apache Ant(TM) version 1.10.1 compiled on February 2 2017

archermind@flm:~/opencv/build$ gedit cvconfig.h &


/* OpenCL Support */
#define HAVE_OPENCL
/* #undef HAVE_OPENCL_STATIC */
/* #undef HAVE_OPENCL_SVM */

從配置文件中我們可以知道當前配置是支持opencl的

archermind@flm:~/opencv/build$ gedit CMakeDownloadLog.txt&

use_cache "/home/archermind/opencv/opencv-3.3.0/.cache"
do_unpack "4.4.3.tar.gz" "8e3e39e1fdfb3f7c3a5ac8ec1afe186e" "https://github.com/01org/tbb/archive/4.4.3.tar.gz" "/home/archermind/opencv/build/3rdparty/tbb"
#check_md5 "/home/archermind/opencv/opencv-3.3.0/.cache/tbb/8e3e39e1fdfb3f7c3a5ac8ec1afe186e-4.4.3.tar.gz"
#remove_unpack "/home/archermind/opencv/build/3rdparty/tbb"
#mkdir "/home/archermind/opencv/build/3rdparty/tbb"
#unpack "/home/archermind/opencv/build/3rdparty/tbb" "/home/archermind/opencv/opencv-3.3.0/.cache/tbb/8e3e39e1fdfb3f7c3a5ac8ec1afe186e-4.4.3.tar.gz"

這裏的log是一份正常的log,但是我之前遇到的問題是這裏的下載失敗,不支持ssl協議。

因爲ssl協議會關係到https協議,所以不支持的話,是不能下載成功的,所以我們需要重新安裝ssl

在安裝ssl之前我重新安裝了一下cmake,並重新配置了環境變量

  cd ~/;wget --no-check-certificate https://cmake.org/files/v3.9/cmake-3.9.0.tar.gz
  sudo tar xzvf ~/cmake-3.9.0.tar.gz .
  sudo tar xzvf ~/cmake-3.9.0.tar.gz -C .
  cd cmake-3.9.0/

然後我們在~/.bashrc中export這個cmake的bin路徑

接着安裝ssl

   sudo apt-get  install libcurl4-openssl-dev
  ./bootstrap --system-curl
   sudo ./bootstrap --system-curl
   make
   sudo make install
   curl --version

安裝成功的話會出現下面的打印

curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets

從Protocols: dict file ftp ftps gopher http https  可知這個curl支持https了

在.bashrc文件中的環境變量設置如下

export ANDROID_NDK=/opt/android-ndk-r14b
export NDK_TOOLCHAINS=/opt/arm-linux-androideabi/bin
export ANDROID_SDK_TOOLCHAINS=~/android/prebuilts/sdk/tools/linux/bin
export CMAKE_DIR=~/cmake-3.9.0/bin

export PATH=$PATH:$ANDROID_NDK:$NDK_TOOLCHAINS:$CMAKE_DIR

export OPENCL_SDK=~/opencl_sdk
export OPENCV_ANDROID_SDK=~/opencv/build


export ANT_HOME=/usr/local/apache-ant

export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64

export PATH=$JAVA_HOME/bin:$PATH:$ANT_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/ssl/lib

然後重新編譯

  cd build/
   rm -fr *
   rm -fr ../opencv-3.3.0/.cache/

安裝TBB的支持


然後執行下面的cmake編譯

cmake -Wno-dev \
-DCMAKE_CXX_FLAGS=-std=c++11 \
-DCMAKE_C_FLAGS="-ffunction-sections -fdata-sections -fvisibility=hidden -O3" \
-DCMAKE_TOOLCHAIN_FILE=../opencv-3.3.0/platforms/android/android.toolchain.cmake \
-DANDROID_ABI="arm64-v8a" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
-DBUILD_ANDROID_EXAMPLES=OFF \
-DINSTALL_ANDROID_EXAMPLES=OFF \
-DWITH_OPENCL=YES \
-DWITH_TBB=ON \
-DANDROID_OPENCL_SDK=$OPENCL_SDK \
-DANDROID_NATIVE_API_LEVEL=14 \
-DANDROID_SDK_TARGET=24 \
../opencv-3.3.0

這裏配置了支持opencl,引用了$OPENCL_SDK下的64位的libOpenCL.so

配置完後編譯安裝

 make -j8
 make install
 find -iname *.so
 cp ./install/sdk/native/libs/arm64-v8a/libopencv_java3.so /mnt/hgfs/share/

然後將libopencv_java3.so push到開發板的/system/lib64/下面,庫生效的話需要adb reboot

下面就是編譯一個執行文件,調用我們生成的libopencv_java3.so

archermind@flm:~/test/jni$ ls
Android.mk  Application.mk   test.cpp
archermind@flm:~/test/jni$ cat Android.mk
LOCAL_PATH:= $(call my-dir)  
include $(CLEAR_VARS)  
NDK_APP_DST_DIR := $(LOCAL_PATH)
include ~/opencv/build/install/sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES := test.cpp
LOCAL_CFLAGS := -D__cpusplus -g -mfloat-abi=hard -mfpu=neon-vfpv4 -march=armv8-a -mtune=cortex-a53
TARGET_ARCH_ABI :=arm64-v8a 
LOCAL_ARM_MODE := arm

ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
LOCAL_ARM_NEON := true 
endif   
LOCAL_MODULE := test     
include $(BUILD_EXECUTABLE)

test.cpp內容如下

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/ocl.hpp"
#include <arm_neon.h>
#include <chrono>

class q_timer { 
public: 
void start()
{
m_start = std::chrono::steady_clock::now();
}
double stop()
{
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
return  std::chrono::duration_cast<std::chrono::duration<double> >(end - m_start).count();
}
void time_display(const char *disp = "", int nr_frame = 1)
{
printf("Running time (%s) is: %5.5f Seconds.\n", disp, stop() / nr_frame);
}
void fps_display(const char *disp = "", int nr_frame = 1)
{
printf("Running time (%s) is: %5.5f frame per second.\n", disp, (double)nr_frame / stop());
}
private: 
std::chrono::steady_clock::time_point m_start;
 };

using namespace cv;
void neon_convert(uint8_t * __restrict dest, uint8_t * __restrict src, int n)
{
int i;
uint8x8_t rfac = vdup_n_u8(77);       // 轉換權值  R      
uint8x8_t gfac = vdup_n_u8(151);    // 轉換權值  G      
uint8x8_t bfac = vdup_n_u8(28);      // 轉換權值  B      


n /= 8;

for (i = 0; i<n; i++)
{
uint16x8_t  temp;
uint8x8x3_t rgb = vld3_u8(src);
uint8x8_t result;

temp = vmull_u8(rgb.val[0], rfac);       // vmull_u8 每個字節(8bit)對應相乘,結果爲每個單位2字節(16bit)      
temp = vmlal_u8(temp, rgb.val[1], gfac);  // 每個比特對應相乘並加上      
temp = vmlal_u8(temp, rgb.val[2], bfac);

result = vshrn_n_u16(temp, 8);  // 全部移位8位      
vst1_u8(dest, result);   // 轉存運算結果      
src += 8 * 3;
dest += 8;
}
}

int main()
{
if( cv::ocl::haveOpenCL())

   printf("have opencl");

Mat src = imread("cap1.png", 1);
Mat dst;
q_timer time;time.start();
bilateralFilter(src, dst, 20, 20, 20);
time.time_display("process mat");
cv::UMat usrc, udst;
time.start();
src.copyTo(usrc);
  time.time_display("copy umat");
time.start();
bilateralFilter(usrc, udst, 20, 20, 20);
        time.time_display("process umat");
time.start();
udst.copyTo(dst);
  time.time_display("copy umat");
}

這樣在~/test/jni/路徑下用ndk-build就可以生成一個執行文件test

我們將這個test push到我們的開發板並執行test

結果如下

amt6757_wifi_n:/data # ./test
have opencl

Running time (process mat) is: 7.87340 Seconds.
Running time (copy umat) is: 0.06674 Seconds.
Running time (process umat) is: 0.47743 Seconds.
Running time (copy umat) is: 8.84810 Seconds.


注意:我把下載源碼的網址給改了,配置時,發現哈希碼(commit的版本號)不匹配,於是我將打印中的哈希碼拷貝到我的cmake裏面,重新配置就好了

在~/opencv/opencv-3.3.0/3rdparty/tbb/CMakeLists.txt裏面修改https爲"https://github.com/01org/tbb/archive/"

set(tbb_src_dir "${OpenCV_BINARY_DIR}/3rdparty/tbb")
ocv_download(FILENAME ${tbb_filename}
             HASH ${tbb_md5}
             URL
               "${OPENCV_TBB_URL}"
               "$ENV{OPENCV_TBB_URL}"
               "https://github.com/01org/tbb/archive/"
             DESTINATION_DIR ${tbb_src_dir}
             ID TBB
             STATUS res
             UNPACK RELATIVE_URL)

下載之前設置哈希碼

set(tbb_md5 "8e3e39e1fdfb3f7c3a5ac8ec1afe186e")


參考鏈接

http://blog.csdn.net/bloodfeast/article/details/77824713

https://stackoverflow.com/questions/44593680/building-opencv4android-from-source-does-not-output-libopencv-java-so

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章