opencv笔记(7):LBP特征

xiaoxiao2021-02-27  349

特征提取之LBP特征

局部二值模式(Local Binary Pattern,LBP)是一种描述图像纹理特征的算子,它具有旋转和灰度不变性。一般不将LBP图谱作为特征向量用于分类识别,而是采用LBP特征值谱的统计直方图作为特征向量用于分类识别。

1.LBP特征算子

1.1原始LBP

原始LBP是在3*3的窗口内,以窗口中心元素为阈值,比较周围8个像素,若大于中心像素点,则标记为1,否则为0。然后这8个点就可以产生一个8位的二进制数(共有2^8=256种),转换为10进制数后,这个值就用来代替像素中心值。 #include <opencv2\core\core.hpp> #include <opencv2\imgproc\imgproc.hpp> #include <opencv2\highgui\highgui.hpp> #include <iostream> using namespace cv; using namespace std; void LBP(IplImage* src, IplImage* dst)//原始LBP { 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 }; //uchar(8位无符号整形数据,范围0~255) 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; //如果大于中心值则为1,否则为0 } CV_IMAGE_ELEM(dst, uchar, i, j) = temp; //将最后的LBP值赋值给中心像素 } } } int main() { IplImage* img = cvLoadImage("D:/img/1.jpg", 0); //IplImage* 图像底层指针 IplImage* dst = cvCreateImage(cvGetSize(img), 8, 1); LBP(img, dst); Mat dst1(dst, 0); //IplImage类型转换Mat类型 namedWindow("dst"); imshow("dst", dst1); waitKey(0); return 0; }

1.2圆形LBP算子

由于原始LBP只是覆盖了一个固定半径范围内的小区域,不能满足不同尺寸和频率纹理的需要。对此,将3*3领域扩展到任意领域,用圆形领域代替正方形领域。

1.3旋转不变LBP

旋转不变LBP即是在8种不同LBP模式下(按位平移,最高位移动到最低位),取其最小值。

1.4均匀LBP(等价模式)

由于一个LBP算子可以产生不同的二进制模式,过多的模式种类对于纹理的识别、分类和信息的存取是不利的。均匀LBP就是一个二进制序列从0到1或者从1到0的变化不超过2次。将二进制序列首尾相连,总共有59种(变化次数为0的有2种,1的有0种,2的有56种,其他为1种)。因为发现计算出来的大部分值在58种之中,可达到90%以上,所以把值分为了59个,58个不超过2次的为一类,另外其他的为一类。这样就从原来的256维降到了58维。 #include <opencv2\core\core.hpp> #include <opencv2\imgproc\imgproc.hpp> #include <opencv2\highgui\highgui.hpp> #include <iostream> using namespace cv; using namespace std; 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++; } } } void ULBP(IplImage* src, IplImage* dst)//均匀LBP { 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) = table[temp]; } } } int main() { IplImage* img = cvLoadImage("D:/img/1.jpg", 0); //IplImage* 图像底层指针 IplImage* dst = cvCreateImage(cvGetSize(img), 8, 1); ULBP(img, dst); Mat dst1(dst, 0); //IplImage类型转换Mat类型 namedWindow("dst"); imshow("dst", dst1); waitKey(0); return 0; }

2.对LBP特征向量进行提取的步骤

(1)将检测窗口划分为16*16的小区域(cell)。 (2)对于每个cell中的一个像素,计算得到它的LBP值。 (3)计算每个cell的直方图,即每个LBP值出现的频率,然后归一化。 (4)统计每个cell的直方图,连接成一个向量。
转载请注明原文地址: https://www.6miu.com/read-1220.html

最新回复(0)