NDK & OpenCV
如何建立一個OpenCV相機
- 先建立一個class ->
OpenNativeClass.java
// OpenNativeClass.java
public class OpenNativeClass {
public native static int convertGray(long matAddrRgba, long matAddrGray);
}
- 這裡
convertGray
會跳出ERROR,先不用理會,儲存後先Rebuild Project
一次 然後到Terminal輸入:
cd app/src/main
先進行資料夾切換 再輸入:javah -d jni -classpath ../../build/intermediates/classes/debug YourPackageName.OpenNativeClass
會發現
main
下面多了一個jni
資料夾 先複製your_package_name_OpenNativeClass.h
直接貼上,並重新命名為your_package_name_OpenNativeClass.cpp
OpenNativeClass.h
修改為:
#include <jni.h>
#include <stdio.h>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#ifndef _Included_com_klapper_opencvcamera_OpenNativeClass
#define _Included_com_klapper_opencvcamera_OpenNativeClass
#ifdef __cplusplus
extern "C" {
#endif
int toGray(Mat img, Mat& gray);
JNIEXPORT jint JNICALL Java_com_klapper_opencvcamera_OpenNativeClass_convertGray
(JNIEnv *, jclass, jlong, jlong);
#ifdef __cplusplus
}
#endif
#endif
OpenNativeClass.cpp
修改為:
#include <Your_Package_Name_OpenNativeClass.h>
JNIEXPORT jint JNICALL Java_your_package_name_OpenNativeClass_convertGray
(JNIEnv *, jclass, jlong addrRgba, jlong addrGray){
Mat& mRgb = *(Mat*)addrRgba;
Mat& mGray = *(Mat*)addrGray;
int conv;
jint retVal;
conv = toGray(mRgb, mGray);
retVal = (jint)conv;
return retVal;
}
int toGray(Mat img, Mat& gray){
cvtColor(img, gray, CV_RGBA2GRAY);
if(gray.rows==img.rows && gray.cols==img.cols)
return 1;
return 0;
}
新增Android.mk & Application.mk
於剛剛.h
和.cpp
檔案的資料夾jni
新增兩個檔案
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCVROOT:=D:/androidSample/OpenCVCamera/app/src/main
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include ${OPENCVROOT}/native/jni/OpenCV.mk
LOCAL_SRC_FILES := com_klapper_opencvcamera_OpenNativeClass.cpp
LOCAL_LDLIBS += -llog -ldl
LOCAL_MODULE := MyOpencvLibs
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-16
修改build.gradle
android:
defaultConfig {
...
...
externalNativeBuild {
cmake {
cppFlags "-std=c++11","-frtti","-fexceptions"
}
}
ndk{
abiFilters 'armeabi-v7a','x86', 'armeabi','mips'
}
}
sourceSets.main{
jni.srcDirs =[]
}
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK'){
commandLine "C:/XXXXXX/AppData/Local/Android/Sdk/ndk-bundle/ndk-build.cmd",
'NDK_PROJECT_PATH=build/intermediates/ndk',
'NDK_LIBS_OUT=src/main/jniLibs',
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
'NDK_APPLICATION_MK=src/main/jni/Application.mk'
}
tasks.withType(JavaCompile){
compileTask -> compileTask.dependsOn ndkBuild
}
基本配置完成
修改主程式- MainActivity.java
public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2{
private static final String TAG = "MainActivity";
JavaCameraView javaCameraView;
Mat mRgba, imgGray,imgCanny,mGray;
static{
System.loadLibrary("MyOpencvLibs");
}
BaseLoaderCallback mLoaderCallBack = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch(status){
case BaseLoaderCallback.SUCCESS:
javaCameraView.enableView();
break;
default:
super.onManagerConnected(status);
break;
}
super.onManagerConnected(status);
}
};
static {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
javaCameraView = (JavaCameraView)findViewById(R.id.java_camera_view);
javaCameraView.setVisibility(SurfaceView.VISIBLE);
javaCameraView.setCvCameraViewListener(this);
}
@Override
protected void onPause(){
super.onPause();
if(javaCameraView!=null)
javaCameraView.disableView();
}
@Override
protected void onDestroy(){
super.onDestroy();
if(javaCameraView!=null)
javaCameraView.disableView();
}
@Override
protected void onResume(){
super.onResume();
if(OpenCVLoader.initDebug()){
Log.d(TAG, "static initializer: successfully");
mLoaderCallBack.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}else{
Log.d(TAG, "static initializer: Load fault.");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_13,this,mLoaderCallBack);
}
}
@Override
public void onCameraViewStarted(int width, int height) {
mRgba = new Mat(height,width, CvType.CV_8UC4);
mGray = new Mat(height,width, CvType.CV_8UC1);
imgGray = new Mat(height,width, CvType.CV_8UC1);
imgCanny = new Mat(height,width, CvType.CV_8UC4);
}
@Override
public void onCameraViewStopped() {
mRgba.release();
}
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
OpenNativeClass.convertGray(mRgba.getNativeObjAddr(),mGray.getNativeObjAddr());
//Imgproc.cvtColor(mRgba,imgGray,Imgproc.COLOR_RGB2GRAY);
//Imgproc.Canny(imgGray,imgCanny,30,150);
return mGray;
}
}
於activity_layout.xml 新增widget
<org.opencv.android.JavaCameraView
android:id="@+id/java_camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
於AndroidManifest.xml 新增權限
<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"/>