机器学习 之 LBP特征
来源:互联网 发布:fiiish旅行数据 编辑:程序博客网 时间:2024/05/20 05:06
综述::
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 << "]";}
- 机器学习 之 LBP特征
- 机器学习 之 LBP特征
- 图像特征学习之LBP特征
- 机器学习实战——LBP特征提取
- 特征提取之LBP
- 图像特征之LBP
- LBP特征学习及实现
- LBP特征学习及实现
- 特征描述之LBP算子
- 目标检测之LBP特征
- 机器学习 特征工程之特征选择
- 机器学习 特征工程之特征选择
- 机器学习之特征工程-特征选择
- 机器学习之特征选择
- 机器学习之特征工程
- 机器学习之特征工程
- 机器学习 之 Haar特征
- 机器学习之 特征选择
- android 主线程和子线程之间的消息传递
- 通过configSource提高web.config配置灵活性
- EventBus使用详解-2-用RxJava实现事件总线(Event Bus)
- 微信小程序开发之录音机 音频播放 动画 (真机可用)
- MFC主窗口可拖入文件
- 机器学习 之 LBP特征
- android网络编程之HttpUrlConnection的讲解--POST请求
- 快速开发Android购物车项目
- C++学习---类的继承
- 结构体空间以及结构体里面指针的空间
- Python 类中方法的内部变量,命名加'self.'变成 self.xxx 和不加直接 xxx 的区别
- linux kernel 一些比较好的网站
- sklearn.neighbors.KNeighborsClassifier源码笔记
- typedef与#define