opencv笔记(7):LBP特征

来源:互联网 发布:数据库是由什么组成的 编辑:程序博客网 时间:2024/05/17 02:59

特征提取之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的直方图,连接成一个向量。
0 0
原创粉丝点击