// peizhi.cpp : Defines the entry point for the console application.
//
#include "stdafx.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 "cv.h"
#include "highgui.h"
#include "cvcam.h"
#include "cxcore.h"
static CvMemStorage* storage=0;
static CvHaarClassifierCascade* cascade = 0;
void detect_and_draw( IplImage* image );
void cam_move(double length,double f);
void change_focus(double length,double f);
IplImage *CvRectToImage(IplImage *img);//根据已知的矩形获取图像
IplImage *ThreeToOne(IplImage *img); //将三通道彩色图像转换成单通道灰度图像
IplImage *GetExampleImage(char *filename);//获得用于对比的目标图像的函数
int JudgeResult();
void compare_picture(IplImage *example,IplImage *object);
static double Width=0,Height=0;//表示摄像头获得图像的大小
IplImage *face=0;//用于指向检测到的人脸
#define MAX1 0.5
#define MIN1 0.2
#define SIZE 0.3//人脸占整个图片的比例调节在0.2-0.5的范围外时(以高度计算),统一修改成比例0.3,
const char *cascade_name ="C://Program Files//OpenCV//data//haarcascades//haarcascade_frontalface_alt2.xml";
CvRect info=cvRect(50,50,50,50); //包含了检测到的图像的坐标信息
int _tmain(int argc, _TCHAR* argv[])
{
storage = cvCreateMemStorage(0);
char filename[20]="01.bmp";
IplImage *img=GetExampleImage(filename);//目标图像
cvNamedWindow("ex",1);
if(!img)
{
printf("出错/n");
exit(0);
}
cvShowImage("ex",img);
CvCapture* capture =cvCaptureFromCAM(0);
IplImage *frame, *frame_copy = 0;
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
if( !cascade )
{
printf("无法找到文件/n");
return -1;
}
else
printf("找到了相应的文件/n");
cvNamedWindow( "result", 1 );
cvNamedWindow("face",1);
for(;;)
{
if(!cvGrabFrame(capture))
{
printf("无法打开摄像头/n");
break;
}
frame = cvRetrieveFrame( capture );
Width=(double)frame->width;
Height=(double)frame->height;
if(!frame )
break;
if( !frame_copy )
frame_copy = cvCreateImage( cvSize(frame->width,frame->height),
IPL_DEPTH_8U, frame->nChannels );
if( frame->origin == IPL_ORIGIN_TL )
cvCopy( frame, frame_copy, 0 );
else
cvFlip( frame, frame_copy, 0 );
detect_and_draw( frame_copy );
face=CvRectToImage(frame);
//cvResize(face,img,2);
cvShowImage("face",face);
compare_picture(img,face);
if(JudgeResult()==1)
printf("识别成功/n");
//change_focus(2,0.0036);
// cam_move(2.0,0.0036);
//printf("%d",info->x);
cvWaitKey(100);
}
cvReleaseImage( &frame_copy );
cvReleaseImage(&face);
cvReleaseCapture( &capture );
cvWaitKey(0);
cvDestroyWindow("result");
cvDestroyWindow("face");
cvDestroyWindow("ex");
return 0;
}
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 = 1.3;
IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),cvRound (img->height/scale)),8, 1 );
int i;
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();
CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,1.1, 2, 0,cvSize(30, 30) );
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
info = *r;
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 );
}
void cam_move(double length,double f)//length表示摄像机到人脸的距离,f是焦距,以米为单位,控制摄像头的移动
{
double center_h=Height/2;
double center_w=Width/2;//图片中心的坐标
double face_w=((double)info.x+(double)info.x+(double)info.width)/2;
double face_h=((double)info.y+(double)info.y+(double)info.height)/2;//检测到的人脸中心坐标
/*摄像头的ccd规格尺寸是 4.8mm 3.6mm,利用公式W/w=length/f进行计算*/
double move_x=(length/f)*(0.0048)*((face_w-center_w)/Width);//实际物体的偏移量
double move_y=(length/f)*(0.0036)*((face_h-center_h)/Height);//实际物体的偏移量
double angle_x=0,angle_y=0;
if(move_x>=0) //右偏
{
angle_x=atan(move_x/length)*180/3.14159;//使用反三角函数求角度
//右移angle_x
}
else
{
angle_x=atan(move_x*(-1)/length)*180/3.14159;
//左偏转角度angle_x)
}
if(move_y>=0)
{
angle_y=atan(move_y/length)*180/3.14159;
//下移转角angle_y
}
else
{
angle_y=atan(move_y*(-1)/length)*180/3.14159;
//上移angle_y
}
// printf("移动的角度%lf/t%lf/n",angle_x,angle_y);
}
void change_focus(double length,double f)//调焦函数
{
if(info.height/Height>=MIN1&&info.height/Height<=MAX1)
return; //不需要调节
double pre_w=(length/f)*0.0048;//调焦前的图片对应的实际宽度
double pre_h=(length/f)*0.0036;//实际高度
double times=(info.height/Height)/SIZE;//实际比例与所需调节比例的倍数关系
f=f/times;//修改焦距
//控制摄像头修改焦距
//printf("焦距是:%lf/n",f);
}
IplImage *ThreeToOne(IplImage *img)//多通道与单通道转换
{
IplImage *dst=cvCreateImage(cvGetSize(img),img->depth,1);
cvCvtColor(img,dst,CV_BGR2GRAY);
return dst;
}
int HistogramBins = 256;
float HistogramRange1[2]={0,255};
float *HistogramRange[1]={&HistogramRange1[0]};
double compare_result[2]={0};//用于存储两个图像的比较结果
/*注意,该函数比较的必须是单通道灰度图像,否则需要转换*/
void compare_picture(IplImage *example,IplImage *object)//比较两个图像的相似度
{
example=ThreeToOne(example);
object=ThreeToOne(object);
//cvResize(example,object);
CvHistogram *Histogram1=cvCreateHist(1,&HistogramBins,CV_HIST_SPARSE,HistogramRange);//创建直方图
CvHistogram *Histogram2=cvCreateHist(1,&HistogramBins,CV_HIST_SPARSE,HistogramRange);
cvCalcHist(&example,Histogram1);//计算图像的直方图
cvCalcHist(&object,Histogram2);
cvNormalizeHist(Histogram1,1);//归一化直方图
cvNormalizeHist(Histogram2,1);
double chisqr=cvCompareHist(Histogram1,Histogram2,CV_COMP_CHISQR);//卡方
double bha=cvCompareHist(Histogram1,Histogram2,CV_COMP_BHATTACHARYYA);//Bhattacharyya
compare_result[0]=chisqr;//存储卡方,卡方越小越相似
compare_result[1]=bha;//存储Bhattacharyya,越小越相似
}
#define CHISQR 0.25 //当chisqr<=0.15时判断为相同
#define BHA 0.25 //当bha<=0.15时判断相同
int JudgeResult()//根据比较结果判断是否相同
{
//printf("%f/t%f/n",compare_result[0],compare_result[1]);
if(compare_result[0]<=CHISQR&&compare_result[1]<=BHA)
return 1; //表示两张图片结果相同
else
return 0; //表示两张图片结果不相同
}
#define SCALE 1.2
IplImage *CvRectToImage(IplImage *img)//通过原图像和所得矩阵,获得检测到人脸的图像
{
CvRect info_copy=info;
info_copy.width*=SCALE;
info_copy.height*=SCALE;
info_copy.x*=SCALE;
info_copy.y*=SCALE;
cvSetImageROI(img, info_copy);
IplImage *smallface=cvCreateImage( cvSize(info_copy.width,info_copy.height), 8, 3 );
cvCopy(img,smallface);
cvResetImageROI(img);
cvConvertImage(smallface,smallface,CV_CVTIMG_FLIP );
return smallface;
}
IplImage *GetExampleImage(char *filename)
{
IplImage *img=cvLoadImage(filename,-1);
double scale =SCALE;
IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),cvRound (img->height/scale)),8, 1 );
cvCvtColor( img, gray, CV_BGR2GRAY );
cvResize(gray, small_img, CV_INTER_LINEAR );
cvEqualizeHist( small_img, small_img );
cvClearMemStorage( storage );
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
if( cascade )
{
CvRect* r=0;
CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,1.1, 2, 0,cvSize(30, 30) );
for(int i = 0; i < (faces ? faces->total : 0); i++ )
r = (CvRect*)cvGetSeqElem( faces, i);
if(r==0)
return 0;
r->width*=SCALE;
r->height*=SCALE;
r->x*=SCALE;
r->y*=SCALE;
cvSetImageROI(img, *r);
IplImage *smallface=cvCreateImage( cvSize(r->width,r->height), 8, 3 );
cvCopy(img,smallface);
cvResetImageROI(img);
return smallface;
}
else
return 0;
}