使用Android NDK编译OpenCV应用
OpenCV 在Android 中的应用
使用Android NDK 编译so 库
简介
在linuxt 系统下使用OpenCV2.3 + NDK R6 编译OpenCV 人脸检测应用
准备
Android NDK ( r5 或更高版本) http://developer.android.com/sdk/ndk/index.html
OpenCV Android 包http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.3/
cmake( 可选,替代NDK) http://www.cmake.org/
注:http://code.google.com/p/android-opencv/ 网站上说要使用crystax ndk r4 代替NDK 。估计可能是对于较旧的Android 版本需要这样。如果NDK 无法编译,请尝试使用crystax ndk r4 编译。
OpenCV 设置
从网站上下载OpenCV 2.3.0 for Android 后,解压到某个目录,如~/ 目录下
设置OPENCV_PACKAGE_DIR 环境变量
$ export OPENCV_PACKAGE_DIR=~/enCV-2.3.0/
新建一个Android 工程
在eclipse 中新建一个android 工程如study.opencv ,并且在工程根目录下新建一个名为jni 的目录。将下载的android-ndk-r6 解压到某个目录下,如~/
从~/android-ndk-r6/sample 下某个sample 中拷贝Android.mk, Application.mk 到study.opencv/jni 目录
设置编译脚本
在Android.mk 中,include $(CLEAR_VARS) 后面,加入下行
include $(OPENCV_PACKAGE_DIR)/$(TARGET_ARCH_ABI)/share/opencv/OpenCV.mk
如果应用支持ARM NEON 那么还需要加入以下行
include $(OPENCV_PACKAGE_DIR)/armeabi-v7a-neon/share/opencv/OpenCV.mk
LOCAL_ARM_NEON := true
在Application.mk 中加入以下行
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
注:关于Android.mk 与Application.mk 的详细说明,请参考ndk/docs 下Android-mk.html 和Application-mk.html 。
Java 层定义native 接口
新建study.opencv.FaceRec 类,定义一个人脸检测的本地接口
/**
* detect front face from image.
*
* @param xml
* opencv haarcascade xml file path
* @param infile
* input image file path
* @param outfile
* output image file path
*/
public native void detect(String xml, String infile, String outfile);
生成jni 头文件
使用javah 命令生成jni 头文件
$ cd ~/workspace/study.opencv/bin
$ javah study.opencv.FaceRec
会在bin 目录生成一个study_opencv_FaceRec.h 文件。将此文件拷贝到../jni 目录中
注:如果接口有变更,请先手动删除生成的.h 文件。以防止一些意外的错误。
在c 层实现图像人脸检测
在jni 目录中使用文本编辑器新建一个facedetect.cpp ,实现图像人脸检测
Cpp代码
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>
#include <android/log.h>
#include <study_opencv_FaceRec.h>
#include <jni.h>
#define LOG_TAG "opencv_face_detect"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
static CvMemStorage* storage = 0;
static CvHaarClassifierCascade* cascade = 0;
void detect_and_draw( IplImage* image );
const char* cascade_name =
"haarcascade_frontalface_alt.xml";
/* "haarcascade_profileface.xml";*/
/*int captureFromImage(char* xml, char* filename);*/
char* jstring2String(JNIEnv*, jstring);
int captureFromImage(char* xml, char* filename, char* outfile)
{
LOGI("begin: ");
// we just detect image
// CvCapture* capture = 0;
IplImage *frame, *frame_copy = 0;
const char* input_name = "lina.png";
if(xml != NULL)
{
cascade_name = xml;
}
if(filename != NULL)
{
input_name = filename;
}
LOGI("xml=%s,filename=%s", cascade_name, input_name);
// load xml
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
LOGI("load cascade ok ? %d", cascade != NULL ? 1 : 0);
if( !cascade )
{
LOGI("ERROR: Could not load classifier cascade\n" );
// I just won't write long full file path, to instead of relative path, but I failed.
FILE * fp = fopen(input_name,"w");
if(fp == NULL){
LOGE("create failed");
}
return -1;
}
storage = cvCreateMemStorage(0);
// cvNamedWindow( "result", 1 );
IplImage* image = cvLoadImage( input_name, 1 );
if( image )
{
LOGI("load image successfully");
detect_and_draw( image );
// cvWaitKey(0);
if(outfile != NULL)
{
LOGI("after detected save image file");
cvSaveImage(outfile, image);//把图像写入文件
 
补充:移动开发 , Android ,