1. Background: NDK + JNI: It is equivalent to a middleware, which provides a native way for Java to call C/C++ code.
2. Principles and processes that you understand: C/C++ code is compiled into so (dynamic link library [CSAPP]) through NDK, and Java can get the interfaces in the C/C++ code by loading these sos, so that these interfaces can be called.
3. Process:
1) First, you need to configure the basic environment: Java + AS3.0 + LLDB + CMAKE. (SDK Manager)
2) NDK: We can go to the official website to download the official website -> extract the compressed package to the directory with the SDK.
3) OpenCV: Download the corresponding package from the official website .
4) Unzip the downloaded package to a folder where your user has read and write permissions.
5) Create a new project: Create it in the default way. [I tried it myself by using CMakeList, and I will add it later]
6) Create a new folder named jni under app/src/main:
7) Copy the Opencv/sdk/native folder into the project:
8) Create Android.mk Application.mk related .h and .cpp files under the jni folder just created:
9) Create your own interface:
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
extern "C" {
JNIEXPORT jintArray JNICALL Java_com_example_za_xxxxxx_myapplication_TestOpen_gray
(JNIEnv *env, jobject obj, jintArray buf, jint w, jint h) {
jint *cbuf;
cbuf = env->GetIntArrayElements(buf, JNI_FALSE);
if (cbuf == NULL) {
return 0;
}
Mat imgData(h, w, CV_8UC4, (unsigned char*) cbuf);
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+1] = grayScale;
ptr[4*i+2] = grayScale;
ptr[4*i+0] = grayScale;
}
int size = w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result, 0, size, cbuf);
env->ReleaseIntArrayElements(buf, cbuf, 0);
return result;
}
}
Among them: JNI interface naming rules:
JNIEXPORT Return type JNICALL Java_package name class name function name (you can also use javah to generate .h files)
10) Write Android.mk and Application.mk files:
#Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OpenCV_INSTALL_MODULES := on
OpenCV_CAMERA_MODULES := off
OPENCV_LIB_TYPE := STATIC
#为了能正确找到opencv的头文件,需要自己定义路径,在这个例子里面是这个路径,其他的视情况而定。
#ifeq ("$(wildcard $(OPENCV_MK_PATH"))", "")
include ..\..\..\..\native\jni\OpenCV.mk
#else
#include $(OPENCV_MK_PATH)
#endif
LOCAL_MODULE := test-open
#自己的文件名
LOCAL_SRC_FILES := com_example_za_xxxxxx_myapplication_TestOpen.cpp
LOCAL_LDLIBS += -lm -llog
include $(BUILD_SHARED_LIBRARY)
#使用GNU的静态(.a)STL
APP_STL := gnustl_static
#支持动态类型绑定,加入异常机制
APP_CPPFLAGS := -frtti -fexceptions
#需要编译的so的平台前面两个是大部分手机使用的平台,X86是模拟器
APP_ABI := armeabi armeabi-v7a x86
11) Create a .java under the java folder:
12) Java code:
public class TestOpen {
static {
System.loadLibrary("test-open");
}
public static native int[] gray(int[] buf, int w, int h);
}
The function definition in this step can be combined with the interface definition in the .cpp file, and you can roughly know the naming rules in the .cpp file.
13) Use the command line to enter the jni directory, ndk-build project:
14) In order to correctly reference the so compiled just now, we need to add relevant references to the build.gradle file of the app: the
last sentence is the reference to so, the countdown The second sentence is to prohibit the built-in NDK function.
15) Define the layout of the Activity and related Java code:
<?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"
tools:context="com.example.za_xxxxxx.myapplication.MainActivity"
android:orientation="vertical">
<TextView
android:id="@+id/main_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
<ImageView
android:id="@+id/main_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/blood"/>
<Button
android:id="@+id/main_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Convert"
android:textAlignment="center"
android:textAllCaps="false"/>
</LinearLayout>
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.main_button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bitmap bitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.blood)).getBitmap();
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int[] resultPixes = TestOpen.gray(pix, w, h);
Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
result.setPixels(resultPixes, 0, w, 0, 0, w, h);
ImageView imageView = findViewById(R.id.main_imageview);
imageView.setImageBitmap(result);
}
});
}
}
16) Run the APP, you can get the following effects:
At this point, the project can be developed using OpenCV.