JAVA應用JNI調用OpenCV實現人臉檢測

1.JAVA的JNI部分
調用JNI的基類

package lveyo.bcndyl.jni.opencv;
public class JNIBase {

public JNIBase(){}

public JNIBase(String libraryName){
loadLibrary(libraryName);
}

private static void loadLibrary(String libraryName){
System.loadLibrary(libraryName);
}

}


實現這個基類
package lveyo.bcndyl.jni.opencv;

public class JNIOpencv extends JNIBase{

public JNIOpencv (String libraryName){
super(libraryName);
}

public JNIOpencv(){
System.loadLibrary("jniOpenCV");
}

public native int[] detectFace(int minFaceWidth, int minFaceHeight,
String cascade, String filename);

}


類中定義了一個detectFace方法,是要用C來實現的。

編譯好這個類後,要用在命令行用javah命令生成需要的.h的頭文件:
[quote]
javah lveyo.bcndyl.jni.opencv.JNIOpencv
[/quote]
會生成一個名爲lveyo_bcndyl_jni_opencv_JNIOpencv.h的頭文件:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class lveyo_bcndyl_jni_opencv_JNIOpencv */

#ifndef _Included_lveyo_bcndyl_jni_opencv_JNIOpencv
#define _Included_lveyo_bcndyl_jni_opencv_JNIOpencv
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: lveyo_bcndyl_jni_opencv_JNIOpencv
* Method: detectFace
* Signature: (IILjava/lang/String;Ljava/lang/String;)[I
*/
JNIEXPORT jintArray JNICALL Java_lveyo_bcndyl_jni_opencv_JNIOpencv_detectFace
(JNIEnv *, jobject, jint, jint, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif


2.C程序部分
按照[url]http://www.opencv.org.cn/index.php/Template:Install[/url]安裝OpenCV並配置相應的開發環境,我這裏用的是VS2005,同時要將JDK中的include目錄和include/win32目錄都加入到VS2005的Include Files中。
新建一個win32 MFC DLL項目jniOpenCV,把剛纔生成的lveyo_bcndyl_jni_opencv_JNIOpencv.h頭文件加入到項目,並且修改jniOpenCV.cpp文件:
#include "stdafx.h"
#include <jni.h>
#include "lveyo_bcndyl_jni_opencv_JNIOpencv.h"
#include "cv.h"
#include "highgui.h"

JNIEXPORT jintArray JNICALL Java_lveyo_bcndyl_jni_opencv_JNIOpencv_detectFace
(JNIEnv *env, jobject obj, jint width, jint height, jstring cascade, jstring filename)
{
const char *str_cascade, *str_filename;
str_cascade = env->GetStringUTFChars(cascade, false);
str_filename = env->GetStringUTFChars(filename, false);

jintArray faceArray;
CvHaarClassifierCascade *cv_cascade = (CvHaarClassifierCascade*)cvLoad( str_cascade );
IplImage *image = cvLoadImage( str_filename, 1 );

if(image!=0){

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* faces;

//double t = (double)cvGetTickCount();
/* use the fastest variant */
faces = cvHaarDetectObjects( image, cv_cascade, storage, 1.2, 2,
CV_HAAR_DO_CANNY_PRUNING, cvSize(width, height) );
//t = (double)cvGetTickCount() - t;
//printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );


const int total = faces->total;

faceArray = env-> NewIntArray(4*total);
jint faceBuf[4];

for( int i = 0; i < total; i++ )
{
CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i );
int pointX = face_rect.x;
int pointY = face_rect.y;
int faceWidth = face_rect.width;
int faceHeight = face_rect.height;

//printf("i %d, x %d, y %d, width %d, height %d\n",
// i,pointX,pointY,faceWidth,faceHeight);


faceBuf[0] = pointX;
faceBuf[1] = pointY;
faceBuf[2] = faceWidth;
faceBuf[3] = faceHeight;


env->SetIntArrayRegion(faceArray,i*4,4,faceBuf);

}

cvReleaseMemStorage( &storage );
cvReleaseImage( &image );
}
cvReleaseHaarClassifierCascade( &cv_cascade );


env->ReleaseStringUTFChars(cascade, str_cascade);
env->ReleaseStringUTFChars(filename, str_filename);
return faceArray;
}

編譯生成jniOpenCV.dll。此處的檢測代碼是根據OpenCV的文檔和示例程序修改,由於本人對c++程序不是很熟練,所以對此段代碼是否會有潛在危險和內存泄露不是很肯定,還請熟悉c使用的朋友幫忙檢查一下。
別忘記將生成的jniOpenCV.dll文件複製到%JAVA_HOME%/bin中,如果在沒安裝OpenCV的機器上運行,還需要將OpenCV安裝目錄中bin目錄下所有dll文件一起復制到%JAVA_HOME%/bin中。

3.實現JAVA的調用


package lveyo.bcndyl.jni.opencv;

public class Test {

public static void main(String[] args) {

//初始化JNI調用類JNIOpencv
JNIOpencv open = new JNIOpencv("jniOpenCV");

//要檢測的圖片文件
String filename = "d:/80010.jpg";

//OpenCv提供的人間的特徵文件
String cascade = "d:/haarcascade_frontalface_alt2.xml";

//人臉檢測,前兩個參數爲可檢測的最小人臉的寬度和高度
//返回值爲人臉在圖中的座標和寬高,{x, y, width, height}
int[] faces = open.detectFace(40, 40, cascade, filename);
if(faces != null && faces.length!=0){

//返回的人臉總數
System.out.println( "faces " + faces.length/4 );

//分別輸出每個人臉的座標信息
for (int temp : faces) {
System.out.println(temp);
}
}
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章