您的位置:首页 > 编程语言 > C语言/C++

OpenCV人脸识别C++源码分析

2016-01-21 13:49 585 查看
#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";





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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: