代码改变世界

OpenCV 2.4+ C++ 人脸识别

2012-11-22 09:58  Justany_WhiteSnow  阅读(24845)  评论(16编辑  收藏  举报

机器学习

  • 机器学习的目的是把数据转换成信息。
  • 机器学习通过从数据里提取规则或模式来把数据转成信息。

 

人脸识别

  • 人脸识别通过级联分类器对特征的分级筛选来确定是否是人脸。
  • 每个节点的正确识别率很高,但正确拒绝率很低。
  • 任一节点判断没有人脸特征则结束运算,宣布不是人脸。
  • 全部节点通过,则宣布是人脸。

工业上,常用人脸识别技术来识别物体。 

 

对图片进行识别

#include "opencv2/core/core.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

string face_cascade_name = "haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;
string window_name = "人脸识别";

void detectAndDisplay( Mat frame );

int main( int argc, char** argv ){
    Mat image;
    image = imread( argv[1]);

    if( argc != 2 || !image.data ){
        printf("[error] 没有图片\n");
        return -1;
    }

    if( !face_cascade.load( face_cascade_name ) ){ 
        printf("[error] 无法加载级联分类器文件!\n");
        return -1; 
    }

    detectAndDisplay(image);

    waitKey(0);    
}

void detectAndDisplay( Mat frame ){
    std::vector<Rect> faces;
    Mat frame_gray;

    cvtColor( frame, frame_gray, CV_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );

    face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );

    for( int i = 0; i < faces.size(); i++ ){
        Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
        ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
    }

    imshow( window_name, frame );
}

效果:

 

 

CascadeClassifier类

class CascadeClassifier

用于检测物体的级联分类器类。

CascadeClassifier::CascadeClassifier

从一个文件读取分类器。

C++: CascadeClassifier::CascadeClassifier(const string& filename)
参数 filename – 所要读取分类器文件的文件名

CascadeClassifier::empty

检查分类器是否已经载入。

C++: bool CascadeClassifier::empty() const

CascadeClassifier::load

从一个文件读取分类器。

C++: bool CascadeClassifier::load(const string& filename)
参数 filename – 所要读取分类器文件的文件名。文件可以是旧版的HAAR分类器模型也可以是新版的分类器模型。

CascadeClassifier::read

读取一个文件存储节点的分类器

C++: bool CascadeClassifier::read(const FileNode& node)

CascadeClassifier::detectMultiScale

对不同大小的输入图像进行物体识别,并返回一个识别到的物体的矩阵列表。

C++: void CascadeClassifier::detectMultiScale(const Mat& 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 – 指定每张图片的缩小比例的参数。
  • minNeighbors – 指定每个候选矩阵至少包含的邻近元素个数。
  • flags与旧版级联分类器模型函数cvHaarDetectObjects的flags相同. 此参数不被用于新版模型。
  • minSize最小可能的对象的大小,小于的对象将被忽略
  • maxSize最大可能的对象的大小,大于对象将被忽略。

CascadeClassifier::setImage

设置被用于检测的图像

C++: bool CascadeClassifier::setImage(Ptr<FeatureEvaluator>& feval, const Mat& image)
参数
  • feval – 用于特征计算的特征求值程序的指针。
  • image – 需要进行特征检测的 CV_8U 输入矩阵。

这个函数将在每张图片中被 CascadeClassifier::detectMultiScale() 自动调用。 但如果你想在不同位置手动使用 CascadeClassifier::runAt(),你需要先调用该函数,使得图像被积分计算。

CascadeClassifier::runAt

在指定点运行检测。

C++: int CascadeClassifier::runAt(Ptr<FeatureEvaluator>& feval, Point pt, double& weight)
参数

feval – 用于特征计算的特征求值程序。

pt – 指定检测窗口左上角的点。窗口的大小和检测的图片大小一致。

如果级联分类器检测给定的位置中的一个对象该函数返回1否则,它会返回已被否决候选区域在哪个阶段的否定指数

使用CascadeClassifier::setImage() 设置图像检测工作

代码注释:

//需要载入的级联分类器文件
string face_cascade_name = "haarcascade_frontalface_alt.xml";
//级联分类器类
CascadeClassifier face_cascade;

//……

    //载入级联分类器,并判断是否载入成功,如果不成功则打印提示
    if( !face_cascade.load( face_cascade_name ) ){ 
        printf("[error] 无法加载级联分类器文件!\n");
        return -1; 
    }

//……

    //对图片frame进行识别检测
    face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );

 

转换成灰度图

由于CascadeClassifier类只支持CV_8U矩阵数据,所以我们需要将图片变成灰度图。

cvtColor API:

将图片从一个色彩空间转到另一个色彩空间。

C++: void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )
参数
  • src输入图像8位无符号16位无符号CV_16UC...)或单精度浮点数据类型
  • dst – 输出图像,与输入图像相同大小、深度。
  • code颜色空间转换代码
  • dstCn – 目标图像的通道数,当该参数为0时,则通道树由src和code自动得出。

该函数将输入图片从一个色彩空间转到另一个色彩空间。当从RGB颜色空间进行变换时,应明确指定的信道的顺序(RGB或BGR)。值得注意,在OpenCV的默认颜色格式中,通常被称为作为RGB,但实际上是BGR(字节是相反的)。因此,在一个标准的(24位)的彩色图像的第一个字节是一个8位的蓝色分量,第二个字节将是绿色的,第三个字节将是红色的。而第四,第五,和第六字节,则是第二像素(蓝,然后绿色,然后红色),依此类推。

R、G和B 通道通常信道值范围:

  • CV_8U:0 — 255
  • CV_16U:0 — 65535
  • CV_32F:0 — 1

线性变换的情况下,有没有范围是无所谓的。但是,在一个非线性变换的情况下,输入的RGB图像应被归为适当的值范围内,以得到正确的结果。例如,如果你有一个32位浮点图像直接转换成一个8位的图像而没有任何缩放,那么它将有0到255的数值范围,而这并不能准确0..1所有浮点数的值。所以,你需要之前调用cvtColor,进行图像缩放。

代码注释:

//将frame转换成灰度图,输出到frame_gray
cvtColor( frame, frame_gray, CV_BGR2GRAY );

 

直方图均衡化

  • 直方图是图像中像素强度分布的图形表达方式。
  • 它统计了每一个强度值所具有的像素个数。

  http://www.cnblogs.com/http://www.cnblogs.com/../_images/Histogram_Equalization_Theory_0.jpg

  • 直方图均衡化是通过拉伸像素强度分布范围来增强图像对比度的一种方法。
  • 说得更清楚一些, 以上面的直方图为例, 你可以看到像素主要集中在中间的一些强度值上. 直方图均衡化要做的就是 拉伸 这个范围. 见下面左图: 绿圈圈出了 少有像素分布其上的 强度值. 对其应用均衡化后, 得到了中间图所示的直方图. 均衡化的图像见下面右图.

  http://www.cnblogs.com/http://www.cnblogs.com/../_images/Histogram_Equalization_Theory_1.jpg

我们利用直方图均衡化对图片增强对比度,方便级联分类器分析。

equalizeHist API:

对灰度图像进行直方图均衡。

C++: void equalizeHist(InputArray src, OutputArray dst)
参数
  • src – 源为8位单通道图像。
  • dst – 输出图像,和源图片同样大小类型。

直方图均衡函数使用了下列的算法:

  1. 计算源文件的直方图 H 。

  2. 调整直方图,使得其方格总个数为255。

  3. 对直方图进行积分:

    H'_i =  \sum _{0  \le j < i} H(j)

  4. 使用 H' 变换图片,其映射函数为:\texttt{dst}(x,y) = H'(\texttt{src}(x,y))

该算法归一化亮度并增加了图像的对比度。

 

 

 

被山寨的原文

Cascade Classifier . OpenCV.org

Cascade Classification API . OpenCV.org

Histogram Equalization . OpenCV.org