用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, 3, 0, Size(50, 50), Size(500, 500));  //检测人脸
    for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
    {
        rectangle(image, *iter, Scalar(0, 0, 255), 2, 8); //画出脸部矩形
    }
    for (size_t i = 0; i<faces.size(); i++)
    {
        Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
        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(64, ‘\0‘);    //定义一个字符串并初始化
    Mat origianlImage, dctImage;                //定义几个矩阵
    Mat floatImage, imageDct;
    if (src.channels() == 3) //判断通道数量
        cvtColor(src, origianlImage, CV_BGR2GRAY); //转换格式
    else
        origianlImage = src.clone(); //不用转换
    resize(origianlImage, origianlImage, Size(32, 32)); //缩小图片尺寸为32*32
    origianlImage.convertTo(floatImage, CV_32FC1); //转换类型
    dct(floatImage, imageDct); //进行DCT运算(离散余弦变换)
    Rect roi(0, 0, 8, 8);  //定义一个8*8的矩阵
    dctImage = imageDct(roi); //将8*8的矩阵赋给dctImage
    uchar *pData;
    for (int i = 0; i<dctImage.rows; i++)
    {
        pData = dctImage.ptr<uchar>(i);
        for (int j = 0; j<dctImage.cols; j++)
        {
            pData[j] = pData[j] / 4;
        }
    }

    int average = mean(dctImage).val[0];//求平均值
    Mat mask = (dctImage >= (uchar)average); //与平均值进行比较
    int index = 0; //用于计数
    for (int i = 0; i<mask.rows; i++)
    {
        pData = mask.ptr<uchar>(i);
        for (int j = 0; j<mask.cols; j++)
        {
            if (pData[j] == 0)
                zeroonestr[index++] = ‘0‘;
            else
                zeroonestr[index++] = ‘1‘;
        }
    }
    return zeroonestr;  //返回一个64位的全是0或1的字符串
}

  计算两幅图片汉明距离代码

int calHanmingDistance(string &str1, string &str2)       //求两张图片的海明距离
{
    if ((str1.size() != 64) || (str2.size() != 64))
        return -1;
    int countstoreHamingdistance = 0;
    for (int i = 0; i<64; 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; //10张图片,图片越多越难正确识别

string calHashValue(Mat &src)      //得到图片的哈希值
{
    string zeroonestr(64, ‘\0‘);    //定义一个字符串并初始化
    Mat origianlImage, dctImage;                //定义几个矩阵
    Mat floatImage, imageDct;
    if (src.channels() == 3) //判断通道数量
        cvtColor(src, origianlImage, CV_BGR2GRAY); //转换格式
    else
        origianlImage = src.clone(); //不用转换
    resize(origianlImage, origianlImage, Size(32, 32)); //缩小图片尺寸为32*32
    origianlImage.convertTo(floatImage, CV_32FC1); //转换类型
    dct(floatImage, imageDct); //进行DCT运算(离散余弦变换)
    Rect roi(0, 0, 8, 8);  //定义一个8*8的矩阵
    dctImage = imageDct(roi); //将8*8的矩阵赋给dctImage
    uchar *pData;
    for (int i = 0; i<dctImage.rows; i++)
    {
        pData = dctImage.ptr<uchar>(i);
        for (int j = 0; j<dctImage.cols; j++)
        {
            pData[j] = pData[j] / 4;
        }
    }

    int average = mean(dctImage).val[0];//求平均值
    Mat mask = (dctImage >= (uchar)average); //与平均值进行比较
    int index = 0; //用于计数
    for (int i = 0; i<mask.rows; i++)
    {
        pData = mask.ptr<uchar>(i);
        for (int j = 0; j<mask.cols; j++)
        {
            if (pData[j] == 0)
                zeroonestr[index++] = ‘0‘;
            else
                zeroonestr[index++] = ‘1‘;
        }
    }
    return zeroonestr;  //返回一个64位的全是0或1的字符串
}
int calHanmingDistance(string &str1, string &str2)       //求两张图片的海明距离
{
    if ((str1.size() != 64) || (str2.size() != 64))
        return -1;
    int countstoreHamingdistance = 0;
    for (int i = 0; i<64; 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, 3, 0, Size(50, 50), Size(500, 500));  //检测人脸
    for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
    {
        rectangle(image, *iter, Scalar(0, 0, 255), 2, 8); //画出脸部矩形
    }
    for (size_t i = 0; i<faces.size(); i++)
    {
        Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
        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, 3, 0, Size(50, 50), Size(500, 500));  //检测人脸
    for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
    {
        rectangle(image, *iter, Scalar(0, 0, 255), 2, 8); //画出脸部矩形
    }
    imshow("图片中的人脸检测", image);
}
int main(int argc, char** argv)
{
    cout << "请输入想要选择的图片" << endl;
    int referencepicture; //用于参考的图片
    int ImageNum; //用于遍历的计数变量
    int storeHamingdistance[9]; //用于储存图片的海明距离
    cin >> referencepicture; //输入参考图片的编号
    const string path1 = format("H:\\picture\\opencv\\jackchen\\%d.jpg", referencepicture);//获取参考图片的路径  //这个路径要根据你电脑的位置来设置
    Mat originalImage, processImage, faceImage;
    originalImage = imread(path1, -1); //获取图片
    faceImage = imread(path1, -1); //获取图片
    string str1, str2, path2; //定义几个字符串
    cvNamedWindow("选择的图片", 1);
    /*cvResizeWindow("选择的图片",700,500);*/
    imshow("选择的图片", originalImage);
    DrawFaceRectangl(faceImage);     //截取人脸,并显示出来
    IdentifyFace(originalImage);    //识别并截取人脸
    str1 = calHashValue(originalImage);   //求出汉明距离
    cvWaitKey(300);
    for (ImageNum = 1; ImageNum <= ImageSumNumber; ImageNum++)//因为我完成的就是8张图片的检测,所以循环值为8
    {
        path2 = format("H:\\picture\\opencv\\jackchen\\%d.jpg", ImageNum);  //这个路径要根据你电脑的位置来设置
        processImage = imread(path2, -1);
        IdentifyFace(processImage);
        str2 = calHashValue(processImage);
        storeHamingdistance[ImageNum] = calHanmingDistance(str1, str2);
    }

    int min = 65;   //这个自己确定,大于64就可以了
    int storemostsimilarImage;  //用于储存最相似的图片的编号
    for (ImageNum = 1; ImageNum <= ImageSumNumber; ImageNum++)    //循环值为8,求与原图片汉明距离最小的那张图片
    {
        if (storeHamingdistance[ImageNum]<min && storeHamingdistance[ImageNum] != 0)
        {
            min = storeHamingdistance[ImageNum];
            storemostsimilarImage = ImageNum;     //检测出的标记为t
        }
    }
    path2 = format("H:\\picture\\opencv\\jackchen\\%d.jpg", storemostsimilarImage);  //这个路径要根据你电脑的位置来设置
    processImage = imread(path2, -1);//将最相似的图片显示出来
    cvNamedWindow("相似的图片", 1);
    imshow("相似的图片", processImage);//这时显示的就是最相似的照片
    cvWaitKey(0);
    cin.get();                    //吃掉回车符
}

下面是我的图片库:

效果:

不足:大家可以看到,检测图片中的人脸时,把旁边的也识别成人脸了,还有就是图片多的时候,识别效果会很差,所以说实用性不强,欢迎交流。下次尝试用深度学习来做。

时间: 2024-11-10 10:03:56

用opencv做的静态图片人脸识别的相关文章

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

Demo功能:利用android自带的人脸识别进行识别,标记出眼睛和人脸位置.点击按键后进行人脸识别,完毕后显示到imageview上. 第一部分:布局文件activity_main.xml [html] view plaincopyprint? <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.co

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

读入图片,算法检测,画出矩形框 import cv2 from PIL import Image,ImageDraw import os def detectFaces(image_name): img = cv2.imread(image_name) face_cascade = cv2.CascadeClassifier('../opencv-2.4.9/data/haarcascades/haarcascade_frontalface_default.xml') if img.ndim==

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

原理:使用GT人脸库做样本,VS2010下使用openCV2.44自带的Haar算法检測人脸区域,ASM Library特征检測,然后使用YCrCb颜色空间做肤色检測,再用LBP+Gabor小波提取特征,最小邻近距离做分类识别. 1.GT人脸库 Georgia Tech face database,网址:http://www.anefian.com/research/face_reco.htm GT人脸库包括50个人,每人15张不同角度.不同表情的正面照片. 图片为JPG格式,640*480,大

利用openCV实现自动抓拍,人脸识别,清晰度的验证等

1.本文主要涉及到opencv的视频帧抓拍和验证的相关问题,不包含如何集成opencv 2.主要讲解涉及到opencv中的关键类及一些常用的方法 3.着重讲解代理方法: - (void)processImage:(cv::Mat &)image 4.集成过程中的注意事项 5.附上抓拍的小demo的下载地址 6.扩展,验证抓拍的图片中是否包含人脸 =====================================分割线====================================

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

准备一部废旧(土豪忽略,主要是穷)的.摄像头还是好的手机做监控设备,(Android 和iPhone都行)当Home Assistant 获得实时的视频流后,可以接入各种图像处理组件完成人脸识别,动作检测等功能. 第一步:手机端安装ip_webcam(IP摄像头)App        1.Android手机 Android手机 打开手机应用市场,搜索ip_webcam或IP摄像头,安装App. 启动App,在出现的设置界面底部点击开启服务器,摄像头进入拍摄传输模式. 记录视频监控界面底部显示的手

C# 图片人脸识别

此程序基于 虹软人脸识别进行的开发 前提条件从虹软官网下载获取ArcFace引擎应用开发包,及其对应的激活码(App_id, SDK_key)将获取到的开发包导入到您的应用中 App_id与SDK_key是在初始化的时候需要使用基本类型所有基本类型在平台库中有定义. 定义规则是在ANSIC 中的基本类型前加上字母“M”同时将类型的第一个字母改成大写.例如“long” 被定义成“MLong”数据结构与枚举 AFR_FSDK_FACEINPUT描述: 脸部信息定义typedef struct{MRE

OpenCV实践之路——人脸识别之一数据收集和预处理

本文由@星沉阁冰不语出品,转载请注明作者和出处. 文章链接:http://blog.csdn.net/xingchenbingbuyu/article/details/51386949 微博:http://weibo.com/xingchenbing  前段时间对人脸检测和人脸标记进行了一些尝试:人脸检测(C++/Python)和用Dlib库进行人脸检测和人脸标记.但是检测和识别是不同的,检测解决的问题是图片中有没有人脸:而识别解决的问题是,如果一张图片中有人脸,这是谁的脸.人脸检测可以利用op

python之OpenCv(四)---人脸识别

对特定图像进行识别,最关键的是要有识别对象的特征文件.OpenCV已经内置了人脸识别特征文件,我们只要使用OpenCV的CascadeClassifier类即可进行识别. 语法: https://github.com/opencv/opencv.git 在这里可以下载特征文件,在data目录下 识别对象变量 = cv2.CascadeClassifier(特征文件).. 识别对象 识别结果变量 = 识别对象变量.detectMultiScale(图片,参数1,参数2,...) 参数有: 1.sc

python使用opencv实现人脸识别系统

1.首先安装过python环境,在这里就不过说    检测是否安装成功如下,在cmd中输入Python     2.安装numpy 现在开始安装numpy,打开cmd,输入pip install numpy 我的电脑已经安装过了,忘记截屏了.就在网上找了图片 测试是否成功 3.安装opencv 在官网自行下载,这里下载的是opencv2.4.10安装. ### (1)复制cv2.pyd 将"\opencv\build\python\2.7\x64"或"\opencv\buil