1. 程式人生 > >為Android平臺編譯支援OpenCL的Opencv靜態庫

為Android平臺編譯支援OpenCL的Opencv靜態庫

Opencv中封裝了OpenCL,直接下載的Opencv4Android SDK中提供了一些相關的庫,我們可以利用nm命令檢視這些庫是否包含opencl的相關函式。ocl整合在core中,所以我們直接檢視libopencv_core.a這個庫。

nm -D libopencv_core.a

檢視結果如下圖,其中包含了ocl、opencl等.o檔案。

這裡寫圖片描述

也許,這還不能斷定這個靜態庫是否支援OpenCL,那麼最好的方法就是寫一個測試程式,去嘗試獲取手機的GPU資訊,之後我也會寫一篇文章來介紹Android平臺的GPU資訊獲取。大家可以利用OpenCL-Z這個軟體來檢視手機平臺的GPU資訊。

OpenCL-Z.apk

當然,我們可以親自動手去編譯一套可以支援opencl的庫,本文也基於OpenCV3.2.0,介紹如何編譯Opencl支援庫。

工具準備:

Cmake的安裝和配置 點選下載cmake ,需要指定cmake的系統變數,安裝過程有個選項可以選上,會自動新增Cmake的bin目錄到path變數中。
Android NDK:可以到官網下載或者直接用Android studio安裝,同樣也需要指定NDK的系統變數。
Opencv Sources的下載官網百度雲

關鍵檔案修改:

  • 修改CMakeList.txt:
    這裡寫圖片描述

    開啟該檔案,找到WITH_OPENCL這一項,將其狀態修改為ON:
    這裡寫圖片描述

  • 修改opencl_core.cpp檔案:

    開啟檔案..\modules\core\src\opencl\runtime\opencl_core.cpp,找到 #if defined(linux)這一項將其修改為:
    #if defined(__linux__)&&!defined(__ANDROID__)

    如下:

    
    #if defined(__linux__)&&!defined(__ANDROID__)
    
    
    #include <dlfcn.h>
    
    
    #include <stdio.h>
    
    ......
    
    #endif //linux

    在上面這片程式碼塊之後新增Android的編譯程式碼:

    
    #if defined(__ANDROID__)
    
        #include <dlfcn.h>
        #include <sys/stat.h>
    
    
    #if defined(__ARM_ARCH_8A__) || defined(_X64_)
    
        static const char *default_so_paths[] = {
                                                "/system/lib64/libOpenCL.so",
                                                "/system/vendor/lib64/libOpenCL.so",
                                                "/system/vendor/lib64/egl/libGLES_mali.so"
                                              };
    
    #else
    
        static const char *default_so_paths[] = {
                                                "/system/lib/libOpenCL.so",
                                                "/system/vendor/lib/libOpenCL.so",
                                                "/system/vendor/lib/egl/libGLES_mali.so"
                                              };
    
    #endif
    
    
    static int access_file(const char *filename)
        {
            struct stat buffer;
            return (stat(filename, &buffer) == 0);
        }
    
        static void* GetProcAddress (const char* name)
        {
            static void* h = NULL;
            unsigned int i;
            if (!h)
            {
                const char* name;
                for(i=0; i<(sizeof(default_so_paths)/sizeof(char*)); i++)
                {
                    if(access_file(default_so_paths[i])) {
                        name = (char *)default_so_paths[i];
                        h = dlopen(name, RTLD_LAZY);
                        if (h) break;
                    }
                }
                if (!h)
                    return NULL;
            }
    
            return dlsym(h, name);
        }
        #define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name)
    
    #endif
    

編譯Opencv

在..\platforms\目錄下建立一個新資料夾opencv_armeabi_v7a並進入該目錄,建立一個opencv_build.bat檔案,檔案裡面的內容如下:

cmake -G "MinGW Makefiles" -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DWITH_EIGEN=off -DCMAKE_TOOLCHAIN_FILE=..\android\android.toolchain.cmake -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows-x86_64\bin\make.exe" -DANDROID_NATIVE_API_LEVEL=23 -DANDROID_ABI=armeabi-v7a ..\..
cmake --build .

上面ANDROID_NDK是Android NDK的home目錄,需要在環境變數中指定好
-DANDROID_NATIVE_API_LEVEL=23: 指定api level為android-23
-DANDROID ABI=armeabi-v7a: 指定編譯的架構為armeabi-v7a, 它可以指定為以下這些:
·”armeabi-v7a”, “armeabi”, “armeabi-v7a with NEON”, “armeabi-v7a-hard with NEON”, “armeabi-v7a with VFPV3”, “armeabi-v6 with VFP”, “arm64-v8a”, “mips”, “mips64”, “x86”, “x86_64”
雙擊opencv_build.bat執行編譯命令,耐心等待,等很久。

這裡寫圖片描述

編譯完成後,可以在lib目錄下找到編譯好的靜態庫。這時候再利用nm命令去檢視庫中的資訊,就可以知道是否包含有opencl相關的cpp檔案了。當然,大家可以寫一個小demo來驗證這些庫是否支援OpenCL。如何寫一個demo來檢驗一些編譯庫呢,可以參閱:Opencv4Android的OpenCL的測試,使用Opencv的ocl封裝庫