最近了解了一下CvHaarClassifierCascade用于人脸检测的流程
然后发现:比我想象的简单多了!!!!!!!!!!!
首先,所有的训练集都能在opencv\sources\data\haarcascades目录下找的到,
其次,只需要一个cvLoad()加载训练集和cvHaarDetectObjects()获得检测轮廓
/*
*image:一般使用单通道灰度图,可以加快检测时间
*cascade:通过cvLoad加载的分类器模型
*storage:findcontour经常用到的内存空间
*scale_factor :搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%
*min_neighbors:构成检测目标的相邻矩形的最小个数(默认为3个)
*flags :默认参数CV_HAAR_DO_CANNY_PRUNING
*min_size :最小人脸尺寸
*max_size:最大人脸尺寸
*/
CVAPI(CvSeq*) cvHaarDetectObjects(
const CvArr* image,
CvHaarClassifierCascade* cascade,
CvMemStorage* storage,
double scale_factor CV_DEFAULT(1.1),
int min_neighbors CV_DEFAULT(3),
int flags CV_DEFAULT(0),
CvSize min_size CV_DEFAULT(cvSize(0,0)),
CvSize max_size CV_DEFAULT(cvSize(0,0))
)
关于人脸识别的方法,采用了最简单的直方图匹配cvCompareHist(),求得的结果越接近1代表,两张图像越相识
话不多说直接贴整个工程的源码了
// Demo.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <math.h>
#include "cv.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\objdetect\objdetect.hpp>
#include <string>
#include <fstream>
using namespace std;
//定义路径
const char *faceCascadeFilename = "haarcascade_frontalface_alt_tree.xml";
const char *NamePath = "../face/face.txt";
//
double CompareHist_Face(IplImage *Src,IplImage *bImage)
{
double bScore = 0.0;
if (Src->nChannels != 1||bImage->nChannels!=1) {
printf("Error:0x001\n");
return -1;
}
int HistogramBins = 256;
float HistogramRange1[2] = { 0, 255 };
float *HistogramRange[1] = { &HistogramRange1[0] };
CvHistogram *Histogram1 = cvCreateHist(1, &HistogramBins, CV_HIST_ARRAY, HistogramRange);
CvHistogram *Histogram2 = cvCreateHist(1, &HistogramBins, CV_HIST_ARRAY, HistogramRange);
cvCalcHist(&Src, Histogram1);
cvCalcHist(&bImage, Histogram2);
cvNormalizeHist(Histogram1, 1);
cvNormalizeHist(Histogram2, 1);
bScore=cvCompareHist(Histogram1, Histogram2, CV_COMP_INTERSECT);
cvReleaseHist(&Histogram1);
cvReleaseHist(&Histogram2);
return bScore;
}
int FaceDetection(IplImage *src,CvRect *bRect)
{
int num = -1;
CvHaarClassifierCascade* face_Classifier = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0);
if (src->nChannels != 3)
{
return num;
}
IplImage *cvtImage = cvCreateImage(cvSize(src->width, src->height), 8, 1);
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
//整张脸
CvMemStorage *pStorage = cvCreateMemStorage(0);
const double scale_factore = 1.1f;
const int flag = CV_HAAR_DO_CANNY_PRUNING;
CvSeq *pSeq = cvHaarDetectObjects(cvtImage, face_Classifier, pStorage, scale_factore, 3, flag, cvSize(20, 20));
num = pSeq->total;
for (int i = 0; i < (pSeq->total); i++)
{
bRect[i] = *(CvRect *)cvGetSeqElem(pSeq, i);
//cvRectangle(src, cvPoint(bRect[i].x, bRect[i].y), cvPoint(bRect[i].x + bRect[i].width - 1, bRect[i].y + bRect[i].height - 1), cvScalar(0, 255, 0), 1, 8, 0);
}
cvReleaseImage(&cvtImage);
cvReleaseMemStorage(&pStorage);
return num;
}
void FaceDetected(const char *path, IplImage *src,bool save)
{
if (path == nullptr)
{
printf("ERROR:0x002\n");
}
CvHaarClassifierCascade* face_Classifier = (CvHaarClassifierCascade*)cvLoad(path, 0, 0, 0);
if (src->nChannels != 3)
{
printf("Error:0x003\n");
}
IplImage *cvtImage = cvCreateImage(cvSize(src->width, src->height), 8, 1);
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
//整张脸
CvMemStorage *pStorage = cvCreateMemStorage(0);
const double scale_factore = 1.1f;
const int flag = CV_HAAR_DO_CANNY_PRUNING;
CvSeq *pSeq = cvHaarDetectObjects(cvtImage, face_Classifier, pStorage, scale_factore, 3, flag, cvSize(20, 20));
for (int i = 0; i < (pSeq->total); i++)
{
CvRect bRect = *(CvRect *)cvGetSeqElem(pSeq, i);
cvSetImageROI(src,bRect);
string bName = "../face/P" + std::to_string(i) + ".jpg";
cvSaveImage(bName.c_str(), src);
cvResetImageROI(src);
}
cvReleaseImage(&cvtImage);
}
int main(int argc, _TCHAR* argv[])
{
//获取txt里面的图片全称
ifstream bfile(NamePath);
if (!bfile.is_open())
{
return 0;
}
vector<string> bName;
bName.clear();
string name;
while (getline(bfile, name))
{
bName.push_back(name);
}
//加载原图像
IplImage *SrcImage = cvLoadImage("1.jpg");//标准图片
IplImage *CvtSrc = cvCreateImage(cvSize(SrcImage->width, SrcImage->height), 8, 1);
cvCvtColor(SrcImage, CvtSrc, CV_BGR2GRAY);
CvRect bFaceRect[20];
//原图像找全部人脸
int num=FaceDetection(SrcImage,bFaceRect);
//创建人脸ROI图像用于检测
IplImage **roiFace = new IplImage*[num];
for (int i = 0; i < num;i++)
{
roiFace[i] = cvCreateImage(cvSize(bFaceRect[i].width, bFaceRect[i].height), 8, 1);
cvSetImageROI(CvtSrc, bFaceRect[i]);
cvCopy(CvtSrc, roiFace[i]);
cvResetImageROI(CvtSrc);
}
//循环对比
for (int x = 0; x < bName.size();x++)
{
string bpath = "../face/" + bName.at(x);
IplImage *face = cvLoadImage(bpath.c_str(),0);
for (int y = 0; y < num;y++)
{
double socre=CompareHist_Face(face, roiFace[y]);
if (socre>0.87)//找最低分
{
CvFont font;
double hScale = 0.6;
double vScale = 0.6;
int line_width = 1;
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, hScale, vScale, 0, line_width, 8);
//人脸区域
cvRectangle(SrcImage, cvPoint(bFaceRect[y].x, bFaceRect[y].y), cvPoint(bFaceRect[y].x + bFaceRect[y].width, bFaceRect[y].y + bFaceRect[y].height),cvScalar(255,0,0));
string s = std::to_string(socre);
s = s.substr(0, 4);//保留两位
string stt = "P"+std::to_string(x)+":"+s;
const char * pName = stt.c_str(); //名称:分数
cvPutText(SrcImage, pName, cvPoint(bFaceRect[y].x, bFaceRect[y].y), &font, cvScalar(0, 255, 0));
cvReleaseImage(&face);
break;
}
}
}
cvShowImage("test", SrcImage);
cvWaitKey(0);
//释放
for (int i = 0; i < num;i++)
{
cvReleaseImage(&roiFace[i]);
}
cvReleaseImage(&SrcImage);
cvReleaseImage(&CvtSrc);
return 0;
}
具体执行效果如下,(PS:图片随便找的,侵权请联系我删除)