机器学习 之 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

Lbpfeatures.cpp源码注释:

#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 << "]";
}
  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值