Opencv2.4.9源码分析——Cascade Classification(二)

本文深入分析OpenCV2.4.9中级联分类器的源码,涉及CvHaarFeatureParams、CvLBPEvaluator等关键类和函数,详细阐述了HAAR、LBP、HOG特征的计算过程,以及级联分类器的训练和检测物体的实现。
摘要由CSDN通过智能技术生成

上一篇文章我们介绍了级联分类器的原理,下面我们给出级联分类器的源码分析。


训练级联分类器的源码在opencv/sources/app/traincascade目录下。

首先我们给出级联分类器的特征类型的相关类和函数。

CvHaarFeatureParamsCvLBPFeatureParamsCvHOGFeatureParams分别表示HAAR状特征、LBP特征和HOG特征的参数类,它们都继承于CvFeatureParams


class CvFeatureParams : public CvParams
{
public:
    //级联分类器能够使用三种特征类型用于训练样本:HAAR、LBP和HOG
    enum { HAAR = 0, LBP = 1, HOG = 2 };
    //缺省构造函数,赋值maxCatCount为0,featSize为1
    CvFeatureParams();
    //初始化maxCatCount和featSize
    virtual void init( const CvFeatureParams& fp );
    //表示向params.xml文件写入一些信息:maxCatCount和featSize的值
    virtual void write( cv::FileStorage &fs ) const;
    //表示从params.xml文件内读取一些信息:maxCatCount和featSize的值
    virtual bool read( const cv::FileNode &node );
    //构建相应的特征参数,即级联分类器具体使用哪种特征,如果输入参数featureType=0,则应用HAAR,该函数返回CvHaarFeatureParams的指针;如果featureType=1,则应用LBP,该函数返回CvLBPFeatureParams的指针;如果featureType=2,则应用HOG,该函数返回CvHOGFeatureParams的指针。
    static cv::Ptr<CvFeatureParams> create( int featureType );
    //表示样本特征的类别数,如果该值为0,则表示特征是数值的形式,对于HAAR和HOG,该值为0,对于LBP,该值被赋值为256
    int maxCatCount; // 0 in case of numerical features
    //表示一个特征所包含的特征成分的数量,HAAR和LBP为1,HOG为36,即HOG特征包含36(9×4)个特征成分
    int featSize; // 1 in case of simple features (HAAR, LBP) and N_BINS(9)*N_CELLS(4) in case of Dalal's HOG features
};

CvHaarEvaluatorCvLBPEvaluatorCvHOGEvaluator分别表示HAAR状特征、LBP特征和HOG特征的计算评估特征值的类,它们都继承于CvFeatureEvaluator类:

class CvFeatureEvaluator
{
public:
    virtual ~CvFeatureEvaluator() {}    //析构函数
    //初始化一些变量:featureParams、winSize、numFeatures、cls,另外还调用了generateFeatures函数,而CvFeatureEvaluator类的子类的init函数主要完成各自特征的初始化参数的任务
    virtual void init(const CvFeatureParams *_featureParams,
                      int _maxSampleCount, cv::Size _winSize );
    //确保样本图像img的尺寸正确,并且设置该图像的类别标签clsLabel,而CvFeatureEvaluator类的子类的setImage函数主要完成积分图像或梯度方向直方图的计算
    virtual void setImage(const cv::Mat& img, uchar clsLabel, int idx);
    //表示向xml文件写入一些内容
    virtual void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const = 0;
    //重载( )运算符,CvFeatureEvaluator类的子类CvHaarEvaluator和CvHOGEvaluator完成了第sampleIdx个样本图像的第featureIdx个特征的特征值的计算,而CvHOGEvaluator完成的是第sampleIdx个样本图像的第featureIdx个特征成分的方向直方图的计算
    virtual float operator()(int featureIdx, int sampleIdx) const = 0;
    //构建相应特征的特征值计算,即级联分类器具体使用哪种特征,如果输入参数type=0,则应用HAAR,该函数返回CvHaarEvaluator的指针;如果type=1,则应用LBP,该函数返回CvLBPEvaluator的指针;如果type=2,则应用HOG,该函数返回CvHOGEvaluator的指针。
    static cv::Ptr<CvFeatureEvaluator> create(int type);
    //得到numFeatures值
    int getNumFeatures() const { return numFeatures; }
    //得到CvFeatureParams:: maxCatCount值
    int getMaxCatCount() const { return featureParams->maxCatCount; }
    //得到CvFeatureParams:: featSize值
    int getFeatureSize() const { return featureParams->featSize; }
    //得到cls值
    const cv::Mat& getCls() const { return cls; }
    //得到矩阵cls中的第si个元素的值,即得到第si个样本的类别标签
    float getCls(int si) const { return cls.at<float>(si, 0); }
protected:
    //虚函数,执行子类的generateFeatures函数,产生HAAR、LBP或HOG的各自特征
    virtual void generateFeatures() = 0;

    int npos, nneg;    //分别表示正、负样本的数量
    int numFeatures;    //表示特征数量
    //表示正样本图像的尺寸大小,负样本图像的尺寸是根据正样本图像的尺寸进行剪切
    cv::Size winSize; 
    CvFeatureParams *featureParams;    //特征变量
    cv::Mat cls;    //表示样本的类别标签,即样本的响应值
};

HAARLBPHOG这三种特征的参数类和评估类中,最重要的是评估类中的setImage函数、generateFeatures函数和重载( )运算符,它们的作用分别是计算积分图像或梯度方向直方图、产生特征,以及计算特征值。下面我们就分别给出这三种特征的相关函数的解释。 


HAAR状特征:

void CvHaarEvaluator::setImage(const Mat& img, uchar clsLabel, int idx)
//img表示待处理的样本图像
//clsLabel表示img图像的类别标签,即img图像是正样本还是负样本
//idx表示img在所有样本图像的索引值
{
    //sum和tilted分别表示所有样本图像的积分图像和旋转积分图像,normfactor表示特征值的归一化因子,这三个变量在init函数中定义,这里再次确认这三个变量是否定义好
    CV_DbgAssert( !sum.empty() && !tilted.empty() && !normfactor.empty() );
    //调用父类的setImage函数,确定图像img尺寸大小是否正确,并赋值类别标签
    CvFeatureEvaluator::setImage( img, clsLabel, idx);
    //sum和titled包含的单一图像的积分图像和旋转积分图像都是以相量的形式存储的,在这里都需转换为矩阵的形式,以便于积分图像的计算
    Mat innSum(winSize.height + 1, winSize.width + 1, sum.type(), sum.ptr<int>((int)idx));
    Mat innTilted(winSize.height + 1, winSize.width + 1, tilted.type(), tilted.ptr<int>((int)idx));
    Mat innSqSum;
    //计算图像img的灰度积分图像innSum,灰度平方的积分图像innSqSum,旋转的积分图像innTilted
    integral(img, innSum, innSqSum, innTilted);
    //得到特征值的归一化因子,一个样本图像只有一个归一化因子
    normfactor.ptr<float>(0)[idx] = calcNormFactor( innSum, innSqSum );
}
void CvHaarEvaluator::generateFeatures()
{
    //得到HAAR状特征的模式,即HAAR状特征模板是BASIC、CORE还是ALL,该值由用户定义。BASIC为图1中的(a)、(b)、(e)、(i)和(n),CORE为BASIC模式再加上图1中的(f)、(j)和(m),ALL为图1中的全部模板
    int mode = ((const CvHaarFeatureParams*)((CvFeatureParams*)featureParams))->mode;
    //偏移量,就是积分图像的宽(在程序中,积分图像的宽和高都要比原图像的宽和高多1),用于计算图像中的某一点的像素从图像左上角开始扫描的位置,如坐标(x,y)在图像的位置是x+y×offset,这是因为积分图像是以相量的形式存储的,必须通过这种形式才能从相量中提取出积分图像中某一像素的积分值
    int offset = winSize.width + 1;
    //遍历样本图像的所有像素
    //x和y表示HAAR状特征模板在样本图像中左上角的坐标
    for( int x = 0; x < winSize.width; x++ )
    {
        for( int y = 0; y < winSize.height; y++ )
        {
            //得到以(x, y)为左上角坐标的所有不同大小、不同类型的HAAR状特征模板
            for( int dx = 1; dx <= winSize.width; dx++ )
            {
                for( int dy = 1; dy <= winSize.height; dy++ )
                {
                    // haar_x2
                    //图1(a)
                    //判断HAAR状特征矩形模板是否超出了样本图像的边界
                    if ( (x+dx*2 <= winSize.width) && (y+dy <= winSize.height) )
                    {
                        //得到一个HAAR状特征模板,把它放入表示特征模板变量的features向量队列中,Feature是CvHaarEvaluator类中的一个类,该类在后面有详细介绍
                        features.push_back( Feature( offset, false,
                            x,    y, dx*2, dy, -1,
                            x+dx, y, dx  , dy, +2 ) );
                    }
                    // haar_y2
                    //图1(b)
                    if ( (x+dx <= winSize.width) && (y+dy*2 <= winSize.height) )
                    {
                        features.push_back( Feature( offset, false,
                            x,    y, dx, dy*2, -1,
                            x, y+dy, dx, dy,   +2 ) );
                    }
                    // haar_x3
                    //图1(e)
                    if ( (x+dx*3 <= winSize.width) && (y+dy <= winSize.height) )
                    {
                        features.push_back( Feature( offset, false,
                            x,    y, dx*3, dy, -1,
                            x+dx, y, dx  , dy, +3 ) );
                    }
                    // haar_y3
                    //图1(i)
                    if ( (x+dx <= winSize.width) && (y+dy*3 <= winSize.height) )
                    {
                        features.push_back( Feature( offset, false,
                            x, y,    dx, dy*3, -1,
                            x, y+dy, dx, dy,   +3 ) );
                    }
                    if( mode != CvHaarFeatureParams::BASIC )
                    {
                        // haar_x4
                        //图1(f)
                        if ( (x+dx*4 <= winSize.width) && (y+dy <= winSize.height) )
                        {
                            features.push_back( Feature( offset, false,
                                x,    y, dx*4, dy, -1,
                                x+dx, y, dx*2, dy, +2 ) );
                        }
                        // haar_y4
                        //图1(j)
                        if ( (x+dx <= winSize.width ) && (y+dy*4 <= winSize.height) )
                        {
                            features.push_back( Feature( offset, false,
                                x, y,    dx, dy*4, -1,
                                x, y+dy, dx, dy*2, +2 ) );
                        }
                    }
                    // x2_y2
                    //图1(n)
                    if ( (x+dx*2 <= winSize.width) && (y+dy*2 <= winSize.height) )
                    {
                        features.push_back( Feature( offset, false,
                            x,    y,    dx*2, dy*2, -1,
                            x,    y,    dx,   dy,   +2,
                            x+dx, y+dy, dx,   dy,   +2 ) );
                    }
                    if (mode != CvHaarFeatureParams::BASIC)
                    {
                        //图1(m)
                        if ( (x+dx*3 <= winSize.width) && (y+dy*3 <= winSize.height) )
                        {
                            features.push_back( Feature( offset, false,
                                x   , y   , dx*3, dy*3, -1,
                                x+dx, y+dy, dx  , dy  , +9) );
                        }
                    }
                    if (mode == CvHaarFeatureParams::ALL)
                    {
                        // tilted haar_x2
                        //图1(c)
                        if ( (x+2*dx <= winSize.width) && (y+2*dx+dy <= winSize.height) && (x-dy>= 0) )
                        {
                            features.push_back( Feature( offset, true,
                                x, y, dx*2, dy, -1,
                                x, y, dx,   dy, +2 ) );
                        }
                        // tilted haar_y2
                        //图1(d)
                        if ( (x+dx <= winSize.width) && (y+dx+2*dy <= winSize.height) && (x-2*dy>= 0) )
                        {
                            features.push_back( Feature( offset, true,
                                x
opencv是一个开源的计算机视觉库,opencv2.4.9是其中的一个版本。在opencv2.4.9中,有一个模块叫做stitching,用于图像拼接。 图像拼接是将多张图像按照一定的顺序和方式进行合并,形成一张更大视野覆盖范围的图像。拼接的过程需要解决图像间的重叠区域匹配、图像变换与叠加等问题。 在opencv2.4.9的stitching模块中,主要有以下几个重要的类: 1. Stitcher类:拼接器类,用于执行拼接的主要操作。它提供了一系列的方法,如设置拼接的模式、添加要拼接的图像等。 2. FeaturesFinder类:特征点检测类,用于在图像中寻找特征点。该类利用SIFT、SURF等算法来检测图像中的关键点,以便进行匹配。 3. FeaturesMatcher类:特征点匹配类,用于对图像中的特征点进行匹配。该类使用KNN算法进行特征点的匹配,并利用RANSAC算法进一步筛选特征点,剔除误匹配。 4. Estimator类:变换估计类,用于估计图像间的变换参数。该类可以通过特征点的对应关系,计算图像间的旋转矩阵、平移矩阵等变换参数。 5. Blender类:图像融合类,用于将拼接后的图像进行融合。该类可以进行多种融合方式,如线性融合、多频融合等。 通过以上的类和方法,opencv2.4.9的stitching模块能够完成图像拼接的过程。整个过程包括特征点检测、特征点匹配、变换参数估计和图像融合等步骤。 需要指出的是,本文只是对opencv2.4.9的stitching模块进行了初步的介绍,具体的源码分析需要深入研究。整个源码工程庞大,包含很多细节和算法,需要对计算机视觉和图像处理有较深入的理解才能进行分析和改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值