LBP算法的研究及其实现

原文:http://blog.csdn.net/dujian996099665/article/details/8886576


一,原始LBP算法

LBP的基本思想是对图像的像素和它局部周围像素进行对比后的结果进行求和。把这个像素作为中心,对相邻像素进行阈值比较。如果中心像素的亮度大于等于他的相邻像素,把他标记为1,否则标记为0。你会用二进制数字来表示每个像素,比如11001111。因此,由于周围相邻8个像素,你最终可能获取2^8个可能组合,被称为局部二值模式,有时被称为LBP码。第一个在文献中描述的LBP算子实际使用的是3*3的邻域

33

一个更加正式的LBP操作可以被定义为

                     34

其中35 是中心像素,亮度是36 ;而 37则是相邻像素的亮度。s是一个符号函数:

        38

这种描述方法使得你可以很好的捕捉到图像中的细节。实际上,研究者们可以用它在纹理分类上得到最先进的水平。正如刚才描述的方法被提出后,固定的近邻区域对于尺度变化的编码失效。所以,使用一个变量的扩展方法,在文献[AHP04]中有描述。主意是使用可变半径的圆对近邻像素进行编码,这样可以捕捉到如下的近邻:

            39

对一个给定的点40   ,他的近邻点 41 可以由如下计算:


        42

其中,R是圆的半径,而P是样本点的个数。

这个操作是对原始LBP算子的扩展,所以有时被称为扩展LBP(又称为圆形LBP)。如果一个在圆上的点不在图像坐标上,我们使用他的内插点。计算机科学有一堆聪明的插值方法,而OpenCV使用双线性插值。


         43


二.原始LBP算法的实现

附上代码:

// LBP.cpp : 定义控制台应用程序的入口点。  
//  
  
  
/*********************************************************************** 
 * OpenCV 2.4.4 测试例程 
 * 杜健健 提供 
 ***********************************************************************/  
  
#include "stdafx.h"  
#include <opencv2/opencv.hpp>  
#include  <cv.h>   
#include  <highgui.h>  
#include  <cxcore.h>  
   
using namespace std;  
using namespace cv;  
   
//原始的LBP算法  
//使用模板参数  
  
template <typename _Tp> static  
void olbp_(InputArray _src, OutputArray _dst) {  
    // get matrices  
    Mat src = _src.getMat();  
    // allocate memory for result  
    _dst.create(src.rows-2, src.cols-2, CV_8UC1);  
    Mat dst = _dst.getMat();  
    // zero the result matrix  
    dst.setTo(0);  
  
    cout<<"rows "<<src.rows<<" cols "<<src.cols<<endl;  
    cout<<"channels "<<src.channels();  
    getchar();  
    // calculate patterns  
    for(int i=1;i<src.rows-1;i++) {  
        cout<<endl;  
        for(int j=1;j<src.cols-1;j++) {  
              
            _Tp center = src.at<_Tp>(i,j);  
            //cout<<"center"<<(int)center<<"  ";  
            unsigned char code = 0;  
            code |= (src.at<_Tp>(i-1,j-1) >= center) << 7;  
            code |= (src.at<_Tp>(i-1,j  ) >= center) << 6;  
            code |= (src.at<_Tp>(i-1,j+1) >= center) << 5;  
            code |= (src.at<_Tp>(i  ,j+1) >= center) << 4;  
            code |= (src.at<_Tp>(i+1,j+1) >= center) << 3;  
            code |= (src.at<_Tp>(i+1,j  ) >= center) << 2;  
            code |= (src.at<_Tp>(i+1,j-1) >= center) << 1;  
            code |= (src.at<_Tp>(i  ,j-1) >= center) << 0;  
  
            dst.at<unsigned char>(i-1,j-1) = code;  
            //cout<<(int)code<<" ";  
            //cout<<(int)code<<endl;  
        }  
    }  
}  
  
//基于旧版本的opencv的LBP算法opencv1.0  
void LBP (IplImage *src,IplImage *dst)  
{  
    int tmp[8]={0};  
    CvScalar s;  
  
    IplImage * temp = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U,1);  
    uchar *data=(uchar*)src->imageData;  
    int step=src->widthStep;  
  
    cout<<"step"<<step<<endl;  
  
    for (int i=1;i<src->height-1;i++)  
      for(int j=1;j<src->width-1;j++)  
      {  
          int sum=0;  
          if(data[(i-1)*step+j-1]>data[i*step+j])  
            tmp[0]=1;  
          else  
            tmp[0]=0;  
          if(data[i*step+(j-1)]>data[i*step+j])  
            tmp[1]=1;  
          else  
            tmp[1]=0;  
          if(data[(i+1)*step+(j-1)]>data[i*step+j])  
            tmp[2]=1;  
          else  
            tmp[2]=0;  
          if (data[(i+1)*step+j]>data[i*step+j])  
            tmp[3]=1;  
      else  
            tmp[3]=0;  
          if (data[(i+1)*step+(j+1)]>data[i*step+j])  
            tmp[4]=1;  
          else  
            tmp[4]=0;  
          if(data[i*step+(j+1)]>data[i*step+j])  
            tmp[5]=1;  
          else  
            tmp[5]=0;  
          if(data[(i-1)*step+(j+1)]>data[i*step+j])  
            tmp[6]=1;  
          else  
            tmp[6]=0;  
          if(data[(i-1)*step+j]>data[i*step+j])  
            tmp[7]=1;  
          else  
            tmp[7]=0;     
          //计算LBP编码  
            s.val[0]=(tmp[0]*1+tmp[1]*2+tmp[2]*4+tmp[3]*8+tmp[4]*16+tmp[5]*32+tmp[6]*64+tmp[7]*128);  
          
        cvSet2D(dst,i,j,s);写入LBP图像  
      }  
}  
  
  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
    //IplImage* face = cvLoadImage("D://input//yalefaces//01//s1.bmp",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);  
    IplImage* face = cvLoadImage("D://input//lena.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);  
    //IplImage* lbp_face =   cvCreateImage(cvGetSize(face), IPL_DEPTH_8U,1);  
  
    IplImage* Gray_face = cvCreateImage( cvSize( face->width,face->height ), face->depth, 1);//先分配图像空间  
    cvCvtColor(face, Gray_face ,CV_BGR2GRAY);//把载入图像转换为灰度图  
    IplImage* lbp_face =   cvCreateImage(cvGetSize(Gray_face), IPL_DEPTH_8U,1);//先分配图像空间  
  
    cvNamedWindow("Gray Image",1);  
    cvShowImage("Gray Image",Gray_face);  
  
    //Mat face2 = imread("D://input//buti.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);  
    Mat face2 = imread("D://input//yalefaces//01//s1.bmp",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);  
    //Mat Gray_face2 = Mat::zeros(face2.size(),IPL_DEPTH_8U,1);  
  
    //cvCvtColor(face2,Gray_face2,CV_BGR2RAY);  
    Mat lbp_face2 = Mat::zeros(face2.size(),face2.type()) ;  
    //Mat::copyTo(lbp_face,face);  
  
  
    //显示原始的输入图像  
    cvNamedWindow("Src Image",CV_WINDOW_AUTOSIZE);  
    cvShowImage("Src Image",face);  
    //imshow("Src Image",face);  
  
    //计算输入图像的LBP纹理特征  
    LBP(Gray_face,lbp_face);  
    //olbp_<uchar>((Mat)face,(Mat)lbp_face);//有问题的调用  
    olbp_<uchar>(face2,lbp_face2);  
  
      
    //显示第一幅图像的LBP纹理特征图  
    cvNamedWindow("LBP Image",CV_WINDOW_AUTOSIZE);  
    cvShowImage("LBP Image",lbp_face);  
    //显示第二幅图 的LBP纹理特征图-一张yaleface人脸库中的人脸LBP特征图  
    namedWindow("LBP Image2",1);  
    imshow("LBP Image2",lbp_face2);  
    waitKey();  
  
    //cvReleaseImage(&face);  
    cvDestroyWindow("Src Image");  
   
    return 0;  
  
}  

三.示例结果,LBP纹理特征

原始图像lena.jpg

变换成灰度图后:


提取图片的LBP特征:



提取人脸图像的LBP特征;



四.注意事项

1 两个函数都只能对灰度图像就行处理,所以,在使用这两个函数时,必须先把原始图像转换成灰度图像方可

2 关于早期只显示图像1/3或者1/4区域的LBP纹理特征问题的解决方法:

这个是因为你的输入图像不是灰度图的缘故,需要把彩色图,多通道的图像转换成单通道的图像,再作为参数传入函数,才能得到完整图像的LBP纹理特征。

3 载入灰度图像的方法:

把函数cvLoadImage()函数的第二个参数,还有imread() 的第二个参数设置成:CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR



五、参考


opencv2.4.4中的facerec文档

http://blog.csdn.net/guoming0000/article/details/8022197

等等。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值