opencv人脸检测

opencv人脸检测

最近有空对学习下opencv的东西,本篇主要记录对人脸检测实现,而人脸检测是为人脸识别做准备。

opencv版本:3.3.0
环境:VS2015

关键函数介绍

void CascadeClassifier::detectMultiScale(InputArray image, 
                                vector<Rect>& objects,
                                double scaleFactor=1.1,
                                int minNeighbors=3, 
                                int flags=0, 
                                Size minSize=Size(), 
                                Size maxSize=Size());
  • image:输入的图像,注意是CV_8U类型的,也就是灰度图;
  • objects:矩形的vector对象用来存放检测到的人脸;
  • scaleFactor:指定图像减少了多少,即每次扫描中搜索窗口的增大比例,默认为1.1;
  • minNeighbors:构成检测目标相邻矩阵的最小个数,默认为3,如果该参数为0,函数不做任何操作就返回所有的候选矩形框;
  • flags:对于新的分类器无用
    • CV_HAAR_DO_CANNY_PRUNING:利用Canny边缘检测时会排除一些边缘很少或者很多的图像区域;
    • CV_HAAR_SCALE_IMAGE:按正常比例监测;
    • CV_HAAR_FIND_BIGGEST_OBJECT:只检测最大的物体;
    • CV_HAAR_DO_ROUGH_SEARCH:只做粗略检测;
  • minSize:检测窗口的最小值
  • maxSize:监测窗口的最大值

人脸检测的过程其实也就是一个分类的过程,CascadeClassifier是opencv中人脸检测的一个级联分类器。opencv中目标检测是使用Haar分类器来实现的(后面也使用了LBP特征),这是一种监督学习分类器,使用的是AdaBoost算法。AdaBoost算法的基本过程是对给定的训练样本进行训练得到弱分类器,然后通过多个弱分类器进行加权叠加得到强分类器。弱分类器和强分类器与若学习和强学习对应,弱学习是指学习算法的识别率只是比随机识别稍好;强学习是指学习算法识别概率很高。

人脸检测

opencv为我们提供了方便API,我们只要调用就可以快速实现人脸检测,过程主要是:

读取图片 -> 转化成灰度图 -> 对灰度图进行直方图均衡化 -> 调用detectMultiScale进行人脸检测 -> 将结果转化成人脸识别需要的训练集格式

在这之前需要获取人脸的照片,这个很好办,打开手机疯狂自拍或者从网上下载一些包含人脸的照片即可。由于我还想用这些数据集来做识别,因此我这里用的是自己的人脸。

#include<opencv2/objdetect/objdetect.hpp>
#include<iostream>
#include<opencv2\core\core.hpp>
#include<opencv2\opencv.hpp>
#include<opencv2\highgui.hpp>
#include<cv.h>
using namespace std;
using namespace cv;
String face_config_name = "D:/whz_tools/opencv/opencv/vc14x64/etc/haarcascades/haarcascade_frontalface_default.xml";
CascadeClassifier face_cascade;
vector<Rect_<int> > faces;
int main()
{
    //存放照片
    string file_path_in = "D:/workspace/VS/opencv/face_detect/face_detect/data/photo/";
    //存放结果的人脸
    string file_path_out = "D:/workspace/VS/opencv/face_detect/face_detect/data/face/";
    vector<string> files;
    get_files(file_path_in, files);     //获取目录下的文件名
    Mat img,img_gray,faceROI;
    string tmp_file_name;
    assert(face_cascade.load(face_config_name));//导入分类器
    for (int i = 0; i < files.size(); ++i)
    {
        tmp_file_name = file_path_in + files[i];
        img = imread(tmp_file_name);
        assert(!img.empty());
        cvtColor(img, img_gray, CV_BGR2GRAY);//转化成灰度图来加快人脸识别的速度
        equalizeHist(img_gray, img_gray);   //直方图均衡化
        face_cascade.detectMultiScale(img_gray, faces, 1.1, 2, CV_HAAR_SCALE_IMAGE, Size(30, 30));
        if (faces.size() > 0)
        {
            for (int j = 0; j < faces.size(); ++j)
            {
                faceROI = img(faces[j]); //将img中人脸区域赋值给faceROI
                if (faceROI.cols > 100)
                {
                    resize(faceROI, faceROI, Size(92, 112));//调整大小
                    tmp_file_name = file_path_out + files[i];
                    imwrite(tmp_file_name, faceROI);
                }
                /*
                也可以不调整大小,直接在原图中画出矩形
                Point p1 = Point(faces[i].x, faces[i].y);
                Point p2 = Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
                rectangle(img, p1, p2, Scalar(255, 0, 0), 2, 8, 0);
                */
            }
        }   
    }
    return 0;
}

对于上面的代码进行如下说明:

  • haarcascade_frontalface_default.xml是opencv提供的Haar分类器的xml文件,其中存放了描述物体的Haar特征值,直接导入该文件就可以使用Haar分类器,也可以使用其它自带xml文件(如haarcascade_frontalface_alt2.xml)。该文件最好使用绝对路径导入,若导入失败就不能坚信人脸检测;
  • vector<Rect_<int> > faces;用来存放识别后的人脸矩形框,最好定义成全局变量,有网友说局部变量在Debug时会出现问题;
  • resize(faceROI, faceROI, Size(92, 112));这里之所以需要调整成92 * 112的大小是为了后续人脸识别做准备,人脸识别选择的是AT&T的The ORL Database of Faces数据库,其中包含了40个不同人的脸,每个人有10张照片,而该数据集的图片大小就是92 * 112;

获取目录下的文件名

这里希望能够自动化处理采集的图像,因此需要自动获取目录下的文件名,然后根据文件名自动处理每个图像。也就是上面代码中get_files函数:

#include<iostream>
#include<io.h>
#include<string>  
using namespace std;  
/*获取目录下的文件名*/
void get_files(string file_path, vector<string>& files)
{
    long file_handler = 0;  //文件句柄
    _finddata_t fileinfo;
    string p;
    if ((file_handler = _findfirst(file_path.append("\\*").c_str(), &fileinfo)) == -1)
    {
        cout << file_path<<" not found"<< endl;
    }
    else 
    {
        while (_findnext(file_handler, &fileinfo) == 0)
        {
            if (strcmp(fileinfo.name, ".") == 0 || strcmp(fileinfo.name, "..") == 0)
                continue;
            files.push_back(fileinfo.name);
        }
    }
    _findclose(file_handler);
}

获取目录下的文件中的关键的结构是_finddata_t,定义在io.h头文件中:

struct _finddata_t
{
     unsigned attrib;       //文件的存储属性
     time_t time_create;    //文件创建时间
     time_t time_access;    //最后一次被访问的时间
     time_t time_write;     //最后一次被修改的时间
     _fsize_t size;         //文件大小
     char name[_MAX_FNAME]; //文件名
};

该结构用来存储文件信息,而查找就需要靠_findfirst_findnext_fineclose

/*@return 若查找成功,将返回long型的文件句柄,该句柄在_findnext中使用;若失败则返回-1;
@param filespec:文件名,支持通配符;
@param fileinfo:存放文件信息的结构体指针;*/
long _findfirst( char *filespec, struct _finddata_t *fileinfo );

/*@return 若成功返回0,否则返回-1;
@param handle:_findfirst返回的文件句柄
@param fileinfo:存放文件信息的结构体指针,找到文件后放入此结构;*/
int _findnext( long handle, struct _finddata_t *fileinfo );

/*@return 结束查找,若成功返回0,否则返回-1;
@param handle:_findfirst返回的文件句柄*/
 int _findclose( long handle );

结果

当程序运行结束时就可以得到92 * 112的人脸图像,可以进行后续的人脸识别了!

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值