動機
- 本身是作影像視覺相關的工作,多數時候都使用 Python 作為開發語言,但OpenCV 本身是C++開發,學 C++ 應該有幫助。
- 公司有 Android/iOS Team ,有些功能需要與他們整合,多了解對方領域可以減少溝通成本。
- 網絡上有關 OpenCV 與 Android Studio 整合的教學零散文章,這次整合成功后,把這些碎片化資訊整理起來記錄,避免之后有同樣需求時又辛苦一次,這次整合采了太多坑,如果不做個記錄,三個月后就會忘了。
環境
- Android Studio Chipmunk | 2021.2.1 Patch 1 (Ubuntu 環境)
- JNI 有 cmake 和ndk-build兩種方法,我是用Cmake (版本3.22.1 )如果你參考的教學有用到 Android.mk 或Application.mk ,那這篇有關 build 的方式會很不一樣。
- OpenCV 4.5.5 / 4.6.0
Android Studio 連結 JNI
開啟新工程,使用Base Activity 即可。![540546ce-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/15/wKgZomTnFhWAFh3ZAADHm0KaL1k669.png)
![54271fce-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/15/wKgZomTnFhWAGvGoAACdN1rh79M031.png)
![543b9198-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/15/wKgZomTnFhWAZgSzAAB24MZNxFM635.png)
![5450c2e8-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/15/wKgZomTnFhaAHj_XAACMYB1jGnQ132.png)
![5469d558-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/15/wKgZomTnFhaAAf_qAAB_Qoez4CY168.png)
![5485aa58-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/15/wKgZomTnFhaAbq6aAAGqUdS7ER4587.png)
![54b3c38e-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/15/wKgZomTnFheAANqwAAEduozIjIs853.png)
externalNativeBuild{ cmake{ path"src/main/cpp/CMakeLists.txt" version"3.18.1" } } 備注2: MyOpenCv Module 和app 可以相連是通過settings.gradle 后兩行的include。
pluginManagement{ repositories{ gradlePluginPortal() google() mavenCentral() } } dependencyResolutionManagement{ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories{ google() mavenCentral() } } rootProject.name="MyApp" include':app' include':MyOpenCv'
Cmake 與OpenCV 依賴
先至 OpenCV 官網(https://opencv.org/releases/)下載Andoird 版本并解壓縮到想要的文件夾,這邊示例是在/home/user/Documents/![54d396c8-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFheAcmmAAABkzIgMgKA136.png)
cmake_minimum_required(VERSION3.18.1) set(OpenCV_DIR"/home/jason9075/Documents/OpenCV-android-sdk/sdk/native/jni") find_package(OpenCVREQUIRED) project("myopencv") add_library(myopencv SHARED myopencv.cpp) include_directories(${OpenCV_INCLUDE_DIRS}) find_library(log-lib log) #ForAndroidBitverttocv::Mat find_library(jnigraphics-libjnigraphics) target_link_libraries(myopencv ${OpenCV_LIBS} ${jnigraphics-lib}#ForAndroidBitmapCoverttocv::Mat ${log-lib}) 這時你會發現Sync 失敗, 問題出在CMakeLists.txt 第五行沒有抓到OpenCV 套件。
![54f2cf5c-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFheAE4eqAACwD570oPs618.png)
![55032a28-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFheAW7PtAAEEQLzOv1s648.png)
![552f5634-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhiAQq2xAALKU_aTGFQ669.png)
![5544a246-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhiAfe6-AACtod7bY0M399.png)
![556c8de2-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhiAMJnpAAAyX6v6Pyw010.png)
C/C++:CMakeFiles/cvmodule.dir/cvmodule.cpp.o(.data+0x0):error:undefinedreferenceto'typeinfoforcv::Exception' 的錯誤。
OpenCV bash 開發
- 開發圖片轉灰度功能
extern"C"JNIEXPORTvoidJNICALL Java_com_jason9075_myopencv_NativeLib_toGrey( JNIEnv*env, jobject, jobjectbitmapIn, jobjectbitmapOut){ Matsrc,greyOut; bitmapToMat(env,bitmapIn,src,false); cvtColor(src,greyOut,CV_BGR2GRAY); matToBitmap(env,greyOut,bitmapOut,false); } 然后在NativeLib.java 里要宣告與C++對應的function。
publicclassNativeLib{ static{ System.loadLibrary("myopencv"); } publicnativeStringstringFromJNI(); publicnativevoidtoGrey(BitmapbitmapIn,BitmapbitmapOut); } 為了測試我們到應用程式app文件夾,把Android綠色機器人圖片放到drawable 文件夾,然后在MainActivity 轉成灰色。
![557d1db0-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhiAU12kAAErgrnkXHI141.png)
@Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); binding=ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); NavControllernavController=Navigation.findNavController(this,R.id.nav_host_fragment_content_main); appBarConfiguration=newAppBarConfiguration.Builder(navController.getGraph()).build(); NavigationUI.setupActionBarWithNavController(this,navController,appBarConfiguration); ImageViewiv=findViewById(R.id.imageView); binding.fab.setOnClickListener(newView.OnClickListener(){ @Override publicvoidonClick(Viewview){ Snackbar.make(view,"Replacewithyourownaction",Snackbar.LENGTH_LONG) .setAction("Action",null).show(); } }); //TestHelloWorldFromMyOpenCv NativeLibcv=newNativeLib(); System.out.println(cv.stringFromJNI()); Bitmapimage=BitmapFactory.decodeResource(getResources(),R.drawable.android); cv.toGrey(image,image); iv.setImageBitmap(image); }
![558f71a4-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhiAODO7AAC6ETc9hgs200.png)
- 開發讀取圖片寬高功能
packagecom.jason9075.myopencv; publicclassImageInfo{ privatefinalintwidth; privatefinalintheight; publicImageInfo(intwidth,intheight){ this.width=width; this.height=height; } publicintgetWidth(){ returnwidth; } publicintgetHeight(){ returnheight; } @Override publicStringtoString(){ return"ImageInfo{"+ "width="+width+ ",height="+height+ '}'; } } 在 NativeLib.java 宣告相對應的 function getInfo()
packagecom.jason9075.myopencv; importandroid.graphics.Bitmap; publicclassNativeLib{ static{ System.loadLibrary("myopencv"); } publicnativeStringstringFromJNI(); publicnativevoidtoGrey(BitmapbitmapIn,BitmapbitmapOut); publicnativeImageInfogetInfo(Bitmapbitmap); } 然后在myopencv.cpp 新增C++ 實做方式。須注意的一點是,因為我們最終要回傳 Java Object,所以在C++這邊要定義clsPath ,要找你預期回傳的 Java Class 長的怎么樣,還有這個Class 的Constructor 需要什么樣的signature (這邊 width 和 height 都是 Int 所以是(II)V)。
extern"C" JNIEXPORTjobjectJNICALL Java_com_jason9075_myopencv_NativeLib_getInfo(JNIEnv*env,jobjectthiz,jobjectbitmap){ Matsrc; bitmapToMat(env,bitmap,src,false); intwidth=src.cols; intheight=src.rows; //returnjavaobject constchar*clsPath="com/jason9075/myopencv/ImageInfo"; jclasscls=env->FindClass(clsPath); jmethodIDconstructor=env->GetMethodID(cls,"
//TestHelloWorldFromMyOpenCv NativeLibcv=newNativeLib(); System.out.println(cv.stringFromJNI()); Bitmapimage=BitmapFactory.decodeResource(getResources(),R.drawable.android); cv.toGrey(image,image); iv.setImageBitmap(image); System.out.println(">>>"+cv.getInfo(image)); 我們可以成功讀取到寬高分別為2688 和3197。(這邊和原圖寬高不同的原因是Android 的Drawable 會自動縮放,若想測試原圖可以改放Asset文件夾)
![559f4566-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhiAbtjgAACpo2oNqHA118.png)
打包成 aar 給其他工程使用
上面的工程主要有兩個部分,一個是 app 擁有Activity 來模擬使用這個lib的情況,令一個部分是 MyOpenCv 這個module 為實際lib 的內容,這是我們接下來要介紹的,如何將這個module 轉成aar。首先,我們先點擊 [Build]>[Select Build Varient] 開啟選單,再生成 aar 時可以選擇 debug 或是 release 來發布,這邊我選用release 做示范。![55c3758a-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhiABxFnAACAaXZI-x0688.png)
![55cf6372-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhiAQVy9AAB9JG8z39I259.png)
![55f10590-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhmAERbjAABiRh2rtSU333.png)
![560910f4-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhmAPmkvAACA6zqJ4ak057.png)
![5624df78-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhmAQwPcAADNsFf9DWc383.png)
![5634d91e-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhmAVbgYAAD2HXkgpog066.png)
![565f587e-1c2c-11ed-ba43-dac502259ad0.png](https://file1.elecfans.com//web2/M00/96/16/wKgZomTnFhmAC6CQAAE4XF4mDgI747.png)
代碼:
MyApp: https://github.com/jason9075/Android_with_OpenCV_Module溫馨提醒:使用時module 的CMakeLists.txt 請將OpenCV_DIR換成自己的sdk路徑。AnotherApp: https://github.com/jason9075/Android_use_OpenCV_AAR_libRef
https://developer.android.com/studio/projects/configure-cmakehttps://github.com/ValYouW/AndroidOpenCVDemohttps://stackoverflow.com/questions/9433257/how-to-specify-array-of-class-in-getmethodid-method-signature-parameterhttps://stackoverflow.com/questions/22300848/return-object-from-java-native-methodhttps://stackoverflow.com/questions/51107185/how-to-create-new-android-aar-in-android-studio審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
C++
+關注
關注
22文章
2114瀏覽量
73854 -
OpenCV
+關注
關注
31文章
635瀏覽量
41556 -
JNI
+關注
關注
0文章
8瀏覽量
7875
原文標題:?如何將 OpenCV 整合 Android JNI 開發 C++ 代碼并打包成 aar lib 給其他工程使用
文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
請問C++如何運用到具體的工程中?
學了很多C語言,現在想學習一下C++,但是現在遇到一個問題,就是不知道C++怎么運用到具體的工程中。學習C語言可以在單片機和Linux上
發表于 03-24 04:35
在鴻蒙的Module中使用了JNI無法調試代碼中的C++是為什么
各位大佬,請教個問題。目前在做JNI開發中,在鴻蒙的Module中使用了JNI,如果編譯使用正常,但是調試時無法在C++中調試代碼中的C++
發表于 04-24 11:11
OpenCV C++程序編譯與演示
1、在JetsonNano上編譯OpenCV源碼與OpenCV C++ YOLOv5程序演示 編譯OpenCV最新4.5.x版本 Jetson Nano自帶的
發表于 11-10 16:42
RK3399 Android 7.1系統JNI層使用C/C++輸出Log
Platform: RK3399OS: Android 7.1Kernel: v4.4.83JNI層使用C/C++需要輸出Log.如果不要TAG,那么只要如下使用就可以:#include &
發表于 11-14 18:00
一文簡析JNI層使用C/C++需要輸出Log
Platform: RK3399OS: Android 7.1Kernel: v4.4.83JNI層使用C/C++需要輸出Log.如果不要TAG,那么只要如下使用就可以:#include &
發表于 11-22 17:59
能請教一下官方的pyOCD是怎么打包成獨立exe的嗎?
能請教一下官方的 pyOCD 是怎么打包成獨立 exe 的?最近我也想打包一個 pyOCD,但是用 pyinstaller 打包后,運行提示OSError: cannot load library
發表于 12-05 11:33
C++課程設計教學大鋼
C++課程設計教學大鋼
課程名稱:C++課程設計英文名稱:Course design of C++ Programming面向專業:對計算機要求較高的理工科專業課程總學時:___ 4
發表于 06-25 23:28
?9次下載
程序設計及C++語言課程設計教學大鋼
程序設計及C++語言課程設計教學大鋼:程序設計及C++語言》課程設計教學大鋼(課程設計類)
課程設計 名稱:C++語言課程設計英文名稱:C
發表于 06-25 23:29
?15次下載
RSA算法的JNI封裝步驟
要求較高的算法往往是基于C/C++語言(與硬件關聯性更強)實現的。如果應用程序需要基于JAVA編程實現時,這就會有一些矛盾。此時,通過JNI技術,Java開發者可以在不了解算法內容的情
![RSA算法的<b class='flag-5'>JNI</b>封裝步驟](https://file1.elecfans.com//web2/M00/A7/5B/wKgZomUMRCuAdggYAAAQA-4d5xY089.png)
如何使用Borland C++ Builder6.0來開發OpenCV的程序
本文檔的主要內容詳細介紹的是如何使用Borland C++ Builder6.0來開發OpenCV的程序。
發表于 05-26 17:32
?14次下載
![如何使用Borland <b class='flag-5'>C++</b> Builder6.0來<b class='flag-5'>開發</b><b class='flag-5'>OpenCV</b>的程序](https://file.elecfans.com/web1/M00/BD/8B/pIYBAF7M4jqAE4eyAAX4d7J-cFo398.png)
評論