* 1 前言 <https://blog.csdn.net/cv_jason/article/details/79758823#1-前言>
* 2 准备工作 <https://blog.csdn.net/cv_jason/article/details/79758823#2-准备工作>
* 2.1 开发环境 <https://blog.csdn.net/cv_jason/article/details/79758823#21-开发环境>
* 2.2 下载相关文件
<https://blog.csdn.net/cv_jason/article/details/79758823#22-下载相关文件>
* 3 OpenCV for Android的配置
<https://blog.csdn.net/cv_jason/article/details/79758823#3-opencv-for-android的配置>
* 3.1 创建项目 <https://blog.csdn.net/cv_jason/article/details/79758823#31-创建项目>
* 3.2 OpenCV相关文件
<https://blog.csdn.net/cv_jason/article/details/79758823#32-opencv相关文件>
* 3.3 配置文件 <https://blog.csdn.net/cv_jason/article/details/79758823#33-配置文件>
* 3.3.1 build.gradle文件
<https://blog.csdn.net/cv_jason/article/details/79758823#331-buildgradle文件>
* 3.3.2 CMakeList.txt文件
<https://blog.csdn.net/cv_jason/article/details/79758823#332-cmakelisttxt文件>
* 3.3.3 资源文件
<https://blog.csdn.net/cv_jason/article/details/79758823#333-资源文件>
* 4 测试Demo:灰度化图片
<https://blog.csdn.net/cv_jason/article/details/79758823#4-测试demo灰度化图片>
* 4.1 代码 <https://blog.csdn.net/cv_jason/article/details/79758823#41-代码>
* 4.2 程序结果 <https://blog.csdn.net/cv_jason/article/details/79758823#42-程序结果>
* 5 参考链接 <https://blog.csdn.net/cv_jason/article/details/79758823#5-参考链接>


1 前言

  Android
Studio在2.2版本更新之后加入了CMAKE方式配置NDK的方法,这大大简化了之前通过Android.mk和Application.mk两个本地配置文件进行NDK开发的方式。这种方法在后续更新的版本中不断增强,越来越好用,越来越不会出问题。本文基于Android
Studio3.1的版本进行配置,使用CMAKE的配置方式配置OpenCV最新版(截止发文时间是OpenCV
3.4.1),并在最后给出一个灰度转换的测试Demo。

  如果你想通过Android NDK开发配置OpenCV,本文或许对你有用。

2 准备工作

2.1 开发环境

* Java 8 u161
* Windows 10 Enterprise 64bit
* Android Studio 3.1
* OpenCV for Android 3.4.1
* Android NDK 16.1.4479499
* Gradle 4.4
* CMAKE

注意:
NDK更迭比较快,之前一直用14R版本,配置最新版的OpenCV,貌似老出一些莫名其妙的bug,后来更新16R之后,bug莫名其妙的消失了,貌似新版本更强大,推荐用最新版。Gradle脚本大部分是AS自动配置的,一般会自动更新,但如果在update推送弹窗中点了ignore之后,会停止推送,推荐使用最新版本。

2.2 下载相关文件

OpenCV

  OpenCV可以直接在官网上下,官方网址为:https://opencv.org/releases.html
<https://opencv.org/releases.html>

  选择Android pack版本即可,大约310MB,由于服务器在国外,下载速度可能会比较慢,使用迅雷要比FireFox自带的下载器快。

NDK

  NDK并不会随着Android SDK自动下载,需要手动配置——
打开AS -> Settings -> Appearance & Behavior -> System Settings -> Android SDK
->SDK Tools 勾选 NDK,如果CMAKE没有勾选,也要勾选。



  至此,准备工作结束。

3 OpenCV for Android的配置

3.1 创建项目

  创建一个名为OpenCVTest的Android project,注意勾选include C++选项即可。




3.2 OpenCV相关文件

* include文件
  在下载好的OpenCV压缩包中,打开路径下的
.\opencv-3.4.1-android-sdk\OpenCV-android-sdk\sdk\native\jni 有一个include
文件夹,把这个文件夹复制粘贴至我们的OpenCVTest项目中,路径为src/main/cpp
* jni文件
  然后是动态库(.so文件),打开路径下的.\opencv-3.4.1-android-sdk\OpenCV-android-sdk\sdk\native
,有一个libs 文件夹,这个文件夹里面是所有版本的abi的so文件。复制粘贴到我们的项目中,路径为src/main/jniLibs
这个文件夹需要自己手动去创建。
注意:
  1. 无论是include还是libs的路径都可以自定义,习惯上是这样放,但其实只要在之后的CMakeList配置文件里面设置正确就没有问题。
  2.
值得一提的是,OpenCV在最新版本中把动态库和静态库分开了,分别放在libs和staticlbs两个文件夹中,之前是放在一个文件夹里的。我们测试Demo仅需要动态库和头文件即可。

  最后配置好之后文件结构如图所示:


3.3 配置文件

3.3.1 build.gradle文件

  在android 节点中添加如下代码:
sourceSets{ main{ jniLibs.srcDirs = ['src/main/jniLibs/libs'] } }
  这一步设置了动态链接库的路径地址,用于项目构建时,Native寻找和链接相关的so文件。

  然后在Android.defaultConfig.externalNativeBuild 的节点内增加一行过滤器,如下:
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'mips',
'mips64'
  .so文件依赖于硬件环境,不同的CPU架构对应不同的.so文件,abiFilters关键字能够指定Android
所支持的CPU架构,一般是以上7种,最终这些.so文件会被打包进APK,所以可以根据自己的项目进行选择,比如在AS模拟器上开发APP选一个x86
就可以了,如果是手机端,一般是arm架构,选armeabi-v7a 即可。

  最终的build.gradle文件如下:
apply plugin: 'com.android.application' android { compileSdkVersion 26
defaultConfig { applicationId"com.example.videomedicine.opencvtest"
minSdkVersion24 targetSdkVersion 26 versionCode 1 versionName "1.0"
testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild { cmake { cppFlags"-std=c++11 -frtti -fexceptions"
abiFilters'x86' } } ndk{ abiFilters 'x86' } } sourceSets{ main{ jniLibs.srcDirs
= ['src/main/jniLibs/libs'] } } buildTypes { release { minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro' } } externalNativeBuild { cmake { path "CMakeLists.txt" }
} } dependencies { implementation fileTree(dir:'libs', include: ['*.jar'])
implementation'com.android.support:appcompat-v7:26.1.0' implementation
'com.android.support.constraint:constraint-layout:1.0.2' testImplementation
'junit:junit:4.12' androidTestImplementation
'com.android.support.test:runner:1.0.1' androidTestImplementation
'com.android.support.test.espresso:espresso-core:3.0.1' }
  配置完之后,点击Sysn Now 。

3.3.2 CMakeList.txt文件


  这个文件也是NDK开发最最最关键的文件,AS采用CMake脚本语法配置C编译器的环境,如果你之前有过使用CMAKE的经验,或许这并非难题,但对于初学者而言,CMAKE的脚本语法,还是略过于生涩,而且AS对该文件的配置并不友好,居然没有代码提示,于是不得不查很多文档。但好在,NDK的开发大多不是大型的C++项目,也不太需要过于复杂的设置(比如OpenCV源代码的CMAKE文件,大约有几千行的样子
Orz~)

  OpenCV配置CMakeList文件的方式如下:
# For more information about using CMake with Android Studio, read the #
documentation: https://d.android.com/studio/projects/add-native-code.html #
设置CMAKE的版本号 cmake_minimum_required(VERSION 3.4.1) # 设置include文件夹的地址
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include) # 设置opencv的动态库
add_library(libopencv_java3 SHARED IMPORTED) set_target_properties
(libopencv_java3 PROPERTIES IMPORTED_LOCATION${CMAKE_SOURCE_DIR}
/src/main/jniLibs/libs/${ANDROID_ABI}/libopencv_java3.so) add_library( # Sets
the name of the library. native-lib # Sets the library as a shared library.
SHARED# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )find_library( # Sets the name of the path variable.
log-lib# Specifies the name of the NDK library that # you want CMake to locate.
log )target_link_libraries( # Specifies the target library. native-lib
libopencv_java3# Links the target library to the log library # included in the
NDK. ${log-lib} )
include_directories 函数设置了include文件夹的路径
add_library 函数设置库名和类型,其中libopencv_java3 是用户自定义的变量名,前后保持一致即可,SHARE 表示引入的库是动态链接库
set_target_properties 设置了OpenCV的动态链接库的路径
target_link_libraries
具有依赖关系的动态库链接到指定目标上,链接顺序需符合gcc链接规则,这里我们把libopencv_java3和log链接到了native-lib上。

  更详细的CMAKE配置语法,可以参考CMAKE官方文档 <https://cmake.org/cmake/help/v3.11/>
,我们这里仅配置动态链接库,以上四个函数足够了。

3.3.3 资源文件

  把一张图片放入src/main/res/drawable 下,作为我们的测试图,注意,资源文件首字母不能大写。

  至此,配置工作结束。

4 测试Demo:灰度化图片

4.1 代码

* MainActivity.java文件 package com.example.videomedicine.opencvtest; import
android.graphics.Bitmap;import android.graphics.BitmapFactory; import
android.support.v7.app.AppCompatActivity;import android.os.Bundle; import
android.view.View;import android.widget.Button; import android.widget.ImageView;
public class MainActivity extends AppCompatActivity implements View.
OnClickListener{ // Used to load the 'native-lib' library on application
startup. static { System.loadLibrary("native-lib"); } private Button btn_1;
private Button btn_2; private ImageView imageView; private Bitmap bitmap;
@Override protected void onCreate(Bundle savedInstanceState) { super
.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_1 =
(Button)findViewById(R.id.button_1); imageView =
(ImageView)findViewById(R.id.image); bitmap =
BitmapFactory.decodeResource(getResources(),R.drawable.luffy);
imageView.setImageBitmap(bitmap); btn_1.setOnClickListener(this); btn_2 =
(Button)findViewById(R.id.button_2); btn_2.setOnClickListener(this); } public
void showImage(){ bitmap =
BitmapFactory.decodeResource(getResources(),R.drawable.luffy);
imageView.setImageBitmap(bitmap); }public void gray(){ int w =
bitmap.getWidth();int h = bitmap.getHeight(); int[] piexls = new int[w*h];
bitmap.getPixels(piexls,0,w,0,0,w,h); int[] resultData
=Bitmap2Grey(piexls,w,h); Bitmap resultImage = Bitmap.createBitmap(w,h,
Bitmap.Config.ARGB_8888); resultImage.setPixels(resultData,0,w,0,0,w,h);
imageView.setImageBitmap(resultImage); }@Override public void onClick(View
view){switch(view.getId()){ case R.id.button_1:showImage();break; case
R.id.button_2:gray();break; } } /** * A native method that is implemented by
the 'native-lib' native library, * which is packaged with this application. */
public native int[] Bitmap2Grey(int[] pixels,int w,int h); @Override public void
onResume(){ super.onResume(); } }
* native-lib.cpp文件 #include <jni.h> #include<opencv2/opencv.hpp>
#include<iostream> using namespace cv; using namespace std; extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_videomedicine_opencvtest_MainActivity_Bitmap2Grey( JNIEnv
*env, jobject/* this */,jintArray buf,jint w,jint h) { jint *cbuf; jboolean
ptfalse =false; cbuf = env->GetIntArrayElements(buf, &ptfalse); if(cbuf ==
NULL){return 0; } Mat imgData(h, w, CV_8UC4, (unsigned char*)cbuf); //
注意,Android的Bitmap是ARGB四通道,而不是RGB三通道 cvtColor(imgData,imgData,CV_BGRA2GRAY);
cvtColor(imgData,imgData,CV_GRAY2BGRA);int size=w * h; jintArray result =
env->NewIntArray(size); env->SetIntArrayRegion(result,0, size,
(jint*)imgData.data); env->ReleaseIntArrayElements(buf, cbuf,0); return result;
}
* activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app=
"http://schemas.android.com/apk/res-auto" xmlns:tools=
"http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:orientation="vertical"
tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="1"
android:orientation="vertical"> <ImageView android:id="@+id/image"
android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_weight="1" app:srcCompat="@drawable/luffy" /> </LinearLayout> <
LinearLayout android:layout_width="match_parent" android:layout_height=
"wrap_content" android:layout_weight="1" android:orientation="horizontal"> <
Button android:id="@+id/button_2" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="1" android:text=
"灰度图" /> <Button android:id="@+id/button_1" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_weight="1" android:text="色图"
/> </LinearLayout> </LinearLayout>
4.2 程序结果



5 参考链接

[1]. Android Studio 2.3利用CMAKE进行OpenCV 3.2的NDK开发
<http://johnhany.net/2017/07/opencv-ndk-dev-with-cmake-on-android-studio/>
[2]. CMake常用语法总结 <https://www.jianshu.com/p/8909efe13308>
[3]. android使用CMake进行jni编写遇到的一些问题
<https://blog.csdn.net/qqchenjian318/article/details/72780874>
[4]. 设置Button多个监听事件 <https://blog.csdn.net/xiziyunqi/article/details/77850484>
[5]. androidstudio视频录制和截图功能
<https://blog.csdn.net/c529836078/article/details/54378210>
[6]. CMAKE官方文档 <https://cmake.org/cmake/help/v3.11/>

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信