opencv学习之(三)-LBP算法的研究及其实现

来源:互联网 发布:python实现svm smo 编辑:程序博客网 时间:2024/05/17 01:00

一,原始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> staticvoid 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.0void 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;  elsetmp[0]=0;  if(data[i*step+(j-1)]>data[i*step+j])tmp[1]=1;  elsetmp[1]=0;  if(data[(i+1)*step+(j-1)]>data[i*step+j])tmp[2]=1;  elsetmp[2]=0;  if (data[(i+1)*step+j]>data[i*step+j])tmp[3]=1;  elsetmp[3]=0;  if (data[(i+1)*step+(j+1)]>data[i*step+j])tmp[4]=1;  elsetmp[4]=0;  if(data[i*step+(j+1)]>data[i*step+j])tmp[5]=1;  elsetmp[5]=0;  if(data[(i-1)*step+(j+1)]>data[i*step+j])tmp[6]=1;  elsetmp[6]=0;  if(data[(i-1)*step+j]>data[i*step+j])tmp[7]=1;  elsetmp[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

就可以了。哦也,这个可是我在网上找了好久才解决的,分享一下,欢迎大家多多指点。

五.遇到的问题

就是使用Mat结构存储彩色图像,多通道图像后,怎么把它转换成单通道的灰度图。
我网上找了好多资料,没发现有相关可以参考的函数可以直接调用。有一个提到可以使用IplImage和Mat相互转化。我想用这种方法,就是先转换再调用cvCvtColor() 进行灰度图的转化。但没有试过,不知道可不可以。
如果有同学知道怎么弄,欢迎告诉我一下,不胜感激

六.参考

opencv2.4.4中的facerec文档

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

等等。

原创粉丝点击