用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库捕获摄像头中的人脸,提取人脸特征,通过计算欧氏距离来和预存的人脸特征进行对比,达到人脸识别的目的: 可以自动从摄像头中抠取人脸图片存储到本地,然后提取构建 ...
随机推荐
- 认识CSS中css引入方式、选择器、文本样式设置以及显示模式
前端之HTML.CSS(三) CSS CSS-Cascading Styles Sheets,层叠样式表.用于网页的表现,主要用于布局和修饰网页. CSS引入方式 CSS的三种引入方式:行内样式,内部 ...
- 微信小程序回到顶部的两种方式
一,使用view形式的回到顶部 <image src='../../img/button-top.png' class='goTop' hidden='{{!floorstatus}}' bin ...
- 关于dedecms数据量大以后生成目录缓慢的问题解决
四月份的时候博客被封.我不知情.因为一直很忙,没有来得及看.前两天来看以后,发现居然被封,吓傻了我. 赶紧找原因,原来是转载了某个人的博文,被他举报了,然后就被封了. 觉得很伤心,毕竟这个博客陪伴了我 ...
- 20190430-BootstrapのJS插件
目录 1.引用 2. 内容 1.引用 引用该插件需注意俩点 1.1插件依赖JQ:JQ必须在所有插件之前,bower.json内列出BT所支持的JQ版本(1.9.1-3) BootCDNのJQ J ...
- ImportError: No module named 'tkinter'
环境说明: windows7.vscode1.33.1.python3.7.0. 解决方案: 通过安装程序单独卸载“tcl/tk and IDLE”------重新安装“tcl/tk and IDLE ...
- win10操作系统系统,小米路由器,小米3 的问题
注意 , 置顶 单独一篇 : { win10 局域网共享 小米路由器,操作盘太卡 } 开发中用专业版 , 别用家庭版 比如有远程桌面程序 和 HV 虚拟机 查看激活信息 和 是不是永久激活 参考 h ...
- Unity中利用委托与监听解耦合的思路
这篇随笔是一篇记录性的随笔,记录了从http://www.sikiedu.com/my/course/304,这门课程中学到的内容,附带了一些自己的思考. 一.单例模式的应用 首先假想一种情况,现在需 ...
- logback.xml文件配置(按时间、文件大小和log名称生成日志)
之前项目中日志多用的log4j2,偶然看到在importNew看到了logback,自己查了下,发现Logback和log4j是非常相似的,其作者也是同一个人,并且logback相比于log4j性能更 ...
- 浏览器获取WEB服务器时间
/* * 获取XMLHttpRequest对象 */ function CreateXMLHttpRequest() { var xmlreq = false; if (window.ActiveXO ...
- Robot Framework常用关键字介绍
常用关键字介绍 在学习一门编程语言的时候,大多教材都是从打印“hello world”开始.我们可以像编程语言一样来学习 Robot Framework.虽然通过 RIDE 提供“填表”一样的写测试用 ...