NDK纔是Android開發通向超高薪之路。(這句話,彷佛四年前有云)java
難點在於經常使用的non-free module (sift and surf)android
unsw@unsw-UX303UB$ pwd /home/unsw/Android/5-android/NDKTest/app/src/main unsw@unsw-UX303UB$ javah -d jni -classpath ../../build/intermediates/classes/debug com.example.unsw.ndktest.NativeClass
生成了jni目錄, 而且有了一個.h文件。c++
1. 經過.h文件複製粘貼出個.c文件,這樣少輸入這麼長的名字。git
2. 而後,把.h的內容改成.c須要的形式。github
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_unsw_ndktest_NativeClass */ #ifndef _Included_com_example_unsw_ndktest_NativeClass #define _Included_com_example_unsw_ndktest_NativeClass #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_unsw_ndktest_NativeClass * Method: getMessageFromJNI * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_unsw_ndktest_NativeClass_getMessageFromJNI (JNIEnv *, jclass); // 改成以下所示:(其餘刪除) #include <com_example_unsw_ndktest_NativeClass.h> JNIEXPORT jstring JNICALL Java_com_example_unsw_ndktest_NativeClass_getMessageFromJNI (JNIEnv *env, jclass obj) { return env->NewStringUTF("This is message from JNI"); } #ifdef __cplusplus } #endif #endif
3. 添加到此處後,能夠嘗試編譯下,應該不會報錯。app
gradle.properties添加:
android.useDeprecatedNdk=true
4. 繼續添加.mk文件:maven
Android.mkide
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := com_example_unsw_ndktest_NativeClass.cpp LOCAL_LDLIBS += -llog LOCAL_MODULE := MyLib include $(BUILD_SHARED_LIBRARY)
Application.mkgradle
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a //若是是本地模擬器,則爲x86
APP_PLATFORM := android-23
5. Compile, generate *.soui
6. Just use your baby function.
public class MainActivity extends AppCompatActivity { static { System.loadLibrary("MyLibs"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((TextView) findViewById(R.id.textView)).setText(NativeClass.getMessageFromJNI()); } }
若c++調用的是OpenCV lib,以下示範
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> #include <stdio.h> #include <opencv2/opencv.hpp> #include "opencv2/nonfree/nonfree.hpp" using namespace cv; using namespace std; /* Header for class com_example_unsw_jeff_OpencvNativeClass */ #ifndef _Included_com_example_unsw_jeff_OpencvNativeClass #define _Included_com_example_unsw_jeff_OpencvNativeClass #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_unsw_jeff_OpencvNativeClass * Method: convertGray * Signature: (JJ)I */ int toGray(Mat img, Mat& gray); JNIEXPORT jint JNICALL Java_com_example_unsw_jeff_OpencvNativeClass_convertGray (JNIEnv *, jclass, jlong, jlong); #ifdef __cplusplus } #endif #endif
但要注意一個問題:Nonfree Module (SIFT, SURF)
參見以下:
Tutorial - part 1: Using OpenCV Nonfree Module (SIFT, SURF) in Android NDK Projects (可用)
Tutorial - part 2: Use OpenCV Nonfree module (SIFT, SURF) in Android Applications via JNI (可用)
http://stackoverflow.com/questions/28510045/undefined-reference-to-cvinitmodule-nonfree-in-android
直接使用現成lib的tutor: https://www.youtube.com/watch?v=cLK9CjQ-pNI
做者代碼隱藏在了這裏:https://dmigit.uqtr.ca/u/nguidjol
1. 工程下新建文件夾 libraries/,並拷貝過來 java文件夾 in opencv-for-android。
unsw@unsw-UX303UB$ cp ./OpenCV-2.4.9-android-sdk/sdk/ etc/ java/ native/
Copy "java" to libraries and change its name to "opencv"
unsw@unsw-UX303UB$ pwd /home/unsw/Programmer/5-android/nonfree_model unsw@unsw-UX303UB$ ls app gradle gradlew.bat nonfree_model.iml build gradle.properties libraries settings.gradle build.gradle gradlew local.properties unsw@unsw-UX303UB$ ls libraries/ libraries.iml opencv
效果以下:
2. opencv文件夾下 create build.gradle.
apply plugin: 'com.android.library' buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:2.2.3' } } android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { minSdkVersion 23 targetSdkVersion 23 versionCode 1 versionName "1.0" } sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] res.srcDirs = ['res'] aidl.srcDirs = ['src'] } } }
3. settings.gradle添加庫
include ':app' include ':libraries:opencv' //add.
以後,Project structure即可加載libraries:opencv 模塊。
4. 添加sift操做java文件
package com.example.unsw.nonfree_model; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.FaceDetector; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.VideoView; import org.opencv.android.Utils; import org.opencv.core.Mat; import org.opencv.core.MatOfKeyPoint; import org.opencv.features2d.FeatureDetector; import org.opencv.features2d.Features2d; import org.opencv.imgproc.Imgproc; public class MainActivity extends AppCompatActivity { static { System.loadLibrary("opencv_java"); System.loadLibrary("nonfree"); } private ImageView imageView; private Bitmap inputImage; // make bitmap from image resource private FeatureDetector detector = FeatureDetector.create(FeatureDetector.SIFT); @Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); inputImage = BitmapFactory.decodeResource(getResources(), R.drawable.test); setContentView(R.layout.activity_main); imageView = (ImageView) this.findViewById(R.id.imageView); sift(); } public void onResume(){ super.onResume(); } public void sift(){ Mat rgba = new Mat(); Utils.bitmapToMat(inputImage,rgba); MatOfKeyPoint keyPoints = new MatOfKeyPoint(); Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGBA2GRAY); detector.detect(rgba, keyPoints); Features2d.drawKeypoints(rgba, keyPoints, rgba); Utils.matToBitmap(rgba, inputImage); imageView.setImageBitmap(inputImage); } }
以及相對應的 layout。
5. 添加現成的 .so
新建jniLibs,給jniLibs各個目錄內添加.so。
效果圖:(可見sift的特徵點)
(1)爲使OpenCV-2.4.9-android-sdk完整,添加了OpenCV-2.4.9的nonfree文件夾。
unsw@unsw-UX303UB$ ls opencv-2.4.9/modules/nonfree/include/opencv2/nonfree/ features2d.hpp gpu.hpp nonfree.hpp ocl.hpp
unsw@unsw-UX303UB$ ls OpenCV-2.4.9-android-sdk/sdk/native/jni/include/opencv2/nonfree/ features2d.hpp nonfree.hpp
(2)新工程:MyApplication下建立文件夾:nonfree_opencv_android/jni, 其下也添加OpenCV-2.4.9的modules/nonfree/src/* 的內容。
unsw@unsw-UX303UB$ pwd
/home/unsw/Programmer/5-android/MyApplication/nonfree_opencv_android unsw@unsw-UX303UB$ ls jni libs obj //ndk-build後生成的。
// jni 添加如下內容: unsw@unsw-UX303UB$ ls ~/Android/opencv-2.4.9/modules/nonfree/src/
cuda/ opencl/ sift.cpp surf_gpu.cpp
nonfree_init.cpp precomp.hpp surf.cpp surf_ocl.cpp
修改文件裏的內容,按照報錯提示去掉ocl相關的部分便可。
unsw@unsw-UX303UB$ ~/Android/Sdk/ndk-bundle/ndk-build [x86] Compile++ : nonfree <= nonfree_init.cpp In file included from jni/nonfree_init.cpp:43: jni/precomp.hpp:46:10: fatal error: 'cvconfig.h' file not found #include "cvconfig.h" ^ 1 error generated. make: *** [obj/local/x86/objs/nonfree/nonfree_init.o] Error 1 unsw@unsw-UX303UB$ ~/Android/Sdk/ndk-bundle/ndk-build [x86] Compile++ : nonfree <= nonfree_init.cpp jni/nonfree_init.cpp:69:19: error: unknown type name 'SURF_OCL' CV_INIT_ALGORITHM(SURF_OCL, "Feature2D.SURF_OCL", ^ jni/nonfree_init.cpp:69:19: error: use of undeclared identifier 'SURF_OCL' 2 errors generated. make: *** [obj/local/x86/objs/nonfree/nonfree_init.o] Error 1
(3)再添加Android.mk和Application.mk,編譯便可。
APP_ABI := x86 APP_STL := gnustl_static APP_CPPFLAGS := -frtti -fexceptions APP_PLATFORM := android-23
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) OPENCV_INSTALL_MODULES:=on OPENCV_CAMERA_MODULES:=off include /home/unsw/Android/OpenCV-2.4.9-android-sdk/sdk/native/jni/OpenCV.mk LOCAL_C_INCLUDES:= /home/unsw/Android/OpenCV-2.4.9-android-sdk/sdk/native/jni/include LOCAL_MODULE := nonfree LOCAL_CFLAGS := -Werror -O3 -ffast-math LOCAL_LDLIBS += -llog LOCAL_SRC_FILES := nonfree_init.cpp \ sift.cpp \ surf.cpp include $(BUILD_SHARED_LIBRARY)
Compile:
unsw@unsw-UX303UB$ ~/Android/Sdk/ndk-bundle/ndk-build [x86] Compile++ : nonfree <= nonfree_init.cpp [x86] Compile++ : nonfree <= sift.cpp [x86] Compile++ : nonfree <= surf.cpp [x86] Prebuilt : libopencv_java.so <= /home/unsw/Android/OpenCV-2.4.9-android-sdk/sdk/native/jni/../libs/x86/ [x86] SharedLibrary : libnonfree.so [x86] Install : libnonfree.so => libs/x86/libnonfree.so [x86] Install : libopencv_java.so => libs/x86/libopencv_java.so
Success!