opencv3之视频识别人脸并匹配

这里的人脸匹配也是从已有的人脸文件夹里找到,最相似的人脸图片与当前的视频中的人脸匹配。

然后它也是用的opencv3训练好的模型文件。

opencv3之视频识别人脸并匹配_第1张图片

直接上代码

#include
#include
#include
#include
#include "opencv2/objdetect.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/imgproc.hpp"


#include //用到了time函数,所以要有这个头文件
using namespace cv;
using namespace std;


string xmlPath = "haarcascade_frontalface_alt.xml";


//识别并截取人脸
Mat detectAndDisplay(Mat image)
{
CascadeClassifier ccf;//创建脸部对象
ccf.load(xmlPath);//导入自己训练好的模型文件
vector faces;
Mat gray;
cvtColor(image, gray, CV_BGR2GRAY);//彩图转化为灰度图
equalizeHist(gray, gray);//直方图均衡化,可提高图像的质量

//检测出图片中所有的人脸,并将人脸用vector保存各个人脸的坐标、大小(用矩形表示),函数由分类器对象调用:
ccf.detectMultiScale(gray, faces, 1.1, 3, 0, Size(50, 50), Size(500, 500));
/*gray,待检测图片,一般为灰度图像加快检测速度;faces,被检测人脸的矩形框向量组;1.1,表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%;
3表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大小都可以检测到人脸)
flags 0--要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为
             CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域,因此这些区域通常不会是人脸所在区域;
minSize和maxSize用来限制得到的目标区域的范围。
*/




for (vector::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
rectangle(image, *iter, Scalar(0, 0, 255), 2, 8); //画出脸部矩形框
}
for (size_t i = 0; 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));
}
return image;
}


//得到图片的哈希值
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));//缩小图片尺寸为32*32,加快计算速度
uchar *pData;
for (int i = 0; i {
pData = img.ptr(i);
for (int j = 0; 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 {
pData = mask.ptr(i);
for (int j = 0; j {
if (pData[j] == 0)
rst[index++] = '0';//哈希码赋值
else
rst[index++] = '1';
}
}
return rst;//返回一个64位的全是0或1的哈希码字符串

}


//求两张图片的汉明距离,汉明距离就是比如:2个字符串,分别为“12345”和“12367”,他们2个字符串的长度都要一样为

//前提,然后才比较对应位置的值是否相同,不同则记1次,所以这个例子的汉明距离是2,因为最后2个对应位置的值不同。

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;
cout << "return diff ,hanming distance " << endl;
}


int main(int argc, char** argv)
{
using std::cout;
using std::endl;



int x;
int i = 9;
int diff[9];
//
//从数据库选择,实际上如果2张判断更简单,只是一次比对而已。我数据库的是多次循环,取最优而已
//

Mat image1, image2;

string str1, str2, path2;
cvNamedWindow("你输入的图片", 1);



int flag = 0;
Mat image;
VideoCapture cam(0);
while (1)
{
cam >> image;
cvNamedWindow("frame", 1);  //命名一个窗口
imshow("frame", image);       //在窗口显示图片


string filename = format("C:\\images\\%d.jpg", i);
char key = waitKey(100);
switch (key)
{
case'p':                              //键盘上每按一次p,就拍一张照
flag = 1;             //写入图片
imshow("photo", image);               //展示照片
waitKey(50);
destroyWindow("photo");
break;
default:break;
}
if (flag == 1)break;
}


image1 = detectAndDisplay(image);
//imshow("after cut ", image1);
str1 = HashValue(image1);


for (i = 1; i <= 8; i++)//因为我的就是8张图片的检测,所以循环值为8
{
path2 = format("C:\\images\\%d.jpg", i);
image2 = imread(path2, -1);
image2 = 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:\\images\\%d.jpg", t);
image2 = imread(path2, -1);//将图片t显示出来
cvNamedWindow("最相似的图片", 1);




imshow("你输入的图片", image1);
//imshow("after cut ", image1);


imshow("最相似的图片", image2);//这时显示的就是最相似的照片
cvWaitKey(0);
cin.get();                    //吃掉回车符

}

代码具体流程:

1.截取视频流中的图片

2.检测出图片出的人脸区域,截图保存

3.计算人脸的特征值。

4.从数据库中选取图片重复1,23步骤,然后使用汉明距离法逐一计算选取图片与当前人脸图片的相似度。

5.选取相似度最高的图片,人脸匹配完成.


以上代码有参考别人的博客,没有保存好链接所以没写出来,请见谅。


你可能感兴趣的:(opencv)