LBP(Local binary pattern)是一个易理解且有效的局部图像特征,应用很广泛。在网上可以搜到一大把的LBP介绍,所以本博文就忽略了对其的介绍。直接附上代码,代码不难,只是希望对大家有用!如有错误和补充,欢迎提出,大家共同进步哈!
注意:下面代码仅为示例便利,牺牲了一些效率!
一)一般的LBP,256维
[cpp] view plain copy //==================================================================== // 作者 : quarryman // 邮箱 : quarrying{at}qq.com // 主页 : http://blog.csdn.net/quarryman // 日期 : 2013年08月11日 // 描述 : 实现一般的LBP //==================================================================== #include <cv.h> #include <highgui.h> void LBP(IplImage* src, IplImage* dst) { int width=src->width; int height=src->height; for(int j=1;j<width-1;j++) { for(int i=1;i<height-1;i++) { uchar neighborhood[8]={0}; neighborhood[7] = CV_IMAGE_ELEM( src, uchar, i-1, j-1); neighborhood[6] = CV_IMAGE_ELEM( src, uchar, i-1, j); neighborhood[5] = CV_IMAGE_ELEM( src, uchar, i-1, j+1); neighborhood[4] = CV_IMAGE_ELEM( src, uchar, i, j-1); neighborhood[3] = CV_IMAGE_ELEM( src, uchar, i, j+1); neighborhood[2] = CV_IMAGE_ELEM( src, uchar, i+1, j-1); neighborhood[1] = CV_IMAGE_ELEM( src, uchar, i+1, j); neighborhood[0] = CV_IMAGE_ELEM( src, uchar, i+1, j+1); uchar center = CV_IMAGE_ELEM( src, uchar, i, j); uchar temp=0; for(int k=0;k<8;k++) { temp+=(neighborhood[k]>=center)<<k; } CV_IMAGE_ELEM( dst, uchar, i, j)=temp; } } } int main() { IplImage* img=cvLoadImage("lena.jpg", 0); IplImage* dst=cvCreateImage(cvGetSize(img),8,1); LBP(img,dst); cvNamedWindow("图像", 1); cvShowImage("图像", dst); cvWaitKey(0); cvDestroyAllWindows(); cvReleaseImage(&img); cvReleaseImage(&dst); return 0; } 结果图像为:
二)Uniform Pattern的LBP,将256维降为59维。 绝大多数LBP模式最多只包含两次从1到0或从0到1的跳变。因此,Ojala将Uniform Pattern定义为:当某个LBP所对应的循环二进制数从0到1或从1到0最多有两次跳变时,该LBP所对应的二进制就称为一个等价模式类。
代码一:
[cpp] view plain copy #include <stdio.h> typedef unsigned char uchar; int getHopCount(uchar i) { int a[8]={0}; int k=7; int cnt=0; while(i) { a[k]=i&1; i>>=1; --k; } for(int k=0;k<8;++k) { if(a[k]!=a[k+1==8?0:k+1]) { ++cnt; } } return cnt; } int main() { int cnt[9]={0}; for(int i=0;i<256;++i) { cnt[getHopCount(i)]++; } for(int i=0;i<9;++i) { printf("跳变%d次的数目:%d\n",i,cnt[i]); } return 0; }
输出结果为: 跳变0次的数目:2 跳变1次的数目:0 跳变2次的数目:56 跳变3次的数目:0 跳变4次的数目:140 跳变5次的数目:0 跳变6次的数目:56 跳变7次的数目:0 跳变8次的数目:2 可见:56+2+1==59,所以有59维。
代码二:
[cpp] view plain copy //==================================================================== // 作者 : quarryman // 邮箱 : quarrying{at}qq.com // 主页 : http://blog.csdn.net/quarryman // 日期 : 2013年08月11日 // 描述 : Uniform Pattern的LBP //==================================================================== #include <cv.h> #include <highgui.h> int getHopCount(uchar i) { int a[8]={0}; int k=7; int cnt=0; while(i) { a[k]=i&1; i>>=1; --k; } for(int k=0;k<8;++k) { if(a[k]!=a[k+1==8?0:k+1]) { ++cnt; } } return cnt; } void lbp59table(uchar* table) { memset(table,0,256); uchar temp=1; for(int i=0;i<256;++i) { if(getHopCount(i)<=2) { table[i]=temp; temp++; } // printf("%d\n",table[i]); } } void LBP(IplImage* src, IplImage* dst) { int width=src->width; int height=src->height; uchar table[256]; lbp59table(table); for(int j=1;j<width-1;j++) { for(int i=1;i<height-1;i++) { uchar neighborhood[8]={0}; neighborhood[7] = CV_IMAGE_ELEM( src, uchar, i-1, j-1); neighborhood[6] = CV_IMAGE_ELEM( src, uchar, i-1, j); neighborhood[5] = CV_IMAGE_ELEM( src, uchar, i-1, j+1); neighborhood[4] = CV_IMAGE_ELEM( src, uchar, i, j+1); neighborhood[3] = CV_IMAGE_ELEM( src, uchar, i+1, j+1); neighborhood[2] = CV_IMAGE_ELEM( src, uchar, i+1, j); neighborhood[1] = CV_IMAGE_ELEM( src, uchar, i+1, j-1); neighborhood[0] = CV_IMAGE_ELEM( src, uchar, i, j-1); uchar center = CV_IMAGE_ELEM( src, uchar, i, j); uchar temp=0; for(int k=0;k<8;k++) { temp+=(neighborhood[k]>=center)<<k; } //CV_IMAGE_ELEM( dst, uchar, i, j)=temp; CV_IMAGE_ELEM( dst, uchar, i, j)=table[temp]; } } } int main() { IplImage* img=cvLoadImage("lena.jpg", 0); IplImage* dst=cvCreateImage(cvGetSize(img),8,1); LBP(img,dst); cvNamedWindow("图像", 1); cvShowImage("图像", dst); cvWaitKey(0); cvDestroyAllWindows(); cvReleaseImage(&img); cvReleaseImage(&dst); return 0; } 输出图像为: