用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库捕获摄像头中的人脸,提取人脸特征,通过计算欧氏距离来和预存的人脸特征进行对比,达到人脸识别的目的: 可以自动从摄像头中抠取人脸图片存储到本地,然后提取构建 ...
随机推荐
- 解决php -v查看到版本于phpinfo()打印的版本不一致问题
https://blog.csdn.net/haif_city/article/details/81315372 整个事件的起因是这样的 通过git拉取laraevl项目发现缺少.env文件,打算使用 ...
- Q844 比较含退格的字符串
给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果. # 代表退格字符. 示例 1: 输入:S = "ab#c", T = " ...
- 用selenium工具做软件自动化测试的面试题及答案
1.selenium中如何判断元素是否存在? 答:isElementPresent 2.selenium中hidden或者是display = none的元素是否可以定位到? 答:不可以定位到 3.s ...
- Vue axios 上传图片
上传图片接口 // 上传图片 export const uploadBanner = formData => { return axios.request({ url: 'manage/slid ...
- DP Intro - poj 1947 Rebuilding Roads
算法: dp[i][j]表示以i为根的子树要变成有j个节点的状态需要减掉的边数. 考虑状态转移的时候不考虑i的父亲节点,就当不存在.最后统计最少减去边数的 时候+1. 考虑一个节点时,有两种选择,要么 ...
- PHP面向对象的基本原则
对象内部是高内聚的 ——对象只负责一项特定的功能(职能可大可小) ——所有对象相关的内容都封装到对象内部 高内聚就是该有的都有,用的时候不会缺胳膊少腿! 对象对外是低耦合的 ——外部世界可以看到对象的 ...
- Jmeter性能测试之添加思考时间
利用定时器添加用户思考时间 JMeter如何插入思考时间,在一个真实的性能测试场景中,是需要加入思考时间,来模拟真实用户行为.本文就来介绍,如何在三个请求之间添加思考时间. 1. 在Test Plan ...
- springmvc整合mybatis详细教程
需求:整合springmvc和mybatis 整合的目标是:控制层采用springmvc,持久层使用mybatis 整合思想 dao层: 1.SqlMapConfig.xml.空文件即可.但是需要头文 ...
- 架构实战项目心得(十一):基于spring-security-oauth2的mysql数据表设计
一.建立数据库及数据表结构 CREATE SCHEMA IF NOT EXISTS `oauth2` DEFAULT CHARACTER SET utf8 ; USE `oauth2` ; -- -- ...
- 使用Charles为Android设备抓取https请求的包
之前开发的Android APP使用的都是http请求,之后改成了https,就出现了以下情况,无法正常读取抓取的内容 找了好多资料说法大概差不多,照着弄,结果出现如下情况,后来发现这种情况其实是手机 ...