LBP特征学习及实现

简介: 老外的原文:《Multiresolution gray-scale and rotation invariant texture classification with local binary patterns》 Timo Ojala, Matti PietikaÈ inen,2002   本文将对这篇文章做部分翻译,最后将分别给出下列代码实现 。

老外的原文:《Multiresolution gray-scale and rotation invariant texture classification with local binary patterns》 Timo Ojala, Matti PietikaÈ inen,2002

  本文将对这篇文章做部分翻译,最后将分别给出下列代码实现

。灰度不变性LBP( gray scale invariant)

。旋转不变性LBP(rotation invariant)

。旋转不变等价LBP(rotation & uniform invariant)


1.INTRODUCTION

   二维纹理分析有许多潜在的应用,比如工业表面检查、遥感、生物图片分析,但是只有很少的例子成功发现了纹理的存在。主要的问题是,在现实世界中,由于方向、尺度及其他视觉外观的变化导致纹理常常不是均一的。灰度尺度不变性通常变得非常重要,因为不均匀的光照或图像内大幅变化。另外,已经提出的纹理测量算法计算量太大【比如灰度共生矩阵,我加的】。

  绝大多数纹理分类方法都显式或隐式的假设,待分类的未知样本与训练样本在在空间大小、方向和灰度尺度属性上都一致。然而,现实世界的纹理受变化的光照条件影响,可以存在任意空间分辨率和旋转方向。

  然后,罗列了一堆前人的工作......

  在老外这篇文章中,老外提出了一种计算量小并且可以有效检测大量旋转和灰度尺度不同的纹理。他们提出一种基于Local Binary Patterns【LBP特征】 的灰度尺度不变性和旋转不变性的纹理算子。从局部邻域的圆形区域内像素灰度的联合分布开始,他们推导了一个算子,对任何单调的灰度尺度变化都能显示不变性。旋转不变性是通过灰度尺度不变算子配合一系列旋转不变模式实现的。

 【我这算直译的,不通也是常理,下面开始重点了】


  2.GRAY SCALE AND ROTATION INVARIANT LOCAL BINARY PATTERNS

   定义纹理 T 为一副黑白纹理图像局部邻域内图像像素灰度的联合分布:


  其中,gc 对应局部邻域中心像素的灰度值,gp (p = 1,2,...,P-1)对应半径为 R 的圆形对称邻域内 P等分的像素灰度。如果 gc 坐标为 (0,0),那么 gp 的坐标为…(- R sin…(2πp/P),R cos… (2πp/P))†。如下图所示,为不同采样点 P 和半径 R 的圆形对称邻域。其中对于邻域内那些没有直接落在像素【方格】中央的点的灰度值将通过二线性插值完成。


2.1  Achieving Gray-Scale Invariance

   首先,我们将邻域内中心像素点 gc 的灰度值与圆形对称区域内其他点 gp 的灰度值相减:


  接下来,我们假设差分 gp - gc  和 gc 是相互独立的,于是就有:


  在实际中,这种直接独立是不能被保证的,因此上式仅是联合分布的一种近似。由于分布 t ( gc )描述了图像整体光照,因此没有给纹理分析提供有用的信息。这样,纹理特征可以由以下联合差分分布表示:


  这是一个具有高度判别性的纹理算子。它在 P 维直方图中,记录了每个像素点的邻域中模式变化的发生次数。对于恒定的区域,所有方向的差分均为 0。对于缓慢的斜边,该算子记录了梯度方向最大的差分,沿着边的方向差分为0 。对于一个斑点,所有方向的差分都很大。

  带符号差分 gp - gc 不受平均光源变化影响。因此,联合差分分布对于灰度尺度变化具有不变性。我们通过仅使用差分的符号,而不是差分本身的值来实现灰度尺度不变性:


  通过对每个符号 s( gp - gc ) 赋予因子2^P,我们将上述公式变成唯一的 LBP值,用来描述局部图像纹理的空间结构:


当P=8,R=1时,这里的LBP值和经典的LBP值很相似,但差别在于,这边采样区域为圆形,且像素值必须通过二线性插值获得。


2.2 Achieving Rotation Invariance

 上述LBP算子将产生 2^P 个不同输出,对应由邻域内P个像素点形成的2 ^ P个不同二进制模式。当图像被旋转,【以下为意译】,灰度值gp 和g0的相对位置将发生变化,而g0通常取中心 gc 的正右 ,坐标(0,R) ,这会导致不同的LBP值。但任何角度的旋转不影响,圆形对称邻域内 0 和 1 的相对位置关系,为了移除旋转获得唯一的LBP值,我们定义:


 其中,ROR(x,i)执行沿时钟方向将P位数 X 移动 i 次。对于图像像素而言,就是将邻域集合按照时钟方向旋转很多次,直到当前旋转下构成的LBP值最小。【即文中所说的,最重要位的最大值为0,即gp-1为0】

 如下图所示,对于8个采样点,将有36种唯一的旋转不变二值模式:【黑点为0,白点为1】


2.3  Improved Rotation Invariance with ªUniformº Patterns

  对于8个采样点,灰度不变性LBP将产生256中输出,旋转不变性LBP将产生36个输出,而基于unifrom的旋转不变LBP将只有9中输出。【uniform形式有58中输出】

  【上面讲的种类对于后面编程实现,计算映射mapping很重要】

  首先介绍什么是uniform,它是指均匀环形结构内包含非常少的空间转换。我们定义U(pattern),用来记录空间转换的数量,即0-1变化的次数。比如,上图第一行中00000000和11111111,它们的U值均为0,而其余种类的U均为2.类似的,上述其他27中模式的 U 值至少为4。我们将 U 值为2的模式称为 uniform

那么:

  对于8个采样点,共有58种唯一的 uniform类型的LBP值输出【此处没考虑旋转不变性,58种输出是LBP的2进制值,而非U值,U值都是2】,如下图所示:


关于uniform输出的种类,并不在该论文中,属于题外话,因为有人直接拿uniform形式去提取LBP特征。详情见《Rotation Invariant Image Description with Local Binary Pattern Histogram Fourier Features》一文。

接下来继续介绍基于uniform的旋转不变LBP,我们定义如下公式:




其中,P为采样点个数。


3.具体实现

 下面代码用C实现,读入一副灰度图像,采样点个数,采样半径,对每个像素计算LBP特征并输出,LBP图像及其直方图。

  对于旋转不变性及uniform旋转不变性,我没有对每个像素都进行上述公式的操作,由于是2进制的圆形循环,可以提前做个mapping映射关系,加快程序执行速度。

 采样点数量均为8,采样半径为10

输入图像:


3.1 灰度不变性LBP:

void gray_invariant_lbp(IplImage *src,int height,int width,int num_sp,MyPoint *spoint)
{
	IplImage *target,*hist;
	int i,j,k,box_x,box_y,orign_x,orign_y,dx,dy,tx,ty,fy,fx,cy,cx,v;
	double min_x,max_x,min_y,max_y,w1,w2,w3,w4,N,x,y;
	int *result;
	float dishu;
	
	dishu = 2.0;
	max_x=0;max_y=0;min_x=0;min_y=0;
	for (k=0;k<num_sp;k++)
	{
		if (max_x<spoint[k].x)
		{
			max_x=spoint[k].x;
		}
		if (max_y<spoint[k].y)
		{
			max_y=spoint[k].y;
		}
		if (min_x>spoint[k].x)
		{
			min_x=spoint[k].x;
		}
		if (min_y>spoint[k].y)
		{
			min_y=spoint[k].y;
		}
	}

	//计算模版大小
	box_x = ceil(MAX(max_x,0)) - floor(MIN(min_x,0)) + 1;
	box_y = ceil(MAX(max_y,0)) - floor(MIN(min_y,0)) + 1;
	
	if (width<box_x||height<box_y)
	{
		printf("Too small input image. Should be at least (2*radius+1) x (2*radius+1)");
		return;
	}

	//计算可滤波图像大小,opencv图像数组下标从0开始
	orign_x = 0 - floor(MIN(min_x,0));//起点
	orign_y = 0 - floor(MIN(min_x,0));
	
	dx = width - box_x+1;//终点
	dy = height - box_y+1;
	
	int cols = pow(dishu,(float)num_sp);
	hist = cvCreateImage(cvSize(300,200),IPL_DEPTH_8U,3);//直方图图像
	target = cvCreateImage(cvSize(dx,dy),IPL_DEPTH_8U,1);
	result = (int *)malloc(sizeof(int)*dx*dy);
	double *val_hist = (double *)malloc(sizeof(double)*cols);	//直方图数组
	
	memset(result,0,sizeof(int)*dx*dy);
	CvRect roi =cvRect(orign_x, orign_y, dx, dy);
	cvSetImageROI(src, roi);
	cvCopy(src, target);  
	cvResetImageROI(src);
	cvSaveImage("haha.jpg",target);
	
	for ( k = 0; k<num_sp;k++)
	{
		x = spoint[k].x+orign_x;
		y = spoint[k].y+orign_y;

		//二线性插值图像
		fy = floor(y);	//向下取整
		fx = floor(x);
		cy = ceil(y);	//向上取整
		cx = ceil(x);
		ty = y - fy;
		tx = x - fx;
		w1 = (1 - tx) * (1 - ty);
		w2 = tx  * (1 - ty);
		w3 = (1 - tx) * ty ;
		w4 = tx * ty ;
        v = pow(dishu,(float)k);

		for (i = 0;i<dy;i++)
		{
			for (j = 0;j<dx;j++)
			{
				//灰度插值图像像素
				N = w1 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+fx]+
					  w2 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+cx]+
					  w3 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+fx]+
					  w4 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+cx];
				
				if( N >= (double)(unsigned char)target->imageData[i*dx+j])
				{
					result[i*dx+j] = result[i*dx+j] + v * 1;
				}else{
					result[i*dx+j] = result[i*dx+j] + v * 0;
				}
			}
		}
	}
	//显示图像
	if (num_sp<=8)
	{
		//只有采样数小于8,则编码范围0-255,才能显示图像
		for (i = 0;i<dy;i++)
		{
			for (j = 0;j<dx;j++)
			{
				target->imageData[i*dx+j] = (unsigned char)result[i*dx+j];
				//printf("%d\n",(unsigned char)target->imageData[i*width+j]);
			}
		}
		cvSaveImage("result.jpg",target);
	}
	
	//显示直方图

	for (i=0;i<cols;i++)
	{
		val_hist[i]=0.0;
	}
	for (i=0; i<dy*dx;i++)
	{
		val_hist[result[i]]++;
	}
	
	double temp_max=0.0;

	for (i=0;i<cols;i++)			//求直方图最大值,为了归一化
	{
		//printf("%f\n",val_hist[i]);
		if (temp_max<val_hist[i])
		{
			temp_max=val_hist[i];
		}
	}
	//画直方图
	CvPoint p1,p2;
	double bin_width=(double)hist->width/cols;
	double bin_unith=(double)hist->height/temp_max;

	for (i=0;i<cols;i++)
	{
		p1.x=i*bin_width;p1.y=hist->height;
		p2.x=(i+1)*bin_width;p2.y=hist->height-val_hist[i]*bin_unith;
		cvRectangle(hist,p1,p2,cvScalar(0,255),-1,8,0);
	}
	cvSaveImage("hist.jpg",hist);
}

实验结果:



3.2 旋转不变性:

void rotation_invariant_mapping(int range,int num_sp,int *Mapping)
{
	int newMax,rm,r;
	int *tmpMap;

	newMax = 0;
	tmpMap = (int *)malloc(sizeof(int)*range);
	memset(tmpMap,-1,sizeof(int)*range);

	for (int i = 0 ; i < range ; i++)
	{
		rm = i;
		r = i;
		for (int j = 0 ; j < num_sp -1 ;j++)
		{
			//将r向左循环移动一位,当r超过num_sp位时,舍弃
			r = r << 1;
			if (r > range -1)
			{
				r = r - (range -1);
			}
			//printf("%d,%d\n",r,rm);
			if (r < rm)
			{
				rm = r;
			}
		}
		if (tmpMap[rm] < 0)
		{
			tmpMap[rm] = newMax;
			newMax++;
			
		}
		Mapping[i] = tmpMap[rm];
	}
	free(tmpMap);
}

void rotation_invariant_lbp(IplImage *src,int height,int width,int num_sp,MyPoint *spoint,int *Mapping)
{
	IplImage *target,*hist;
	int i,j,k,box_x,box_y,orign_x,orign_y,dx,dy,tx,ty,fy,fx,cy,cx,v;
	double min_x,max_x,min_y,max_y,w1,w2,w3,w4,N,x,y;
	int *result;
	float dishu;

	dishu = 2.0;
	max_x=0;max_y=0;min_x=0;min_y=0;
	for (k=0;k<num_sp;k++)
	{
		if (max_x<spoint[k].x)
		{
			max_x=spoint[k].x;
		}
		if (max_y<spoint[k].y)
		{
			max_y=spoint[k].y;
		}
		if (min_x>spoint[k].x)
		{
			min_x=spoint[k].x;
		}
		if (min_y>spoint[k].y)
		{
			min_y=spoint[k].y;
		}
	}

	//计算模版大小
	box_x = ceil(MAX(max_x,0)) - floor(MIN(min_x,0)) + 1;
	box_y = ceil(MAX(max_y,0)) - floor(MIN(min_y,0)) + 1;

	if (width<box_x||height<box_y)
	{
		printf("Too small input image. Should be at least (2*radius+1) x (2*radius+1)");
		return;
	}

	//计算可滤波图像大小,opencv图像数组下标从0开始
	orign_x = 0 - floor(MIN(min_x,0));//起点
	orign_y = 0 - floor(MIN(min_x,0));

	dx = width - box_x+1;//终点
	dy = height - box_y+1;

	target = cvCreateImage(cvSize(dx,dy),IPL_DEPTH_8U,1);
	result = (int *)malloc(sizeof(int)*dx*dy);
	
	memset(result,0,sizeof(int)*dx*dy);
	CvRect roi =cvRect(orign_x, orign_y, dx, dy);
	cvSetImageROI(src, roi);
	cvCopy(src, target);  
	cvResetImageROI(src);
	cvSaveImage("haha.jpg",target);

	for ( k = 0; k<num_sp;k++)
	{
		x = spoint[k].x+orign_x;
		y = spoint[k].y+orign_y;

		//二线性插值图像
		fy = floor(y);	//向下取整
		fx = floor(x);
		cy = ceil(y);	//向上取整
		cx = ceil(x);
		ty = y - fy;
		tx = x - fx;
		w1 = (1 - tx) * (1 - ty);
		w2 = tx  * (1 - ty);
		w3 = (1 - tx) * ty ;
		w4 = tx * ty ;
		v = pow(dishu,(float)k);

		for (i = 0;i<dy;i++)
		{
			for (j = 0;j<dx;j++)
			{
				//灰度插值图像像素
				N = w1 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+fx]+
					w2 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+cx]+
					w3 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+fx]+
					w4 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+cx];

				if( N >= (double)(unsigned char)target->imageData[i*dx+j])
				{
					result[i*dx+j] = result[i*dx+j] + v * 1;
				}else{
					result[i*dx+j] = result[i*dx+j] + v * 0;
				}
			}
		}
	}

	//将result的值映射为mapping的值
	for(i = 0; i < dy ;i++)
	{
		for (j = 0; j < dx ;j ++)
		{
			result[i*dx+j] = Mapping[result[i*dx+j]];
		}
	}

	//显示图像
	int cols = 0;//直方图的横坐标,也是result数组的元素种类
	int mapping_size = pow(dishu,(float)num_sp);
	for (i = 0;i < mapping_size; i++ )
	{
		if (cols < Mapping[i])
		{
			cols = Mapping[i];
		}
	}

	if (cols < 255)
	{
		//只有采样数小于8,则编码范围0-255,才能显示图像
		for (i = 0;i<dy;i++)
		{
			for (j = 0;j<dx;j++)
			{
				target->imageData[i*dx+j] = (unsigned char)result[i*dx+j];
				//printf("%d\n",(unsigned char)target->imageData[i*width+j]);
			}
		}
		cvSaveImage("result.jpg",target);
	}

	//计算直方图
	hist = cvCreateImage(cvSize(300,200),IPL_DEPTH_8U,3);//直方图图像
	
	double *val_hist = (double *)malloc(sizeof(double)*cols);	//直方图数组
	for (i=0;i<cols;i++)
	{
		val_hist[i]=0.0;
	}
	for (i=0; i<dy*dx;i++)
	{
		val_hist[result[i]]++;
	}

	double temp_max=0.0;

	for (i=0;i<cols;i++)			//求直方图最大值,为了归一化
	{
		//printf("%f\n",val_hist[i]);
		if (temp_max<val_hist[i])
		{
			temp_max=val_hist[i];
		}
	}
	//画直方图
	CvPoint p1,p2;
	double bin_width=(double)hist->width/cols;
	double bin_unith=(double)hist->height/temp_max;

	for (i=0;i<cols;i++)
	{
		p1.x=i*bin_width;p1.y=hist->height;
		p2.x=(i+1)*bin_width;p2.y=hist->height-val_hist[i]*bin_unith;
		cvRectangle(hist,p1,p2,cvScalar(0,255),-1,8,0);
	}
	cvSaveImage("hist.jpg",hist);
}

实验结果:




3.3 uniform 旋转不变性,给出完整代码:

#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#define  PI 3.1415926
#define MAX(x,y) (x)>(y)?(x):(y)
#define MIN(x,y) (x)<(y)?(x):(y)

typedef struct MyPoint
{
	double x;
	double y;
}MyPoint;
void calc_position(int radius,int num_sp,MyPoint *spoint)
{
	double theta;

	theta = 2*PI/num_sp;
	
	for (int i = 0; i < num_sp; i++)
	{
		spoint[i].y = -radius * sin(i * theta);
		spoint[i].x = radius * cos(i * theta);
	}
}
int calc_sum(int r)
{
	int res_sum;

	res_sum = 0;
	while (r)
	{
		res_sum = res_sum + r % 2;
		r /= 2;
	}
	return res_sum;
}
void rotation_uniform_invariant_mapping(int range,int num_sp,int *Mapping)
{
	int numt,i,j,tem_xor;

	numt = 0;
	tem_xor = 0;
	for (i = 0; i< range; i++)
	{
		j = i << 1;
		if (j > range -1)
		{
			j = j - (range -1);
		}
		
		tem_xor = i ^ j;	// 异或
		numt = calc_sum(tem_xor);//计算异或结果中1的个数,即跳变个数
		
		if (numt <= 2)
		{
			Mapping[i] = calc_sum(i);
		}else{
			Mapping[i] = num_sp+1;
		}
	}	

}

void rotation_uniform_invariant_lbp(IplImage *src,int height,int width,int num_sp,MyPoint *spoint,int *Mapping)
{
	IplImage *target,*hist;
	int i,j,k,box_x,box_y,orign_x,orign_y,dx,dy,tx,ty,fy,fx,cy,cx,v;
	double min_x,max_x,min_y,max_y,w1,w2,w3,w4,N,x,y;
	int *result;
	float dishu;

	dishu = 2.0;
	max_x=0;max_y=0;min_x=0;min_y=0;
	for (k=0;k<num_sp;k++)
	{
		if (max_x<spoint[k].x)
		{
			max_x=spoint[k].x;
		}
		if (max_y<spoint[k].y)
		{
			max_y=spoint[k].y;
		}
		if (min_x>spoint[k].x)
		{
			min_x=spoint[k].x;
		}
		if (min_y>spoint[k].y)
		{
			min_y=spoint[k].y;
		}
	}

	//计算模版大小
	box_x = ceil(MAX(max_x,0)) - floor(MIN(min_x,0)) + 1;
	box_y = ceil(MAX(max_y,0)) - floor(MIN(min_y,0)) + 1;

	if (width<box_x||height<box_y)
	{
		printf("Too small input image. Should be at least (2*radius+1) x (2*radius+1)");
		return;
	}

	//计算可滤波图像大小,opencv图像数组下标从0开始
	orign_x = 0 - floor(MIN(min_x,0));//起点
	orign_y = 0 - floor(MIN(min_x,0));

	dx = width - box_x+1;//终点
	dy = height - box_y+1;

	target = cvCreateImage(cvSize(dx,dy),IPL_DEPTH_8U,1);
	result = (int *)malloc(sizeof(int)*dx*dy);

	memset(result,0,sizeof(int)*dx*dy);
	CvRect roi =cvRect(orign_x, orign_y, dx, dy);
	cvSetImageROI(src, roi);
	cvCopy(src, target);  
	cvResetImageROI(src);
	cvSaveImage("haha.jpg",target);

	for ( k = 0; k<num_sp;k++)
	{
		x = spoint[k].x+orign_x;
		y = spoint[k].y+orign_y;

		//二线性插值图像
		fy = floor(y);	//向下取整
		fx = floor(x);
		cy = ceil(y);	//向上取整
		cx = ceil(x);
		ty = y - fy;
		tx = x - fx;
		w1 = (1 - tx) * (1 - ty);
		w2 = tx  * (1 - ty);
		w3 = (1 - tx) * ty ;
		w4 = tx * ty ;
		v = pow(dishu,(float)k);

		for (i = 0;i<dy;i++)
		{
			for (j = 0;j<dx;j++)
			{
				//灰度插值图像像素
				N = w1 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+fx]+
					w2 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+cx]+
					w3 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+fx]+
					w4 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+cx];

				if( N >= (double)(unsigned char)target->imageData[i*dx+j])
				{
					result[i*dx+j] = result[i*dx+j] + v * 1;
				}else{
					result[i*dx+j] = result[i*dx+j] + v * 0;
				}
			}
		}
	}

	//将result的值映射为mapping的值
	for(i = 0; i < dy ;i++)
	{
		for (j = 0; j < dx ;j ++)
		{
			result[i*dx+j] = Mapping[result[i*dx+j]];
		}
	}

	//显示图像
	int cols = 0;//直方图的横坐标,也是result数组的元素种类
	int mapping_size = pow(dishu,(float)num_sp);
	for (i = 0;i < mapping_size; i++ )
	{
		if (cols < Mapping[i])
		{
			cols = Mapping[i];
		}
	}

	if (cols < 255)
	{
		//只有采样数小于8,则编码范围0-255,才能显示图像
		for (i = 0;i<dy;i++)
		{
			for (j = 0;j<dx;j++)
			{
				target->imageData[i*dx+j] = (unsigned char)result[i*dx+j];
				//printf("%d\n",(unsigned char)target->imageData[i*width+j]);
			}
		}
		cvSaveImage("result.jpg",target);
	}

	//计算直方图
	hist = cvCreateImage(cvSize(300,200),IPL_DEPTH_8U,3);//直方图图像
	double *val_hist = (double *)malloc(sizeof(double)*cols);	//直方图数组
	for (i=0;i<cols;i++)
	{
		val_hist[i]=0.0;
	}
	for (i=0; i<dy*dx;i++)
	{
		val_hist[result[i]]++;
	}

	double temp_max=0.0;

	for (i=0;i<cols;i++)			//求直方图最大值,为了归一化
	{
		//printf("%f\n",val_hist[i]);
		if (temp_max<val_hist[i])
		{
			temp_max=val_hist[i];
		}
	}
	//画直方图
	CvPoint p1,p2;
	double bin_width=(double)hist->width/cols;
	double bin_unith=(double)hist->height/temp_max;

	for (i=0;i<cols;i++)
	{
		p1.x=i*bin_width;p1.y=hist->height;
		p2.x=(i+1)*bin_width;p2.y=hist->height-val_hist[i]*bin_unith;
		cvRectangle(hist,p1,p2,cvScalar(0,255),-1,8,0);
	}
	cvSaveImage("hist.jpg",hist);
}

int _tmain(int argc, _TCHAR* argv[])
{
	IplImage *src,*grey,*result;
	int samples,radius,range,*mapping;
	MyPoint *spoint;
	float Mi;

	samples = 8;
	radius = 10;
	Mi = 2.0;
	range = pow(Mi,samples);

	src = cvLoadImage("test2.jpg");
	grey = cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
	cvCvtColor(src,grey,CV_BGR2GRAY);
	mapping = (int *)malloc(sizeof(int)*range);
	memset(mapping,0,sizeof(int)*range);
	
	//计算采样点相对坐标
	spoint = (MyPoint *)malloc(sizeof(MyPoint)*samples); 
	calc_position(radius,samples,spoint);
	
	//计算灰度不变性LBP特征,写回浮点数图像矩阵中
	//gray_invariant_lbp(grey,src->height,src->width,samples,spoint);

	//计算旋转不变形LBP特征
	//rotation_invariant_mapping(range,samples,mapping);
	//rotation_invariant_lbp(grey,src->height,src->width,samples,spoint,mapping);

	//计算旋转不变等价LBP特征
	rotation_uniform_invariant_mapping(range,samples,mapping);
	rotation_uniform_invariant_lbp(grey,src->height,src->width,samples,spoint,mapping);
	return 0;
}

 实验结果:



越到后面越黑,因为输出的种类越来越少。

目录
相关文章
|
6月前
|
机器学习/深度学习 自然语言处理 数据可视化
深度探索变分自编码器在无监督特征学习中的应用
【4月更文挑战第20天】 在深度学习领域,无监督学习一直是研究的热点问题之一。本文聚焦于一种前沿的生成模型——变分自编码器(Variational Autoencoder, VAE),探讨其在无监督特征学习中的关键作用与应用潜力。不同于传统的摘要形式,本文将直接深入VAE的核心机制,分析其如何通过引入随机隐变量和重参数化技巧,实现对复杂数据分布的有效建模。文章还将展示VAE在多个实际数据集上的应用结果,验证其作为无监督特征提取工具的有效性和普适性。通过理论与实践的结合,本文旨在为读者提供关于VAE在无监督特征学习领域的全面认识。
|
14天前
|
机器学习/深度学习 算法 数据可视化
机器学习的核心功能:分类、回归、聚类与降维
机器学习领域的基本功能类型通常按照学习模式、预测目标和算法适用性来分类。这些类型包括监督学习、无监督学习、半监督学习和强化学习。
19 0
|
3月前
|
机器学习/深度学习 数据挖掘
这7大经典回归模型,你用过几个?
这7大经典回归模型,你用过几个?
这7大经典回归模型,你用过几个?
|
5月前
|
机器学习/深度学习 算法 Python
机器学习算法的比较与选择是在实际应用中非常重要的一步,不同的算法适用于不同的问题和数据特征。
机器学习算法的比较与选择是在实际应用中非常重要的一步,不同的算法适用于不同的问题和数据特征。
|
6月前
|
机器学习/深度学习 算法
【机器学习】如何使用朴素贝叶斯分类器来处理类别特征?
【5月更文挑战第10天】【机器学习】如何使用朴素贝叶斯分类器来处理类别特征?
|
6月前
|
机器学习/深度学习 数据挖掘 Python
机器学习-特征选择:如何使用互信息特征选择挑选出最佳特征?
机器学习-特征选择:如何使用互信息特征选择挑选出最佳特征?
630 1
|
机器学习/深度学习 数据采集 算法
机器学习-特征选择:如何使用Lassco回归精确选择最佳特征?
本文旨在介绍Lasso回归在精确特征选择中的应用。首先,我们将探讨特征选择的重要性,包括如何提高模型性能和降低计算成本。接着,我们将深入解析Lasso回归的原理和算法,并说明其在特征选择中的优势。为了支撑我们的观点,我们将引用相关文献提供的实证结果和案例分析。
2187 1
|
机器学习/深度学习 算法 索引
逻辑回归与多项式特征:解密分类问题的强大工具
逻辑回归与多项式特征:解密分类问题的强大工具
|
供应链 开发者
服务的特征 | 学习笔记
快速学习服务的特征。
644 0
服务的特征 | 学习笔记
|
机器学习/深度学习 人工智能 算法
分类预测:分类算法概念|学习笔记(二)
快速学习分类预测:分类算法概念
分类预测:分类算法概念|学习笔记(二)