基于Opencv的人脸检测及识别

时间:2022-01-28 04:10:11

 

一、实验目的:我这里完成的是,将8张人脸图片(4组,每组两张)存入库中,选取1张图片,程序识别出与其匹配的另一张。

这里介绍分三个步骤完成该工作,①程序读取摄像头、拍照

                 ②程序从电脑文档中读取图片

                 ③检测人脸,并用红框框出人脸

                                                    ④使用感知哈希算法匹配最相似的图片

 

二、实验环境: Win 7(x64)、visual studio 2010、openCV-2.4.3

使用语言:C++

三、实验准备:①安装好vs2010,本文不予介绍。

        ②配置opencv :

  1'进入官网下载http://opencv.org/  (OpenCv 2.4x是支持Vs2010的,建议根据自己的Vs版本安装相应的OpenCv的版本)解压后,目录如下:

基于Opencv的人脸检测及识别

  2'打开vs2010,创建项目,这里以我的工程名test为例。右击项目->属性->vc++目录->包含目录, 添加三个路径:(在解压后opencv下的build目录)

                                               E:\新建文件夹\opencv\build\include

                                               E:\新建文件夹\opencv\build\include\opencv

                                               E:\新建文件夹\opencv\build\include\opencv2

 

然后点击库目录,添加路径:E:\新建文件夹\opencv\build\x86\vc10\lib

基于Opencv的人脸检测及识别

 

基于Opencv的人脸检测及识别

 

配置好了后,第二步,点击链接器->输入->附加依赖项,编辑添加,把E:\新建文件夹\opencv\build\x86\vc10\bin里面左右的文件名称全导入进去,导入带d的文件,比如有opencv_calib3d243.dll与opencv_calib3d243d.dll文件,只需添加后者带d的即可。

 

至此,openCV配置已经全部完成。接下来编写代码。

四、编写代码

①为了收集图片库,我编写了直接拍照的功能,按下p进行拍照,并自动命名排序存到文件中。

#include <iostream>
#include
<opencv2/core/core.hpp>
#include
<opencv2/highgui/highgui.hpp>
using namespace cv;
int main( int argc, char** argv )
{

int i=1;//照片名从1开始命名
while(1)
{
CvCapture
*pCapture=cvCreateCameraCapture(-1);//打开摄像头
Mat image=cvQueryFrame(pCapture); //将摄像头拍的以图片形式展现
cvNamedWindow("frame",1); //命名一个窗口
imshow("frame",image); //在窗口显示图片
string filename=format("C:\\images\\%d.jpg",i);
char key=waitKey(100);
switch(key)
{
case'p':
i
++; //键盘上每按一次p,就拍一张照
imwrite(filename,image); //写入图片
imshow("photo",image); //展示照片
waitKey(500);
destroyWindow(
"photo");
break;
default:break;
}
}
}

实验效果:

基于Opencv的人脸检测及识别

②读取图片,显示在屏幕上

    Mat image=imread("C:\\images\\2.jpg",-1);    //使用Mat创建一个对象,-1为打开类型的参数
cvNamedWindow("图像显示",1); //命名一个窗口 ,1为显示参数
imshow("图像显示",image);
cvWaitKey(
0); //很重要,不写读不出来

③将读取的图片进行检测出人脸。

首先找到opencv目录下,识别人脸的类的文件(包装在data路径下)

基于Opencv的人脸检测及识别

Haarcascades_frontalface_default 包装的是 检测人脸,将这个文件拷贝到你的vs工程下。

#include <iostream>
#include
<string>
#include
<opencv2/core/core.hpp>
#include
<opencv2/highgui/highgui.hpp>
#include
<opencv2/gpu/gpu.hpp>
using namespace cv;
using namespace std;
string xmlPath="C:\\Users\\yu\\Documents\\Visual Studio 2010\\Projects\\加我南\\haarcascade_frontalface_default.xml";
//xmlpath 字符串记录那个.xml文件的路径
void detectAndDisplay(Mat image);
int main( int argc,char**argv )
{
string path="C:\\Users\\yu\\Documents\\Visual Studio 2010\\Projects\\test\\images\\1.jpg";//以检测图片1.jpg为例
Mat image =imread(path,-1);

CascadeClassifier a;
//创建脸部对象
if(!a.load(xmlPath)) //如果读取文件不出错,则检测人脸
{
cout
<<"无法加载xml文件"<<endl;
return 0;
}
detectAndDisplay(image);
// 检测人脸
return 0;

}

void detectAndDisplay(Mat image)
{
CascadeClassifier ccf;
//创建脸部对象
ccf.load(xmlPath); //导入opencv自带检测的文件
vector<Rect> faces;
Mat gray;
cvtColor(image,gray,CV_BGR2GRAY);
equalizeHist(gray,gray);
ccf.detectMultiScale(gray,faces,
1.1,3,0,Size(50,50),Size(500,500));
for(vector<Rect>::const_iterator iter=faces.begin();iter!=faces.end();iter++)
{
rectangle(image,
*iter,Scalar(0,0,255),2,8); //画出脸部矩形
}
Mat image1;

for(size_t i=0;i<faces.size();i++)
{
Point center(faces[i].x
+ faces[i].width / 2, faces[i].y + faces[i].height / 2);
image1
= image(Rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height));
}

imshow(
"1",image);
imshow(
"2",image1);
cvWaitKey(
0);

}

 

实验结果如下:

基于Opencv的人脸检测及识别

 

④进行人脸检测

opencv的FaceRecogizer目前有三个类实现了它,特征脸和fisherface方法最少训练图像为两张,而LBP可以单张图像训练,LBP方法原理:

     引用:http://blog.csdn.net/lsq2902101015/article/details/49717441

 

 基于Opencv的人脸检测及识别

因此,我想到了与LBP算法类似的感知哈希算法。

说下原理过程:

     (1)缩小尺寸:去除高频和细节的最快方法是缩小图片,将图片缩小到8x8的尺寸,共64个像素。不用保持纵横比,只需将其变成8x8的正方形,这样就可以摒弃不同尺寸、比例带来的图片差异
      (2)简化色彩:将8x8的小图片转换成灰度图像。
      (3)计算平均值:计算所有64个像素的灰度平均值
      (4)比较像素的灰度:将每个像素的灰度,与平均值进行比较,大于或等于就记为1,小于均值,就记为0;
       (5)计算hash值,将上面的比价比较结果组合在一起,构成了64位的哈希值,就是这张图片的指纹。
       (6)通过比较两张图片的哈希值,计算差值得到汉明距离。汉明距离越小,说明两张图片越相似。
  引用:http://blog.csdn.net/zouxy09/article/details/17471401

#include <iostream>
#include
<string>
#include
<opencv2/core/core.hpp>
#include
<opencv2/highgui/highgui.hpp>
#include
<opencv2/gpu/gpu.hpp>
using namespace cv;
string xmlPath="C:\\Users\\yu\\Documents\\Visual Studio 2010\\Projects\\加我南\\haarcascade_frontalface_default.xml";

string HashValue(Mat &src) //得到图片的哈希值
//很久之前写的,现在想不起来了...注释就先不写了.....抱歉哈。但是是可以运行的
{
string rst(64,'\0');
Mat img;
if(src.channels()==3)
cvtColor(src,img,CV_BGR2GRAY);
else
img
=src.clone();
resize(img,img,Size(
8,8));
uchar
*pData;
for(int i=0;i<img.rows;i++)
{
pData
=img.ptr<uchar>(i);
for(int j=0;j<img.cols;j++)
{
pData[j]
=pData[j]/4;
}
}

int average=mean(img).val[0];
Mat mask
=(img>=(uchar)average);
int index=0;
for(int i=0;i<mask.rows;i++)
{
pData
= mask.ptr<uchar>(i);
for(int j=0;j<mask.cols;j++)
{
if(pData[j]==0)
rst[index
++]='0';
else
rst[index
++]='1';
}
}
return rst;
}
int HanmingDistance(string &str1,string &str2) //求两张图片的汉明距离
{
if((str1.size()!=64)||(str2.size()!=64))
return -1;
int diff=0;
for(int i=0;i<64;i++)
{
if(str1[i]!=str2[i])
diff
++;
}
return diff;
}
void detectAndDisplay(Mat image)
{
CascadeClassifier ccf;
ccf.load(xmlPath);
vector
<Rect> faces;
Mat gray;
cvtColor(image,gray,CV_BGR2GRAY);
equalizeHist(gray,gray);
ccf.detectMultiScale(gray,faces,
1.1,3,0,Size(50,50),Size(500,500));
for(vector<Rect>::const_iterator iter=faces.begin();iter!=faces.end();iter++)
{
rectangle(image,
*iter,Scalar(0,0,255),2,8); //画出脸部矩形
}
for(size_t i=0;i<faces.size();i++)
{
Point center(faces[i].x
+ faces[i].width / 2, faces[i].y + faces[i].height / 2);
image
= image(Rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height));
}
}
//识别并截取人脸
int main( int argc, char** argv )
{
using std::cout;
using std::endl;
using std::cin;
cout
<<"请输入想要选择的图片"<<endl;
int a,x,i;
int diff[9];
cin
>>a;
const string path1=format("C:\\Users\\yu\\Documents\\Visual Studio 2010\\Projects\\test\\images\\%d.jpg",a);
Mat image1,image2;
image1
=imread(path1,-1);
string str1,str2,path2;
cvNamedWindow(
"选择的图片",1);
/*cvResizeWindow("选择的图片",700,500);*/
imshow(
"选择的图片",image1);
detectAndDisplay(image1);
str1
=HashValue(image1);
cvWaitKey(
0);
for(i=1;i<=8;i++)//因为我完成的就是8张图片的检测,所以循环值为8
{
path2
=format("C:\\Users\\yu\\Documents\\Visual Studio 2010\\Projects\\test\\images\\%d.jpg",i);
image2
=imread(path2,-1);
detectAndDisplay(image2);
str2
=HashValue(image2);
diff[i]
=HanmingDistance(str1,str2);
}

int min=1000,t;
for(i=1;i<=8;i++) //循环值为8,求与原图片汉明距离最小的那张图片
{
if(min>diff[i]&&diff[i]!=0)
{
min
=diff[i];
t
=i;} //检测出的标记为t
}
path2
=format("C:\\Users\\yu\\Documents\\Visual Studio 2010\\Projects\\test\\images\\%d.jpg",t);
image2
=imread(path2,-1);//将图片t显示出来
cvNamedWindow("相似的图片",1);
imshow(
"相似的图片",image2);//这时显示的就是最相似的照片
cvWaitKey(0);
cin.
get(); //吃掉回车符
}

实验结果如下:

 基于Opencv的人脸检测及识别

基于Opencv的人脸检测及识别

 

我的照片库如下:

基于Opencv的人脸检测及识别

 

 至此,简单地完成了检测并且识别人脸的功能。