这次给大家分享一个图像识别方面的小项目,主要功能是识别图像中的人脸并根据人脸在图片库找出同一个与它最相似的图片,也就是辨别不同的人。

  环境: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做的静态图片人脸识别的更多相关文章

  1. Android静态图片人脸识别的完整demo(附完整源码)

    Demo功能:利用android自带的人脸识别进行识别,标记出眼睛和人脸位置.点击按键后进行人脸识别,完毕后显示到imageview上. 第一部分:布局文件activity_main.xml < ...

  2. Opencv 入门学习之图片人脸识别

    读入图片,算法检测,画出矩形框 import cv2 from PIL import Image,ImageDraw import os def detectFaces(image_name): im ...

  3. openCV+ASM+LBP+Gabor实现人脸识别(GT人脸库)

    原理:使用GT人脸库做样本,VS2010下使用openCV2.44自带的Haar算法检測人脸区域,ASM Library特征检測,然后使用YCrCb颜色空间做肤色检測,再用LBP+Gabor小波提取特 ...

  4. python3+opencv+tkinter开发简单的人脸识别小程序

    学校里有门图像处理的课程最终需要提交一个图像处理系统, 正好之前对于opencv有些了解,就简单的写一个人脸识别小程序吧 效果图如下 笔者IDE使用Pycharm,GUI编程直接使用内置的tkinte ...

  5. C# 图片人脸识别

    此程序基于 虹软人脸识别进行的开发 前提条件从虹软官网下载获取ArcFace引擎应用开发包,及其对应的激活码(App_id, SDK_key)将获取到的开发包导入到您的应用中 App_id与SDK_k ...

  6. 使用 HTML5, javascript, webrtc, websockets, Jetty 和 OpenCV 实现基于 Web 的人脸识别

    这是一篇国外的文章,介绍如何通过 WebRTC.OpenCV 和 WebSocket 技术实现在 Web 浏览器上的人脸识别,架构在 Jetty 之上. 实现的效果包括: 还能识别眼睛 人脸识别的核心 ...

  7. Home Assistant系列 -- 接入手机摄像头做实时监控和人脸识别

    准备一部废旧(土豪忽略,主要是穷)的.摄像头还是好的手机做监控设备,(Android 和iPhone都行)当Home Assistant 获得实时的视频流后,可以接入各种图像处理组件完成人脸识别,动作 ...

  8. 我的opencv之旅:ios人脸识别

    学习opencv有一年多了,这本来是我的毕业设计的一部分,但是因为不能突出专业重点,所以换了个课题. opencv在vc.android.ios下都能用,其中vc和android下的教程和主题贴最多, ...

  9. Python3利用Dlib19.7实现摄像头人脸识别的方法

    0.引言 利用python开发,借助Dlib库捕获摄像头中的人脸,提取人脸特征,通过计算欧氏距离来和预存的人脸特征进行对比,达到人脸识别的目的: 可以自动从摄像头中抠取人脸图片存储到本地,然后提取构建 ...

随机推荐

  1. ABP相关网站

    ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate 系列文章 ...

  2. C# DataTable 用法

    1.创建DataTable DataTable dataTable = new DataTable(); //创建一个空表 2.创建DataRow DataRow row = dataTable.Ne ...

  3. python 流式游标读取mysql大型数据库

    import asyncio import aiomysql async def dbdaochu(loop): sqlstr='sql' conn = await aiomysql.connect( ...

  4. Google Map API抓取地图坐标信息小程序

    因为实验室需要全国城市乡镇的地理坐标,有Execl的地名信息,需要一一查找地方的经纬度.Google Map地图实验室提供自带的查找经纬度的方法,不过需要一个点一个点的手输入,过于繁琐,所以自己利用G ...

  5. JAVA学习6:用Maven创建Spring3 MVC项目

    一.      环境 spring-framework-3.2.4.RELEASE jdk1.7.0_11 Maven3.0.5 eclipse-jee-juno-SR2-win32 二.      ...

  6. 常见Http协议响应码

    总体总结: 1XX:信息相应类,表示接受到请求并且继续处理 2XX:处理成功响应类,表示动作被成功的接收.理解和接受 3XX:重定向响应类,为了完成指定的动作,必须完成进一步处理和操作 4XX:客户端 ...

  7. 用eclipse查看JDK源代码

    把jdk的源代码导入eclipse

  8. Firebird 条件函数

    1.iif  IIF (<condition>, ResultT, ResultF) 示例: select iif( sex = 'M', 'Sir', 'Madam' ) from Cu ...

  9. C#基础笔记 转自wojiushigelg

    笔记如下: 概念:.net与c# .net/dontnet:一般指.net framework框架,一种平台,一种技术 c#(charp):一种编程语言,可以开发基于.net的应用. *java既是一 ...

  10. first post

    post