机器学习 之 LBP特征

综述:: 
LBP特征:Local Binary Pattern,局部二值模式特征,是一种用来描述图像局部纹理特征的算子。LBP特征算子计算简单、效果较好,数据量小,因此LBP特征在计算机视觉的许多领域都得到了广泛的应用,LBP特征比较多用于目标检测中。LBP计算出的特征具有灰度不变性和旋转不变性等显著优点,例如对光照不敏感。

LBP的基本算子

原始的LBP算子定义为在3*3的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该像素 点的位置被标记为1,否则为0。这样,3*3邻域内的8个点经过比较可产生8个0或1,将这8个0或1作为二进制数按照一定的次序排列形成一个二进制数字,这个二进制数字就是中心像素的LBP值。LBP值共有 种可能,因此LBP值有256种。像素之间的比较反映的是一种像素之间的差异关系,能够很好反映图像局部纹理这种特征。 
这里写图片描述

LBP特征的改进

http://blog.csdn.net/pi9nc/article/details/26678691 
http://blog.csdn.net/quincuntial/article/details/50541815 
http://www.open-open.com/lib/view/open1440832074794.html 
这三篇博客对LBP特征的改进版本均有很好的描述,我在这里做个总结:

圆形LBP算子:

所谓圆形LBP算子:如果要计算某个像素的点LBP特征,以这个像素点为中心,以一个任意大小半径R画一个圆,将落在圆内的像素与中心点像素比较得到LBP算子。如下图: 
这里写图片描述

这样做的好处是:它能够适应一定程序上纹理的尺度变化,并达到灰度和旋 转不变性的要求。

LBP旋转不变模式

首先讲下为什么LBP特征会有旋转可变这个情况,就是以上面3x3区域的像素值为例: 
这里写图片描述
逆时针旋转一格后得到的LBP值与原始不同。 
那么旋转不变模式是什么呢,就是旋转圆形邻域一周得到一系列初始定义的 LBP值,取其最小值作为该邻域的 LBP 值,这样无论怎样旋转,该点LBP值始终不变。如下图所示: 
这里写图片描述

LBP等价模式

具体可见上面三个博客里的介绍,总的来说: 
原来是LBP的每个位都作为该特征的决定项,例如01100100与01101100被认为是两个不同的特征值,采用LBP的等价模式后,只认为0到1的跳变与1到0的跳变为一个特征决定项,那么这样说的话,01100100中0~1有2个,1~0有2个,而01101100中0~1有2个,1~0也是有2个,我们认为它是同一个特征,这样LBP特征的种类就大减少了。

opencv中LBP特征实现

opencv中LBP特征的实现原理:将一个图像窗口画分成9个格子,统计每个格子的像素和,然后把周围8个像素和与中间那个格子的像素和比较,大于的取1,小于的取0,按顺序组成一个8位的LBP特征值。

opencv中主要是Lbpfeatures.cpp和Lbpfeatures.h两个文件来实现计算LBP特征的源码。

Lbpfeatures.h源码注释:

#ifndef _OPENCV_LBPFEATURES_H_
#define _OPENCV_LBPFEATURES_H_

#include "traincascade_features.h"

#define LBPF_NAME "lbpFeatureParams"
struct CvLBPFeatureParams : CvFeatureParams
{
    CvLBPFeatureParams();

};

/*LBP特征类定义*/
class CvLBPEvaluator : public CvFeatureEvaluator
{
public:
    virtual ~CvLBPEvaluator() {}
    virtual void init(const CvFeatureParams *_featureParams,
        int _maxSampleCount, Size _winSize );
    virtual void setImage(const Mat& img, uchar clsLabel, int idx);
    virtual float operator()(int featureIdx, int sampleIdx) const
    { return (float)features[featureIdx].calc( sum, sampleIdx); }
    virtual void writeFeatures( FileStorage &fs, const Mat& featureMap ) const;
protected:
    virtual void generateFeatures();

    class Feature
    {
    public:
        Feature();
        Feature( int offset, int x, int y, int _block_w, int _block_h  ); 
        uchar calc( const Mat& _sum, size_t y ) const;
        void write( FileStorage &fs ) const;

        Rect rect;
        int p[16];
    };
    vector<Feature> features;

    Mat sum;
};

/*将9个窗口中周围8个窗口的像素和与中间窗口的像素和比较得到LBP特征值*/
inline uchar CvLBPEvaluator::Feature::calc(const Mat &_sum, size_t y) const
{
    const int* sum = _sum.ptr<int>((int)y);
    int cval = sum[p[5]] - sum[p[6]] - sum[p[9]] + sum[p[10]];

    return (uchar)((sum[p[0]] - sum[p[1]] - sum[p[4]] + sum[p[5]] >= cval ? 128 : 0) |   // 0
        (sum[p[1]] - sum[p[2]] - sum[p[5]] + sum[p[6]] >= cval ? 64 : 0) |    // 1
        (sum[p[2]] - sum[p[3]] - sum[p[6]] + sum[p[7]] >= cval ? 32 : 0) |    // 2
        (sum[p[6]] - sum[p[7]] - sum[p[10]] + sum[p[11]] >= cval ? 16 : 0) |  // 5
        (sum[p[10]] - sum[p[11]] - sum[p[14]] + sum[p[15]] >= cval ? 8 : 0) | // 8
        (sum[p[9]] - sum[p[10]] - sum[p[13]] + sum[p[14]] >= cval ? 4 : 0) |  // 7
        (sum[p[8]] - sum[p[9]] - sum[p[12]] + sum[p[13]] >= cval ? 2 : 0) |   // 6
        (sum[p[4]] - sum[p[5]] - sum[p[8]] + sum[p[9]] >= cval ? 1 : 0));     // 3
}

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

Lbpfeatures.cpp源码注释:

扫描二维码关注公众号,回复: 1470239 查看本文章
#include "lbpfeatures.h"
#include "cascadeclassifier.h"

CvLBPFeatureParams::CvLBPFeatureParams()
{
    maxCatCount = 256;
    name = LBPF_NAME;
}

/*Lbp特征的对象初始化*/
void CvLBPEvaluator::init(const CvFeatureParams *_featureParams, int _maxSampleCount, Size _winSize)
{
    CV_Assert( _maxSampleCount > 0);
    /*分配积分图内存*/
    sum.create((int)_maxSampleCount, (_winSize.width + 1) * (_winSize.height + 1), CV_32SC1);
    /*调用父类初始化函数*/
    CvFeatureEvaluator::init( _featureParams, _maxSampleCount, _winSize );
}

/*设置图像宽高,并计算积分图像*/
void CvLBPEvaluator::setImage(const Mat &img, uchar clsLabel, int idx)
{
    CV_DbgAssert( !sum.empty() );
    CvFeatureEvaluator::setImage( img, clsLabel, idx );
    Mat innSum(winSize.height + 1, winSize.width + 1, sum.type(), sum.ptr<int>((int)idx));
    integral( img, innSum );
}

/*将特征值写到文件中*/
void CvLBPEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
{
    _writeFeatures( features, fs, featureMap );
}

/*计算窗口内LBP特征:将窗口内图像区域分成9个cell,
 计算中间那个cell与其他8个cell的像素值和的大小关系,以实现LBP特征计算*/
void CvLBPEvaluator::generateFeatures()
{
    int offset = winSize.width + 1;
    for( int x = 0; x < winSize.width; x++ )
        for( int y = 0; y < winSize.height; y++ )
            for( int w = 1; w <= winSize.width / 3; w++ )
                for( int h = 1; h <= winSize.height / 3; h++ )
                    if ( (x+3*w <= winSize.width) && (y+3*h <= winSize.height) )
                        features.push_back( Feature(offset, x, y, w, h ) );
    numFeatures = (int)features.size();
}

/*初始化特征的窗口坐标:Feature类构造函数*/
CvLBPEvaluator::Feature::Feature()
{
    rect = cvRect(0, 0, 0, 0);
}

/*给特征窗口点赋坐标值:Feature类构造函数*/
CvLBPEvaluator::Feature::Feature( int offset, int x, int y, int _blockWidth, int _blockHeight )
{
    Rect tr = rect = cvRect(x, y, _blockWidth, _blockHeight);
    CV_SUM_OFFSETS( p[0], p[1], p[4], p[5], tr, offset )
    tr.x += 2*rect.width;
    CV_SUM_OFFSETS( p[2], p[3], p[6], p[7], tr, offset )
    tr.y +=2*rect.height;
    CV_SUM_OFFSETS( p[10], p[11], p[14], p[15], tr, offset )
    tr.x -= 2*rect.width;
    CV_SUM_OFFSETS( p[8], p[9], p[12], p[13], tr, offset )
}

/*将特征坐标写到文件*/
void CvLBPEvaluator::Feature::write(FileStorage &fs) const
{
    fs << CC_RECT << "[:" << rect.x << rect.y << rect.width << rect.height << "]";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lanxueCC/article/details/54016304

猜你喜欢

转载自blog.csdn.net/haoji007/article/details/80299182