用opencv做的静态图片人脸识别
这次给大家分享一个图像识别方面的小项目,主要功能是识别图像中的人脸并根据人脸在图片库找出同一个与它最相似的图片,也就是辨别不同的人。
环境:VS2013+opencv2.4.13
主要是算法:opencv中人脸识别算法(截取人脸)+哈希算法(辨别人脸)
opencv中人脸识别算法:这个很常用,就是普通的人脸识别算法,直接上代码:
void IdentifyFace(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, , , Size(, ), Size(, )); //检测人脸
for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
rectangle(image, *iter, Scalar(, , ), , ); //画出脸部矩形
}
for (size_t i = ; i<faces.size(); i++)
{
Point center(faces[i].x + faces[i].width / , faces[i].y + faces[i].height / );
image = image(Rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height));
}
}
哈希算法:主要是用来视觉目标跟踪,主要的思路如下:
(1)缩小尺寸:pHash以小图片开始,但图片大于8*8,32*32是最好的。这样做的目的是简化了DCT的计算,而不是减小频率。
(2)简化色彩:将图片转化成灰度图像,进一步简化计算量。
(3)计算DCT:计算图片的DCT变换,得到32*32的DCT系数矩阵。
(4)缩小DCT:虽然DCT的结果是32*32大小的矩阵,但我们只要保留左上角的8*8的矩阵,这部分呈现了图片中的最低频率。
(5)计算平均值:如同均值哈希一样,计算DCT的均值。
(6)计算hash值:这是最主要的一步,根据8*8的DCT矩阵,设置0或1的64位的hash值,大于等于DCT均值的设为”1”,小于DCT均值的设为“0”。组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。
结果并不能告诉我们真实性的低频率,只能粗略地告诉我们相对于平均值频率的相对比例。只要图片的整体结构保持不变,hash结果值就不变。能够避免伽马校正或颜色直方图被调整带来的影响。
pHash同样可以用汉明距离来进行比较。(只需要比较每一位对应的位置并算计不同的位的个数)
代码:
string calHashValue(Mat &src) //得到图片的哈希值
{
string zeroonestr(, '\0'); //定义一个字符串并初始化
Mat origianlImage, dctImage; //定义几个矩阵
Mat floatImage, imageDct;
if (src.channels() == ) //判断通道数量
cvtColor(src, origianlImage, CV_BGR2GRAY); //转换格式
else
origianlImage = src.clone(); //不用转换
resize(origianlImage, origianlImage, Size(, )); //缩小图片尺寸为32*32
origianlImage.convertTo(floatImage, CV_32FC1); //转换类型
dct(floatImage, imageDct); //进行DCT运算(离散余弦变换)
Rect roi(, , , ); //定义一个8*8的矩阵
dctImage = imageDct(roi); //将8*8的矩阵赋给dctImage
uchar *pData;
for (int i = ; i<dctImage.rows; i++)
{
pData = dctImage.ptr<uchar>(i);
for (int j = ; j<dctImage.cols; j++)
{
pData[j] = pData[j] / ;
}
} int average = mean(dctImage).val[];//求平均值
Mat mask = (dctImage >= (uchar)average); //与平均值进行比较
int index = ; //用于计数
for (int i = ; i<mask.rows; i++)
{
pData = mask.ptr<uchar>(i);
for (int j = ; j<mask.cols; j++)
{
if (pData[j] == )
zeroonestr[index++] = '';
else
zeroonestr[index++] = '';
}
}
return zeroonestr; //返回一个64位的全是0或1的字符串
}
计算两幅图片汉明距离代码
int calHanmingDistance(string &str1, string &str2) //求两张图片的海明距离
{
if ((str1.size() != ) || (str2.size() != ))
return -;
int countstoreHamingdistance = ;
for (int i = ; i<; i++)
{
if (str1[i] != str2[i])
countstoreHamingdistance++;
}
return countstoreHamingdistance;
}
整个工程代码:
#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 = "E:\\VS2013\\openCV\\opencv\\build\\share\\OpenCV\\haarcascades\\haarcascade_frontalface_default.xml"; //这个路径要根据你电脑的位置来设置
const int ImageSumNumber = ; //10张图片,图片越多越难正确识别 string calHashValue(Mat &src) //得到图片的哈希值
{
string zeroonestr(, '\0'); //定义一个字符串并初始化
Mat origianlImage, dctImage; //定义几个矩阵
Mat floatImage, imageDct;
if (src.channels() == ) //判断通道数量
cvtColor(src, origianlImage, CV_BGR2GRAY); //转换格式
else
origianlImage = src.clone(); //不用转换
resize(origianlImage, origianlImage, Size(, )); //缩小图片尺寸为32*32
origianlImage.convertTo(floatImage, CV_32FC1); //转换类型
dct(floatImage, imageDct); //进行DCT运算(离散余弦变换)
Rect roi(, , , ); //定义一个8*8的矩阵
dctImage = imageDct(roi); //将8*8的矩阵赋给dctImage
uchar *pData;
for (int i = ; i<dctImage.rows; i++)
{
pData = dctImage.ptr<uchar>(i);
for (int j = ; j<dctImage.cols; j++)
{
pData[j] = pData[j] / ;
}
} int average = mean(dctImage).val[];//求平均值
Mat mask = (dctImage >= (uchar)average); //与平均值进行比较
int index = ; //用于计数
for (int i = ; i<mask.rows; i++)
{
pData = mask.ptr<uchar>(i);
for (int j = ; j<mask.cols; j++)
{
if (pData[j] == )
zeroonestr[index++] = '';
else
zeroonestr[index++] = '';
}
}
return zeroonestr; //返回一个64位的全是0或1的字符串
}
int calHanmingDistance(string &str1, string &str2) //求两张图片的海明距离
{
if ((str1.size() != ) || (str2.size() != ))
return -;
int countstoreHamingdistance = ;
for (int i = ; i<; i++)
{
if (str1[i] != str2[i])
countstoreHamingdistance++;
}
return countstoreHamingdistance;
}
void IdentifyFace(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, , , Size(, ), Size(, )); //检测人脸
for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
rectangle(image, *iter, Scalar(, , ), , ); //画出脸部矩形
}
for (size_t i = ; i<faces.size(); i++)
{
Point center(faces[i].x + faces[i].width / , faces[i].y + faces[i].height / );
image = image(Rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height));
}
} void DrawFaceRectangl(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, , , Size(, ), Size(, )); //检测人脸
for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
rectangle(image, *iter, Scalar(, , ), , ); //画出脸部矩形
}
imshow("图片中的人脸检测", image);
}
int main(int argc, char** argv)
{
cout << "请输入想要选择的图片" << endl;
int referencepicture; //用于参考的图片
int ImageNum; //用于遍历的计数变量
int storeHamingdistance[]; //用于储存图片的海明距离
cin >> referencepicture; //输入参考图片的编号
const string path1 = format("H:\\picture\\opencv\\jackchen\\%d.jpg", referencepicture);//获取参考图片的路径 //这个路径要根据你电脑的位置来设置
Mat originalImage, processImage, faceImage;
originalImage = imread(path1, -); //获取图片
faceImage = imread(path1, -); //获取图片
string str1, str2, path2; //定义几个字符串
cvNamedWindow("选择的图片", );
/*cvResizeWindow("选择的图片",700,500);*/
imshow("选择的图片", originalImage);
DrawFaceRectangl(faceImage); //截取人脸,并显示出来
IdentifyFace(originalImage); //识别并截取人脸
str1 = calHashValue(originalImage); //求出汉明距离
cvWaitKey();
for (ImageNum = ; ImageNum <= ImageSumNumber; ImageNum++)//因为我完成的就是8张图片的检测,所以循环值为8
{
path2 = format("H:\\picture\\opencv\\jackchen\\%d.jpg", ImageNum); //这个路径要根据你电脑的位置来设置
processImage = imread(path2, -);
IdentifyFace(processImage);
str2 = calHashValue(processImage);
storeHamingdistance[ImageNum] = calHanmingDistance(str1, str2);
} int min = ; //这个自己确定,大于64就可以了
int storemostsimilarImage; //用于储存最相似的图片的编号
for (ImageNum = ; ImageNum <= ImageSumNumber; ImageNum++) //循环值为8,求与原图片汉明距离最小的那张图片
{
if (storeHamingdistance[ImageNum]<min && storeHamingdistance[ImageNum] != )
{
min = storeHamingdistance[ImageNum];
storemostsimilarImage = ImageNum; //检测出的标记为t
}
}
path2 = format("H:\\picture\\opencv\\jackchen\\%d.jpg", storemostsimilarImage); //这个路径要根据你电脑的位置来设置
processImage = imread(path2, -);//将最相似的图片显示出来
cvNamedWindow("相似的图片", );
imshow("相似的图片", processImage);//这时显示的就是最相似的照片
cvWaitKey();
cin.get(); //吃掉回车符
}
下面是我的图片库:

效果:

不足:大家可以看到,检测图片中的人脸时,把旁边的也识别成人脸了,还有就是图片多的时候,识别效果会很差,所以说实用性不强,欢迎交流。下次尝试用深度学习来做。
用opencv做的静态图片人脸识别的更多相关文章
- Android静态图片人脸识别的完整demo(附完整源码)
Demo功能:利用android自带的人脸识别进行识别,标记出眼睛和人脸位置.点击按键后进行人脸识别,完毕后显示到imageview上. 第一部分:布局文件activity_main.xml < ...
- Opencv 入门学习之图片人脸识别
读入图片,算法检测,画出矩形框 import cv2 from PIL import Image,ImageDraw import os def detectFaces(image_name): im ...
- openCV+ASM+LBP+Gabor实现人脸识别(GT人脸库)
原理:使用GT人脸库做样本,VS2010下使用openCV2.44自带的Haar算法检測人脸区域,ASM Library特征检測,然后使用YCrCb颜色空间做肤色检測,再用LBP+Gabor小波提取特 ...
- python3+opencv+tkinter开发简单的人脸识别小程序
学校里有门图像处理的课程最终需要提交一个图像处理系统, 正好之前对于opencv有些了解,就简单的写一个人脸识别小程序吧 效果图如下 笔者IDE使用Pycharm,GUI编程直接使用内置的tkinte ...
- C# 图片人脸识别
此程序基于 虹软人脸识别进行的开发 前提条件从虹软官网下载获取ArcFace引擎应用开发包,及其对应的激活码(App_id, SDK_key)将获取到的开发包导入到您的应用中 App_id与SDK_k ...
- 使用 HTML5, javascript, webrtc, websockets, Jetty 和 OpenCV 实现基于 Web 的人脸识别
这是一篇国外的文章,介绍如何通过 WebRTC.OpenCV 和 WebSocket 技术实现在 Web 浏览器上的人脸识别,架构在 Jetty 之上. 实现的效果包括: 还能识别眼睛 人脸识别的核心 ...
- Home Assistant系列 -- 接入手机摄像头做实时监控和人脸识别
准备一部废旧(土豪忽略,主要是穷)的.摄像头还是好的手机做监控设备,(Android 和iPhone都行)当Home Assistant 获得实时的视频流后,可以接入各种图像处理组件完成人脸识别,动作 ...
- 我的opencv之旅:ios人脸识别
学习opencv有一年多了,这本来是我的毕业设计的一部分,但是因为不能突出专业重点,所以换了个课题. opencv在vc.android.ios下都能用,其中vc和android下的教程和主题贴最多, ...
- Python3利用Dlib19.7实现摄像头人脸识别的方法
0.引言 利用python开发,借助Dlib库捕获摄像头中的人脸,提取人脸特征,通过计算欧氏距离来和预存的人脸特征进行对比,达到人脸识别的目的: 可以自动从摄像头中抠取人脸图片存储到本地,然后提取构建 ...
随机推荐
- Gson使用
Gson提供了fromJson()方法来实现从Json相关对象到Java实体的方法. 在日常应用中,我们一般都会碰到两种情况,转成单一实体对象和转换成对象列表或者其他结构. 先来看第一种: 比如jso ...
- ajax 的error参数
ajax发生错误会进入到error中,我们在这里把错误信息从控制台中输出出来,为了避免每次写ajax都得写好几个console.log(). 我在这里写一个模板,需要用的时候直接过来拷贝. error ...
- js面向对象(二)——继承
上一篇随笔讲了封装,这一篇我们说说继承,还是那上一篇猫和狗说事儿 function Dog(name,s){ this.name=name; this.sex=s; } Dog.prototype.t ...
- 问题记录——com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
最近在搞一个Spring boot + Mybatis + Mysql的项目,用Mybatis访问数据库时,报了如下的错误,先在网上搜索了,试了各种办法都不行, 奇葩的是,连接另外1个数据库又没问题. ...
- restsharp 组件调用返回 gbk 编码的api,中文乱码解决方法。(restsharp response 中文乱码 gbk)
最近要调一个restful风格的api 用了 一个开源第三方组件,组件还是蛮好用的, 支持直接按参数定义实体类,然后发起请求之前直接 addobject 的方式就把请求参数给添加进去了, 解码的时候可 ...
- centos 7编译安装apache
1.安装工具和依赖包 yum install unzipyum -y install gcc gcc-c++ 2.创建软件安装目录mkdir /usr/local/{apr,apr-util,apr- ...
- 【随笔】 MyEclipse2014的安装和破解
MyEclipse,是在eclipse 基础上加上了自己的插件.MyEclipse,是在eclipse 基础上加上自己的插件开发而成的功能强大的企业级集成开发环境,主要用于Java.Java EE以及 ...
- PHP正则表达式(转载)
这个星期要攻破PHP正则表达式 正则表达式定义 正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串.将匹配的子串做替换或者从某个串中取 ...
- 【转】C++和Java比较
"作为一名C++程序员,我们早已掌握了面向对象程序设计的基本概念,而且Java的语法无疑是非常熟悉的.事实上,Java本来就是从C++衍生出来的." 然而,C++和Java之间仍存 ...
- win10-查看wifi密码
1:查看pc连接的wifi名称:netsh wlan show profile 2:生成xml文件: netsh wlan export profile name= YJ-PC_Network fo ...