opencv学习之(三)-LBP算法的研究及其实现
2013-05-05 13:17
288 查看
一,原始LBP算法
LBP的基本思想是对图像的像素和它局部周围像素进行对比后的结果进行求和。把这个像素作为中心,对相邻像素进行阈值比较。如果中心像素的亮度大于等于他的相邻像素,把他标记为1,否则标记为0。你会用二进制数字来表示每个像素,比如11001111。因此,由于周围相邻8个像素,你最终可能获取2^8个可能组合,被称为局部二值模式,有时被称为LBP码。第一个在文献中描述的LBP算子实际使用的是3*3的邻域一个更加正式的LBP操作可以被定义为
其中
是中心像素,亮度是
;而
则是相邻像素的亮度。s是一个符号函数:
这种描述方法使得你可以很好的捕捉到图像中的细节。实际上,研究者们可以用它在纹理分类上得到最先进的水平。正如刚才描述的方法被提出后,固定的近邻区域对于尺度变化的编码失效。所以,使用一个变量的扩展方法,在文献[AHP04]中有描述。主意是使用可变半径的圆对近邻像素进行编码,这样可以捕捉到如下的近邻:
对一个给定的点
,他的近邻点
可以由如下计算:
其中,R是圆的半径,而P是样本点的个数。
这个操作是对原始LBP算子的扩展,所以有时被称为扩展LBP(又称为圆形LBP)。如果一个在圆上的点不在图像坐标上,我们使用他的内插点。计算机科学有一堆聪明的插值方法,而OpenCV使用双线性插值。
二.原始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
就可以了。哦也,这个可是我在网上找了好久才解决的,分享一下,欢迎大家多多指点。
五.遇到的问题
就是使用Mat结构存储彩色图像,多通道图像后,怎么把它转换成单通道的灰度图。
我网上找了好多资料,没发现有相关可以参考的函数可以直接调用。有一个提到可以使用IplImage和Mat相互转化。我想用这种方法,就是先转换再调用cvCvtColor() 进行灰度图的转化。但没有试过,不知道可不可以。
如果有同学知道怎么弄,欢迎告诉我一下,不胜感激。
六.参考
opencv2.4.4中的facerec文档/article/1636788.html
等等。
相关文章推荐
- LBP算法的研究及其实现
- 图像分割中阈值的自动选取的研究及其算法实现
- 图像分割中阈值的自动选取的研究及其算法实现
- 保护PC程序的高速软件加密锁及其自定义算法的实现
- 【密码学】RC4加解密原理及其Java和C实现算法
- 单节目变码率TS流复用算法的研究及实现
- 经典算法研究系列:九之续、sift算法的编译与实现
- [置顶] KNN及其改进算法的python实现
- 384位NIST素域椭圆曲线快速约减算法x64编程实现研究(下)
- 感知器算法及其实现
- 通俗理解卡尔曼滤波及其算法实现(实例解析)
- 约瑟夫环及其变种算法 java实现
- Linux系统下利用OpenCV实现人脸检测和基于LBPH算法的人脸识别
- (手写识别) Zinnia库及其实现方法研究
- Md5加密原理及其实现算法
- 一个应用实例详解卡尔曼滤波及其算法实现
- 【密码学】维吉尼亚密码加解密原理及其破解算法Java实现
- 卡尔曼滤波简介及其算法实现代码(转)
- 哈希表及其常用算法(代码实现)
- 图像处理之基础---卷积及其快速算法的C++实现