您的位置:首页 > 移动开发 > Android开发

Android Studio 2.2 NDK开发 opencv 人脸识别

2016-11-17 15:13 525 查看
一、开发环境准备

1、Android Studio到 2.2版本,在sdk Manager中下载 ndk-bundle 和 cmake

2、下载OpenCV for Android 下载地址:http://opencv.org/downloads.html

二、搭建环境

1、使用Android Studio 新建一个项目(在c++ suport 上打上对勾)

2、带项目创建好之后,将opencv中的头文件,和动态链接库copy到项目中,并在CMakeLists.txt中引入他们。

最后我们的目录大致如下:



三、编码

1、新建jni类

package com.blueberry.facerec;

/**
* Created by blueberry on 11/16/2016.
* <p>
* 人脸检测
*/
public class FaceDetector {

static {
System.loadLibrary("face_detect");
}

private long cPtr;

public FaceDetector(String path) {
cPtr = init(path);
}

/**
* 初始化CascadeClassifier,需要传入xml文件的路径,CascadeClassifier会根据这个xml文件进行识别。
*
* @param path xml文件的路径
* @return CascadeClassifier的路径
*/
public final native long init(String path);

/**
* 人脸检测
*
* @param path 人脸图片文件的路径
* @return 检测到人脸数据的集合
*/
public final native Face[] detect(String path);

/**
* 删除CascadeClassifier
*
* @param cPtr CascadeClassifier的指针
*/
private final native void delete(long cPtr);

@Override
protected void finalize() throws Throwable {
delete(cPtr);
}

}


package com.blueberry.facerec;

/**
* Created by blueberry on 11/17/2016.
* <p>
* 检测到人脸的坐标
*/
public class Face {

private int x;
private int y;
private int width;
private int height;

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

@Override
public String toString() {
return "Face{" +
"x=" + x +
", y=" + y +
", width=" + width +
", height=" + height +
'}';
}

public int getWidth() {
return width;
}

public void setWidth(int width) {
this.width = width;
}

public int getHeight() {
return height;
}

public void setHeight(int height) {
this.height = height;
}
}


对应的cpp文件

//
// Created by Administrator on 11/16/2016.
//

#ifndef FACERECOGNITION_FACE_DETECT_CPP
#define FACERECOGNITION_FACE_DETECT_CPP

#include "face_detect.h"

using namespace cv;
using namespace std;

CascadeClassifier *g_CascadeClassifier;

JNIEXPORT jlong JNICALL
Java_com_blueberry_facerec_FaceDetector_init(JNIEnv *env, jobject instance, jstring path_) {
const char *path = env->GetStringUTFChars(path_, NULL);
g_CascadeClassifier = new CascadeClassifier(path);
long ptr = reinterpret_cast<long>(g_CascadeClassifier);
env->ReleaseStringUTFChars(path_, path);
LOGD("cascadeClassifier initialized");
return ptr;
}

JNIEXPORT jobjectArray JNICALL
Java_com_blueberry_facerec_FaceDetector_detect(JNIEnv *env, jobject instance, jstring path_) {

if (!g_CascadeClassifier) {
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, "CascadeClassifier not initialized!");
}
// 图片的路径
const char *path = env->GetStringUTFChars(path_, 0);
//单通道模式,读取图片
Mat srcImage = imread(path, IMREAD_GRAYSCALE);
//直方图均值化
equalizeHist(srcImage, srcImage);
vector<Rect> vectors;
g_CascadeClassifier->detectMultiScale(srcImage, vectors);
LOGD("detected.");
jclass objectClass = env->FindClass("com/blueberry/facerec/Face");
// 返回的人脸数组
jobjectArray result = env->NewObjectArray(vectors.size(), objectClass, NULL);
jmethodID cId = env->GetMethodID(objectClass, "<init>", "()V");
jfieldID xId = env->GetFieldID(objectClass, "x", "I");
jfieldID yId = env->GetFieldID(objectClass, "y", "I");
jfieldID widthId = env->GetFieldID(objectClass, "width", "I");
jfieldID heightId = env->GetFieldID(objectClass, "height", "I");
for (int i = 0; i < vectors.size(); i++) {
jobject obj = env->NewObject(objectClass, cId);
env->SetIntField(obj, xId, vectors[i].x);
env->SetIntField(obj, yId, vectors[i].y);
env->SetIntField(obj, widthId, vectors[i].width);
env->SetIntField(obj, heightId, vectors[i].height);
env->SetObjectArrayElement(result, i, obj);
}
env->ReleaseStringUTFChars(path_, path);
return result;
}

JNIEXPORT void JNICALL
Java_com_blueberry_facerec_FaceDetector_delete(JNIEnv *env, jobject instance, jlong cptr) {
cv::CascadeClassifier *cascadeClassifier = reinterpret_cast<cv::CascadeClassifier *>(cptr);
delete cascadeClassifier;
return;
}

#endif //FACERECOGNITION_FACE_DETECT_CPP


四、遇到的坑

1、在编写项目时,我发现ndk-bundle更新了,于是我点了一下更新,满怀激动的心情等到下载完(更新到了ndk 13),但在我编译的时候蛋疼的事情发生了,编译不通过了,搞得我很焦灼。最后静下心来看log 其中报错的信息中有这么一段话:

..... Invalid Android NDK revision (should be 12):


What!!! 真是蛋疼~ ,说明:升级有风险,更新需谨慎啊!,但最后终于找到了一个方法来fix它,打开android_sdk/cmke/3.6.xxxxx/android.toolchain.cake文件,找到报错的那一行:

if(NOT ANDROID_NDK_PACKAGE_REVISION MATCHES "^${ANDROID_NDK_REVISION}\\.")
message(FATAL_ERROR "Invalid Android NDK revision (should be ${ANDROID_NDK_REVISION}): ${ANDROID_NDK_PACKAGE_REVISION}.")
endif()


错误正式从这里出来的。

最后们只需要吧ANDROID_NDK_REVISION 改成13就行了,也就是位于android.toolchain.cmake的 第43行左右 改为 set(ANDROID_NDK_REVISION 13) 好了。

2、在 build.gradle 要引入opencv的动态库文件目录

sourceSets {
main {
java.srcDirs  'src/main/java'
jniLibs.srcDirs  'opencv/prebuilt', 'lib'

}}


其中 opencv/prebuilt为opencv动态库的目录

3、设置 abi类型

ndk {
//打包进APK的ABI类型
abiFilters   'x86'
}


这里只能设置一种ABI类型,设置2个以上就会报错,目前我也不知道什么情况~,有知道的朋友留言哈~

旨在体验Android 2.2 使用NDK开发,代码中若是有不严谨的地方,还望大神勿喷

最后完整项目的地址: https://github.com/blueberryCoder/FaceRecognition
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ndk opencv cmake