2016年,公司讓我做個手機號碼識別功能,主要是快遞運單上面的機打手機號碼,當時研究了好長時間的OpenCV 也沒有接入成功,主要是想把手機號碼那塊區域提取出來直接讓Google的開源Tesseract OCR庫來進行識別.因為OpenCV這個玩意兒里面的代碼全是C++寫的,當時的進度又比較趕,我一看C++的代碼看都看不懂就沒仔細研究,只把拍出來的照片進行了寬高限制,所以最終對準備號碼就比較麻煩了,導致被領導說了一通,顯得我這一年里面沒什么進步,工資也沒加多少。所以心情不開心!
為了能讓自己的工作能得到領導的認可,在過完年后的工作里,我特意抽時間再研究了下OpenCV,終于把這個難題解決了。
上面都是我說的廢話,看下面:
網上找了很多辦法,大多在Activity中OnResume這個方法中寫的是下面這串代碼:
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_2_0, getapplicationContext(), mLoaderCallback);經過我的測試,這句代碼是要讓你在你的手機上裝一個對應你CPU處理器的Manager APK。但是在正常的工作中,你總不會讓使用你APP的用戶也裝一個Manager apk包吧~~所以還是要使用一個編譯好了的so庫。
不用擔心,這個SO庫就在你從OpenCV官網上下載的包中:C:/Users/kb82/Desktop/open_cv/OpenCV-android-sdk/sdk/native/libs 當然了,這個只是我存放在電腦上的目錄
。
---【圖一】
--【圖二】這個就是你需要的.so庫了
好了,廢話不多說了!下面是重點:
Step1:下載OpenCV下載地址 http://opencv.org/點擊打開鏈接
【圖三】
點擊進入后等待幾秒便開始下載了。下載到哪兒需要自己設置找一下,一般在系統下載目錄里可以找到。
由于下載的包里存在【圖二】中的.so庫我們就不配置NDK了~
Step2:導入OpenCV的sdk
2-1 AS中執行-->File->New->Inport Module,找出OpenCV-android-sdk目錄下sdk中的java文件夾。
導入成功以后如下圖:
2-2導入libopencv_java3在項目app/src/main目錄下新建文件夾jniLibs,然后將OpenCV-android-sdk目錄下的
/sdk/native/libs對應的各個平臺.so文件放進去。
導入成功以后如下圖:
2-3到這里,我們還沒有結束-需要在app-build.gradle中的android節點中加入自定義 jni的地址。(我的地址如下:)
sourceSets { main { jniLibs.srcDirs = ['src/main/jniLibs'] } }這樣,我們的工作就算完成了。這樣我們就算配置好了該有的資源了。
那么有的人又會問,我這樣配置好了為什么系統還是存在需要安裝manager 的APK文件呢?原因出在我們初始化openCV的時候!
Opencv 在初始化的時候需要執行這樣一個API:
/** * Loads and initializes OpenCV library using OpenCV Engine service. * @param Version OpenCV library version. * @param AppContext application context for connecting to the service. * @param Callback object, that implements LoaderCallbackInterface for handling the connection status. * @return Returns true if initialization of OpenCV is successful. */public static boolean initAsync(String Version, Context AppContext, LoaderCallbackInterface Callback){ return AsyncServiceHelper.initOpenCV(Version, AppContext, Callback);}進入到initOpenCV方法中我們可以看他是如何處理的:
public static boolean initOpenCV(String Version, final Context AppContext,final LoaderCallbackInterface Callback){ AsyncServiceHelper helper = new AsyncServiceHelper(Version, AppContext, Callback); // 下面兩句Intent就是啟動OpenCV Manager中相關服務的 Intent intent = new Intent("org.opencv.engine.BIND"); intent.setPackage("org.opencv.engine"); if (AppContext.bindService(intent, helper.mServiceConnection, Context.BIND_AUTO_CREATE)){ return true; } else { AppContext.unbindService(helper.mServiceConnection); InstallService(AppContext, Callback); return false; }}// 由上面我們知道OpenCV Manager是如何給OpenCV Api提供動太庫的。那我們如何不使用這個方法呢~OpencvLoader 所在的類有兩個方法一直沒有被使用過。我們可以找到看一下/***Loads and initializes OpenCV library from current application package. Roughly, it's an analog of system.loadLibrary("opencv_java").*@return Returns true is initialization of OpenCV was successful.*/ public static boolean initDebug(){ return StaticHelper.initOpenCV(false); }/*** Loads and initializes OpenCV library from current application package. Roughly, it's an analog of system.loadLibrary("opencv_java").* @param InitCuda load and initialize CUDA runtime libraries.* @return Returns true is initialization of OpenCV was successful.*/ public static boolean initDebug(boolean InitCuda){ return StaticHelper.initOpenCV(InitCuda); }我們看注釋Loads and initializes OpenCV library from current applicationpackage.Roughly,it's an analog of system.loadLibrary("opencv_java").
這說明,我們可以把所需要的包放到本地,但是是哪個包呢,從注釋里可以大概知道應該是libopencv_java3.so這個包,即我們之前放在jniLibs中對應的.so。
我們跟進代碼看一下
PRivate static boolean initOpenCVLibs(String Libs){ Log.d(TAG, "Trying to init OpenCV libs"); boolean result = true; if ((null != Libs) && (Libs.length() != 0)){ Log.d(TAG, "Trying to load libs by dependency list"); StringTokenizer splitter = new StringTokenizer(Libs, ";"); while(splitter.hasMoreTokens()){ result &= loadLibrary(splitter.nextToken()); } }else{ // If dependencies list is not defined or empty. result &= loadLibrary("opencv_java3"); } return result;}Step3:最后一步
說到這里,還差最后一步了,就是使用本地so庫。
在你使用界面的OnResume界面直接加一句下面的代碼:
if (!OpenCVLoader.initDebug()){// 默認加載opencv_java.so庫}上面那兩個基本相似的initDebug()一個是使用cuda利用gpu跑算法的,一個是不用的,從他的名字可以看出來.
這樣不裝Manager也就可以使用了。
結束~
新聞熱點
疑難解答