opencv笔记(7):LBP特征

特征提取之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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值