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

#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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值