原始LBP纹理特征提取方法介绍以及代码实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_22562949/article/details/45966009

     在模式识别数字图像处理领域,LBP指局部二值模式,即Local Binary Patterns。最初功能为辅助图像局部对比度,后来提升为一种有效的纹理描述算子,度量和提取图像局部的纹理信息,对光照具有不变性。该描述方法还用于质量检测,人脸图像分析等领域,取得了很好的效果。

    本文详细分析和研究了LBP算法的原理和实现方法。编程的时候采用c++语言,成功实现了提取视频中物体局部纹理特征的功能,并且显示出了很好的处理效果。

1 算法描述

1.1 LBP算法的介绍

LBP(Local Binary Pattern,局部二值模式)是一种用来描述图像局部纹理特征的算子;显然,它的作用是进行特征提取,而且提取的特征是图像的纹理特征,并且是局部的纹理特征; 

芬兰Oulu大学的T.Ojala等人于1996年提出这个算子用来分析图像纹理特征,并且描述了它在纹理分类中的强区分能力。LBP算子定义为一种灰度尺度不变的纹理算子,是从局部邻域纹理的普通定义得来的。 基本思想是:用中心像素的灰度值作为阈值,与它的邻域相比较得到的二进制码来表述局部纹理特征。 在纹理分析方面,LBP算子是最好的纹理描述符之一,它的主要优点有以下几点:通过它的定义可知,LBP算子的灰度尺度不随任何单一变换而变化,因此灰度尺度的鲁棒性好,也就是光照条件下的鲁棒性好;计算速度快。由于它可以通过在小邻域内进行比较操作得到,使得在复杂的实时条件下分析图像成为可能;由于LBP算子是一种无参数(Non-Parametric)的方法,在应用过程中不需要对它的分布进行预先假设。    

    LBP算子是一种灰度范围内的纹理度量,是从一种纹理局部近邻定义中衍生出来,它利用结构法思想分析固定窗口特征,再利用统计法作整体的特征提取。LBP算法一般定义为3×3的窗口,以窗口中心点的灰度值为阈值对窗口内其它像素作二值化处理,然后根据像素不同位置进行加权求和得到该窗口的LBP值。

    LBP算子刚提出来的时候,基本的概念就是图像纹理中某个指定的中心像素

点(gc)及其周围紧邻的8个像素点(g0-g7,)所组成的局部区域。

    基本方法里所用的是经过处理后所得到的灰度图像,每一个像素点的灰度值

是0~255中的一个值。当指定了某一个像素点作为中心像素点(g0)之后(此

时暂不考虑图像边界上的像素点),其周围的8个像素点(g0一g7)的灰度值即可随之确定下来。我们以中心像素点(go)的灰度值作为阈(thresholded value),将gc周边相邻的8个像素点的灰度值与阈值进行比较,如果某相邻像素点的灰度值大于或等于该阈值,则令该像素点的赋值为1;如果相邻像素点的灰度值小于该阈值,则令该像素点的赋值为0。这样,在顺次将周围像素点的灰度值与阈值进行比较之后,就可以得到一个局部二进制的模式(Local Binary Pattern)。接下来,从左上角的第一个像素点(go)开始,将权值2的n次方(n=0,1⋯.7)按照顺时针次序依次赋予周围各个像素点,并与该像素点经过阈值化之后所赋的二进制值相乘。最后,当每一个像素点都依次进行了上述运算之后,将所有8个像素点运算所得的结果相加,即为该中心像素点(gc)的LBP值。现举例说明LBP算子基本方法的计算方式。

    比如样本的中心像素的灰度值为83,以之作为阈值,同其周边8个像素点的灰度值依次进行比较,此过程称为阈值化(thresh01ding)。在进行了阈值化之后,我们可以得到一个局部二进制的模式——01111100;与此同时,将权值2的n次方(n=O,l⋯.7从g。点开始按照顺时针顺序依次赋予周边的8个像素点,这些点的赋值依次是g0=l28,g1=64,g2=32,g3=16,g4=8,g5=4,g6=2,g7=1。此后,把各像素点阈值化之后所得的二进制值和所赋权值一一对应相乘——0×128,1×64,1×32,1×16,l×8,1×4,0×2,0×1;最后将所得结果相加一64+32+16+8+4=124,即为中心像素点(gc)的LBP值。

目前,LBP局部纹理提取算子,已经成功应用在指纹识别、字符识别、人脸识别、车牌识别等领域。

1.2 LBP算法的实现步骤

  (1)首先进行灰度化的处理,需要将彩色的三通道视频转化为单通道的灰度级视频,然后显示灰度视频;

  (2)另外,原始视频数据可能存在噪声,采用高斯滤波的方法对灰度化后的视频进行平滑处理来去除可能存在的噪点,然后显示高斯滤波处理过的视频。

  (3)对于高斯滤波处理过的视频中的每一帧灰度级图像中的一个像素,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该像素点的位置被标记为1,否则为0。这样,3*3邻域内的8个点经比较可产生8位二进制数,即得到该窗口中心像素点的LBP值;

  (4)将得到的窗口中心像素点的LBP值赋给该中心点,作为该中心点的像素值;

  (5)显示提取了视频中物体局部纹理特征效果的视频;     


2 实验代码

/*#include "highgui.h"
#include "cv.h"
//函数声明
void RGB_Gray_Typical(IplImage *Image1, IplImage *Image2);
void GaussFliter(IplImage *Image3,IplImage *Image4);
void LBPAlgorithm(IplImage *Image5,IplImage *Image6);
char  *Array_gray;
char  *Array_Gauss;
char  *Array_LBP ;
//主函数
void main()
{
//确定要读入的AVI视频
CvCapture *capture = cvCreateFileCapture("E:\\新建文件夹\\行车视频.avi");
//将视频文件的下一帧加载到内存
IplImage *tempFrame= cvQueryFrame(capture);
IplImage *grayImage,*gaussImage,*lbpImage;
//创建头并分配数据,取与这一帧图大小一样的尺寸,数据类型为无符号8位整型,单通道
grayImage = cvCreateImage(cvSize(tempFrame->width, tempFrame->height),8,1);
    gaussImage=cvCreateImage(cvSize(tempFrame->width,tempFrame->height),8,1);
lbpImage=cvCreateImage(cvSize(tempFrame->width,tempFrame->height),8,1);
while (IplImage *tempFrame = cvQueryFrame(capture))
{
cvShowImage("原始视频",tempFrame); //播放原视频
RGB_Gray_Typical(tempFrame, grayImage);//得到灰度图
        GaussFliter(grayImage,gaussImage); 
        LBPAlgorithm(gaussImage,lbpImage );
cvWaitKey(10);
}
cvReleaseCapture(&capture);
cvReleaseImage(&grayImage);
cvReleaseImage(&gaussImage);
cvReleaseImage(&lbpImage);
cvDestroyWindow("原始视频");
cvDestroyWindow("灰度视频");
cvDestroyWindow("高斯视频");
cvDestroyWindow("LBP视频");
}


//传统方法将彩色图转换成灰度图
void RGB_Gray_Typical(IplImage *Image1, IplImage *Image2)
{    
    //申请图像的高度乘以宽度个char类型的内存单元,
      并把这块内存单元的首地址赋给一个char类型的指针Array_gray
Array_gray = new char[Image1->height *Image1->width];
for(int j=0; j<Image1->height; j++)  
    for(int i=0; i<Image1->width; i++)  
    {    
//int liv_size = j * img->width + i;//测试循环多少次    
uchar *data=( uchar *)(Image1->imageData );
   int step=Image1->widthStep;
//得到某个像素点bgr三个通道的像素值
        double B = (double)data[j*step + i*3+0];     //B分量  
        double G= (double)data[j*step + i*3 + 1]; //G分量  
        double R = (double)data[j*step + i*3 + 2]; //R分量 
//用灰度公式,计算出这个像素点转换后的灰度值GRAY
double GRAY = (double)(0.299 * R+ 0.587 * G + 0.114 * B+0.5);  
//把GRAY的值赋给它对应的内存单元
long int index= j*Image1->width + i;
    Array_gray[index] = GRAY;
//cout<<"liv_size = "<<liv_size<<endl;
}
   //让指针 Array_gray指向Image2所对应的数据块
   Image2->imageData = Array_gray; 
   cvShowImage("灰度视频",Image2);

}


 


//原始视频数据可能存在噪声,采用高斯滤波以达到滤除噪声的目的
//高斯滤波
void GaussFliter(IplImage *Image3,IplImage *Image4)
{
//定义一个数组存放高斯模板
int temp[9];
temp[0] = 1;
temp[1] = 2;
temp[2] = 1;
    temp[3] = 2;
    temp[4] = 4;
    temp[5] = 2;
temp[6] = 1;
temp[7] = 2;
temp[8] = 1;
//申请图像的高度乘以宽度个char类型的内存单元,
      并把这块内存单元的首地址赋给一个char类型的指针Array_Gauss
Array_Gauss = new  char[Image3->height *Image3->width];
uchar *data0=(uchar*)(Image3->imageData );
int step0=Image3->widthStep;
for(int j= 0; j < Image3->height; j++)
  {
for(int  i= 0; i <Image3->width; i++)
{
 double gauss=
 temp[0]*data0[(j-1)*step0+i-1]+ temp[1]*data0[(j-1)*step0+i]+ temp[2]*data0[(j-1)*step0+i+1]
 +temp[3]*data0[j*step0+i-1]+temp[4]*data0[j*step0+i]+temp[5]*data0[j*step0+i+1]
 +temp[6]*data0[(j+1)*step0+i-1]+temp[7]*data0[(j+1)*step0+i]+temp[8]*data0[(j+1)*step0+i+1];
double gauss1=gauss/16;
    long int index0= j*Image3->width + i;
Array_Gauss[index0]=gauss1;
}
}
Image4->imageData = Array_Gauss; 
cvShowImage("高斯视频",Image4);
//IplImage  *lbpImage = cvCreateImage(cvSize(Image3->width, Image3->height), IPL_DEPTH_8U, 1);
//调用下面定义的LBPAlgorithm函数
//LBPAlgorithm(Image4,lbpImage );
     delete Array_gray;
}


/*---------------------LBP算子-----------------------*/
/*
void LBPAlgorithm(IplImage *Image5,IplImage *Image6)
{
int temp[8];
//申请图像的高度乘以宽度个char类型的内存单元,
      并把这块内存单元的首地址赋给一个char类型的指针Array_LBP
    Array_LBP = new  char[Image5->height *Image5->width];
uchar *data1=(uchar*)(Image5->imageData );
int step1=Image5->widthStep;
//cout<<"step1"<<" "<<step1<<endl;


提取原图像中除去第一行,最后一行,第一列,最后一列的所有像素值,
    因为这部分LBP像素值不准确


for(int j=2; j<Image5->height-1; j++)  
    for(int i=2; i<Image5->width-1; i++)  
{
  //LBP算法的思想:
  在像素3x3邻域内的,以邻域中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,
  若周围像素值大于中心像素值,则该像素点的位置被标记为1,否则为0


if(data1[(j-1)*step1+i-1]>data1[j*step1+i])
temp[0]=1;
else
temp[0]=0;
        if(data1[(j-1)*step1+i]>data1[j*step1+i])
temp[1]=1;
else
temp[1]=0;
       if(data1[(j-1)*step1+i+1]>data1[j*step1+i])
temp[2]=1;
else
temp[2]=0;
   if(data1[j*step1+i+1]>data1[j*step1+i])
temp[3]=1;
else
temp[3]=0;
if(data1[(j+1)*step1+i+1]>data1[j*step1+i])
temp[4]=1;
else
temp[4]=0;
if(data1[(j+1)*step1+i]>data1[j*step1+i])
temp[5]=1;
else
temp[5]=0;
if(data1[(j+1)*step1+i-1]>data1[j*step1+i])
temp[6]=1;
else
temp[6]=0;
if(data1[j*step1+i-1]>data1[j*step1+i])
temp[7]=1;
else
temp[7]=0;
   //这样,3x3邻域内的8个点经比较可产生8位二进制数,
       即得到该邻域中心像素点的LBP值center_lbp,并用这个值来反映该区域的纹理信息


       int center_lbp=temp[0]*128+temp[1]*64+temp[2]*32+temp[3]*16
                          +temp[4]*8+temp[5]*4+temp[6]*2+temp[7]*1;
   long int index1= j*Image5->width + i;
//把center_lbp的值赋给它对应的内存单元
Array_LBP[index1]=center_lbp;
}
    //让指针Array_LBP指向Image4所对应数据块的首地址
Image6->imageData = Array_LBP;
cvShowImage("LBP视频",Image6);
    delete Array_Gauss;
delete Array_LBP;
}




猜你喜欢

转载自blog.csdn.net/qq_22562949/article/details/45966009