代码过程实现
AndroidStudio平台JNI对Opencv环境搭建请参考文章 https://blog.csdn.net/u014159143/article/details/88975487
平台开发环境
- Android Studio 3.2
- opencv-3.4.3-android-sdk
配置文件修改
1、将opencv和app的build.gradle中配置改成一致:
compileSdkVersion 28
minSdkVersion 17
targetSdkVersion 28
2、修改openCVLibrary343\src\main\AndroidManifest.xml文件中的配置(根据你的需要修改)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.opencv"
android:versionCode="3430"
android:versionName="3.4.3">
<!--uses-sdk android:minSdkVersion="17" android:targetSdkVersion="28" /-->
</manifest>
3、在app的build.gradle文件中指定jnilib目录
android {
compileSdkVersion 28
defaultConfig {
... ...
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions"
}
}
}
... ...
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
}
}
4、在CMakeLists.txt文件中添加opencv的库配置
cmake_minimum_required(VERSION 3.4.1)
# 添加opencv的头文件目录
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)
# 导入opencv的so
add_library(opencv_java3 SHARED IMPORTED)
set_target_properties(opencv_java3 PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libopencv_java3.so)
... ...
target_link_libraries( # Specifies the target library.
native-lib opencv_java3
# Links the target library to the log library
# included in the NDK.
${log-lib})
千万注意:以上代码中的三个库名称可以写成opencv_java3、libopencv_java3、mylib等等,这里我先前纠结了很久,主要是发现网上有写成opencv_java3的也有写成libopencv_java3的,后来我查了下cmake的原理才明白, 它的原理就是将你调用的库重新编译成一个文件,当然编译成的名字还是libopencv_java3.so(你可以对比下apk中的so库和libs下的已经不一样了),叫啥名字无所谓,只是方便jni编译和调用而已,但是一定要一致,否则将报错。
好了如果AS没有报错误,恭喜你,你的平台环境已经搭建完成,现在只需要修改代码就可实现你想要的功能了,这里我们还是用网上比较多的图片二值化效果:
编写功能代码
1、编写布局文件layout.xml
首先将你要用的图片拖进来:
编写你的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/ivOld"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:src="@mipmap/luffy"/>
<Button
android:id="@+id/btChange"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点我没用,好看而已,哈哈!"/>
<ImageView
android:id="@+id/ivNew"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:layout_gravity="center_horizontal" />
</LinearLayout>
2、编写MainActivity.java代码
package com.hello;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
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("opencv_java3");
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView ivOld = (ImageView)findViewById(R.id.ivOld);
ImageView ivNew = (ImageView)findViewById(R.id.ivNew);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.luffy);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixArr = new int[width*height];
bitmap.getPixels(pixArr,0,width,0,0,width,height);
gray(pixArr,width,height);
Bitmap newBitmap = Bitmap.createBitmap(width,height,Bitmap.Config.RGB_565);
newBitmap.setPixels(pixArr,0,width,0,0,width,height);
ivNew.setImageBitmap(newBitmap);
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public native int[] gray(int [] pix,int w,int h);
}
说明一下,这里的gray函数是我想添加的native函数,教大家一个快速生成jni接口的方法:将光标放在gray上,按住Alt+Enter,选择Create fuction将自动生成Jni接口函数,怎么样帅不帅,还傻傻的自己写或者javac编译么,哈哈,智能改变工作。
还有一点需要说明的是System.loadlibrary(opencv_java3),在高版本android设备上是不需要的,但是如果低版本就必须写上,而且是在调用opencv_java3的jni库前面写,具体原因不知道,这是我在调试android4.2版本的时候遇到的,都是血与泪的教训啊。
3、编写native-lib.cpp
#include <jni.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
using namespace cv;
extern "C" JNIEXPORT jstring JNICALL
Java_com_test_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_test_MainActivity_gray(JNIEnv *env, jobject instance, jintArray pix_, jint w, jint h) {
jint *pix = env->GetIntArrayElements(pix_, NULL);
if (pix == NULL) {
return 0;
}
#if 1
//将c++图片转成Opencv图片
Mat imgData(h, w, CV_8UC4, (unsigned char *) pix);
uchar* ptr = imgData.ptr(0);
for(int i = 0; i < w*h; i ++){
//计算公式:Y(亮度) = 0.299*R + 0.587*G + 0.114*B
//对于一个int四字节,其彩色值存储方式为:BGRA
int grayScale = (int)(ptr[4*i+2]*0.299 + ptr[4*i+1]*0.587 + ptr[4*i+0]*0.114);
ptr[4*i+1] = grayScale;
ptr[4*i+2] = grayScale;
ptr[4*i+0] = grayScale;
}
#endif
int size = w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result, 0, size, pix);
env->ReleaseIntArrayElements(pix_, pix, 0);
return result;
}
切记一定要加上opencv2/opencv.hpp和using namespace cv;
好了到这里已经全部完成了。下面来看看效果:
如果还有问题的话可以参考我的代码:点我下载