1.前言
由于笔者在配置NDK环境时遇到了各种坑,在爬坑的过程中有所感悟,所以特地写一篇博客来详细描述利用Android Studio3.0.1(版本>=2.2即可)中的CMAKE方式配置NDK的过程,希望能够帮助各位。
2.准备工作
2.1开发环境
- Android Studio 3.0.1(版本>=2.2即可)
- Android NDK 17.1.4828580
- CMAKE
- Android SDK 27.0.1
- OpenCV-3.4.1-android-sdk OpenCV下载地址(点击此链接即可下载)
- 下载ndk,在File->Settings->Appearance & Behavior -> System Settings-> Android SDK下载相应的ndk
- 同时如图所示,下载相应的CMake和LLDB
3.Java OpenCV环境的配置
1.创建一个新项目,注意勾选Include C++ support 选项
根据图示勾选相应的选项后点击Finish即可
2.将OpenCV下面的java文件夹(路径为OpenCV-android-sdk\sdk\java)作为模块导入,导入后会发现在Project目录下生成openCVLibrary341的目录,修改该目录下的build.gradle的compileSDKVersion、buildToolsVersion、minSdkVersion和targetSdkVersion使其和app目录下的build.gradle文件中的相同,点击右上角的Try Again 重新配置应用即可消除错误
3.在主模块中加入对OpenCV Library的依赖(右击左侧边栏的app,选择Open Module Settings,切换到Dependencies窗口,选择Module dependency,若前面成功导入Opencv SDK,这里则会出现类似如图中的选项,选择OK即可将OpenCV引入应用当中)
4.至此,OpenCV的Java层配置已经完成,sync一下,应该就有代码补全了
5.为了愉快的使用OpenCV Library,可以直接在AndroidManifest.xml里面加入如下权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
4.配置NDK环境
1.将include文件夹(路径OpenCV-android-sdk\sdk\native\jni\include)拷贝到cpp目录下(路径\app\src\main\cpp)
2.在\src\main目录下建议一个jniLIbs目录,将依赖的动态库和静态库(路径为OpenCV-android-sdk\sdk\native\jni\libs)中的libopencv_java.so和libopencv_java3.so文件拷贝到\src\main\jniLibs下面
3.完成以上步骤,你的工程结构应该如下图所示
4.修改app中的gradle,修改成如图所示
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.zxing.cameraapplication.forlastopencv07151100"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions"
arguments "-DANDROID_TOOLCHAIN=gcc"
arguments "-DANDROID_ABI=armeabi-v7a"
arguments "-DCMAKE_BUILD_TYPE=Release"
}
}
ndk{
abiFilters "armeabi-v7a"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
productFlavors{
}
sourceSets{ main { jni.srcDirs = ['src/main/jni' , 'src/main/jniLibs/'] } }
}
dependencies {
androidTestCompile('com.android.support:support-annotations:26.1.0') {
force = true
}
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation project(':openCVLibrary341')
}
5.修改CMakeLists.txt文件(重要),修改后如图所示
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_VERBOSE_MAKEFILE on)
set(libs "${CMAKE_SOURCE_DIR}/src/main/jniLibs")
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)
add_library(libopencv_java3 SHARED IMPORTED )
set_target_properties(libopencv_java3 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_java3.so")
add_library(libopencv_java SHARED IMPORTED )
set_target_properties(libopencv_java PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_java.so")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -fexceptions -frtti")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
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 )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
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 )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries(native-lib android log
libopencv_java3 #used for java sdk
libopencv_java #same to static libs
${log-lib}
)
点击右上角sync重新配置即可
5.demo演示(图片灰度化)
1.native-lib.cpp
#include <jni.h>
#include <string>
#include <opencv2/core/hal/interface.h>
#include <opencv2/calib3d.hpp>
using namespace cv;
extern "C" {
JNIEXPORT jintArray JNICALL
Java_com_www_ndk_MainActivity_getGrayImage(JNIEnv *env, jobject, jintArray buf, int w, int h){
jint *pixels = env->GetIntArrayElements(buf, NULL);
if(pixels == NULL){
return NULL;
}
cv::Mat imgData(h, w,CV_8UC4, pixels);
uchar *ptr = imgData.ptr(0);
for(int i=0; i<w*h; i++){
int grayScale = (int)(ptr[4*i+2]*0.299 + ptr[4*i+1]*0.587 + ptr[4*i+0]*0.114);
ptr[4*i+0] = (uchar)grayScale;
ptr[4*i+1] = (uchar)grayScale;
ptr[4*i+2] = (uchar)grayScale;
}
int size = w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result, 0, size, pixels);
env->ReleaseIntArrayElements(buf, pixels, 0);
return result;
}
}
2.activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context="com.www.ndk.MainActivity">
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/boy"
android:layout_centerInParent="true" />
<Button
android:id="@+id/bt_Gray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:text="Gray" />
</RelativeLayout>
3.MainActivity.java
package com.www.ndk;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import org.opencv.core.Mat;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
private Button bt_photo = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// adding
bt_photo = findViewById(R.id.bt_Gray);
bt_photo.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ImageView img = (ImageView)findViewById(R.id.img);
Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(
R.drawable.boy)).getBitmap();
int w = bitmap.getWidth(), h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int[] resultPixes = getGrayImage(pix,w,h);
Bitmap result = Bitmap.createBitmap(w,h, Bitmap.Config.RGB_565);
result.setPixels(resultPixes, 0, w, 0, 0,w, h);
img.setImageBitmap(result);
}
});
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native int[] getGrayImage(int[] pixels, int w, int h);
}
4.将命名为boy的图片放在drawable目录下面
5.运行的结果如图所示
至此,NDK环境已经确定配置好。。。