用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库捕获摄像头中的人脸,提取人脸特征,通过计算欧氏距离来和预存的人脸特征进行对比,达到人脸识别的目的: 可以自动从摄像头中抠取人脸图片存储到本地,然后提取构建 ...
随机推荐
- Behind the scenes of the C# yield keyword(转)
https://startbigthinksmall.wordpress.com/2008/06/09/behind-the-scenes-of-the-c-yield-keyword/ Behind ...
- V1-bug Alpha阶段测试报告
发现的Bug Bug现象 Bug原因 是否解决 访问到错误的视图 路由正则写的太过宽泛 是 主题太长时超过页面宽度,导致超过顶部的宽度 / 否 无法使用域名访问服务器 后端没有在配置文件的ALLOWE ...
- iview tree 之如何获取已勾选的节点
1.记得添加 ref 2.用 this.$refs.tree.getCheckNodes()
- node.js修改全局安装文件路径
在进行 node.js 的开发过程中,我们需要下载大量的依赖模块,为了不让 c 盘的东西太过于散乱,可以通过修改node的配置参数,来修改node依赖的下载路径. 步骤: ①创建两个文件夹:node_ ...
- es put mapping
fd dg public Map<String, Map<String, String>> javaBeanToMapping(Object instance, List< ...
- 浅谈Cordova优缺点与环境部署(转载)
浅谈Cordova优缺点与环境部署 作者:苏华杰 简介 Cordova是一个用基于HTML.CSS和JavaScript的,用于创建跨平台移动应用程序的快速开发平台.它使开发者能够利用iPhone.A ...
- selenium+Python(Js处理日历控件)
日历控件是web网站上经常会遇到的一个场景,有些输入框是可以直接输入日期的,有些不能,以我们经常抢票的12306网站为例,详细讲解如何解决日历控件为readonly属性的问题. 基本思路:先用js去掉 ...
- 问题集录--JS如何处理和解析Json数据
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族 ...
- window.location.href.substr(window.location.href.length - 6)
if (window.location.href.substr(window.location.href.length - 6) == "flag=1") { var tOptio ...
- A space or line break was encountered after the "@" character. Only valid identifiers, keywords, comments, "(" and "{" are valid at the start of a code block and they must occur immediately following
mvc 控制器调用分布视图出错,("A space or line break was encountered after the "@" character. Only ...