#include "cv.h"
#include "highgui.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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";
char* jstring2String(JNIEnv*, jstring);
//主要功能函数
int captureFromImage(char* xml, char* filename, char* outfile)
{
LOGI("begin: ");
// we just detect image
// CvCapture* capture = 0;
//opencv的结构体IplImage指针,详见http://baike.baidu.com/view/3083269.htm
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
LOGI("ERROR: Could not load classifier cascade\n" );
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);//把图像写入文件
}
//释放内存
cvReleaseImage( &image );
}
else
{
LOGE("can't load image from : %s ", input_name);
}
}
//主要识别函数
void detect_and_draw( IplImage* img )
{
static CvScalar colors[] =
{
{{0,0,255}},
{{0,128,255}},
{{0,255,255}},
{{0,255,0}},
{{255,128,0}},
{{255,255,0}},
{{255,0,0}},
{{255,0,255}}
};
double scale = 2;
//保存灰度图像,8位,单通道
IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
//对一个double型的数进行四舍五入,并返回一个整型数
IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),
cvRound (img->height/scale)),
8, 1 );
int i;
//将BGR图像转换为灰度图像
cvCvtColor( img, gray, CV_BGR2GRAY );
//缩放源图像到目标图像
cvResize( gray, small_img, CV_INTER_LINEAR );
//用来使灰度图象直方图均衡化,该方法归一化图像亮度和增强对比度。
cvEqualizeHist( small_img, small_img );
cvClearMemStorage( storage );
if( cascade )
{ //计时
double t = (double)cvGetTickCount();
//storage 用来存储检测到的一序列候选目标矩形框的内存区域。
//scale_factor 在前后两次相继的扫描中,搜索窗口的比例系数。例如1.1指将搜索窗口依次扩大10%
//min_neighbors 构成检测目标的相邻矩形的最小个数(缺省-1)。
//flags 操作方式。当前唯一可以定义的操作方式是 CV_HAAR_DO_CANNY_PRUNING。如果被设定,函数利用Canny边缘检测器来排除一些边缘很少或者很多的图像区域
//min_size 检测窗口的最小尺寸
CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
1.1, 2, 0,
cvSize(30, 30) );
t = (double)cvGetTickCount() - t;
LOGI( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );
//便利检测结果,在图上画圈标记
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
CvPoint center;
int radius;
center.x = cvRound((r->x + r->width*0.5)*scale);
center.y = cvRound((r->y + r->height*0.5)*scale);
radius = cvRound((r->width + r->height)*0.25*scale);
//画圈
cvCircle( img, center, radius, colors[i%8], 3, 8, 0 );
}
}
// cvShowImage( "result", img );
//释放内存
cvReleaseImage( &gray );
cvReleaseImage( &small_img );
}
JNIEXPORT void JNICALL Java_study_opencv_FaceRec_detect
(JNIEnv * env, jobject obj, jstring xml, jstring filename, jstring outfile)
{
LOGI("top method invoked! ");
captureFromImage(jstring2String(env,xml), jstring2String(env,filename), jstring2String(env,outfile));
}
//jstring to char*
char* jstring2String(JNIEnv* env, jstring jstr)
{
if(jstr == NULL)
{
LOGI("NullPointerException!");
return NULL;
}
char* rtn = NULL;
//得到Java中的类
jclass clsstring = env->FindClass("java/lang/String");
//声明一个jstring类型对象,内容为编码方式
jstring strencode = env->NewStringUTF("utf-8");
//得到java类中某方法的ID
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
//用ID调用java类的方法,执行。参数:输入字符串,方法ID,编码方式(jstring),返回byte数组(jbyteArray)。
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
//得到数组长度(jsize)
jsize alen = env->GetArrayLength(barr);
//声明指针,指向byte数组内容
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
//为(char*)指针 rtn 申请空间,多申请一个char位置
rtn = (char*)malloc(alen + 1);
//内存拷贝,将原byte数组内容copy到char*指针所指位置。长度为alen
memcpy(rtn, ba, alen);
//将最后一个字符设置为0,表示为nuRFll
rtn[alen] = 0;
}
//释放java类中的数组空间
env->ReleaseByteArrayElements(barr, ba, 0);
LOGI("char*=%s",rtn);
return rtn;
}
FROM: http://blog.sina.com.cn/s/blog_5b2469f20100zvmx.html