老外的原文:《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:

[cpp] view plaincopy
  1. void gray_invariant_lbp(IplImage *src,int height,int width,int num_sp,MyPoint *spoint)
  2. {
  3. IplImage *target,*hist;
  4. int i,j,k,box_x,box_y,orign_x,orign_y,dx,dy,tx,ty,fy,fx,cy,cx,v;
  5. double min_x,max_x,min_y,max_y,w1,w2,w3,w4,N,x,y;
  6. int *result;
  7. float dishu;
  8. dishu = 2.0;
  9. max_x=0;max_y=0;min_x=0;min_y=0;
  10. for (k=0;k<num_sp;k++)
  11. {
  12. if (max_x<spoint[k].x)
  13. {
  14. max_x=spoint[k].x;
  15. }
  16. if (max_y<spoint[k].y)
  17. {
  18. max_y=spoint[k].y;
  19. }
  20. if (min_x>spoint[k].x)
  21. {
  22. min_x=spoint[k].x;
  23. }
  24. if (min_y>spoint[k].y)
  25. {
  26. min_y=spoint[k].y;
  27. }
  28. }
  29. //计算模版大小
  30. box_x = ceil(MAX(max_x,0)) - floor(MIN(min_x,0)) + 1;
  31. box_y = ceil(MAX(max_y,0)) - floor(MIN(min_y,0)) + 1;
  32. if (width<box_x||height<box_y)
  33. {
  34. printf("Too small input image. Should be at least (2*radius+1) x (2*radius+1)");
  35. return;
  36. }
  37. //计算可滤波图像大小,opencv图像数组下标从0开始
  38. orign_x = 0 - floor(MIN(min_x,0));//起点
  39. orign_y = 0 - floor(MIN(min_x,0));
  40. dx = width - box_x+1;//终点
  41. dy = height - box_y+1;
  42. int cols = pow(dishu,(float)num_sp);
  43. hist = cvCreateImage(cvSize(300,200),IPL_DEPTH_8U,3);//直方图图像
  44. target = cvCreateImage(cvSize(dx,dy),IPL_DEPTH_8U,1);
  45. result = (int *)malloc(sizeof(int)*dx*dy);
  46. double *val_hist = (double *)malloc(sizeof(double)*cols);   //直方图数组
  47. memset(result,0,sizeof(int)*dx*dy);
  48. CvRect roi =cvRect(orign_x, orign_y, dx, dy);
  49. cvSetImageROI(src, roi);
  50. cvCopy(src, target);
  51. cvResetImageROI(src);
  52. cvSaveImage("haha.jpg",target);
  53. for ( k = 0; k<num_sp;k++)
  54. {
  55. x = spoint[k].x+orign_x;
  56. y = spoint[k].y+orign_y;
  57. //二线性插值图像
  58. fy = floor(y);  //向下取整
  59. fx = floor(x);
  60. cy = ceil(y);   //向上取整
  61. cx = ceil(x);
  62. ty = y - fy;
  63. tx = x - fx;
  64. w1 = (1 - tx) * (1 - ty);
  65. w2 = tx  * (1 - ty);
  66. w3 = (1 - tx) * ty ;
  67. w4 = tx * ty ;
  68. v = pow(dishu,(float)k);
  69. for (i = 0;i<dy;i++)
  70. {
  71. for (j = 0;j<dx;j++)
  72. {
  73. //灰度插值图像像素
  74. N = w1 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+fx]+
  75. w2 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+cx]+
  76. w3 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+fx]+
  77. w4 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+cx];
  78. if( N >= (double)(unsigned char)target->imageData[i*dx+j])
  79. {
  80. result[i*dx+j] = result[i*dx+j] + v * 1;
  81. }else{
  82. result[i*dx+j] = result[i*dx+j] + v * 0;
  83. }
  84. }
  85. }
  86. }
  87. //显示图像
  88. if (num_sp<=8)
  89. {
  90. //只有采样数小于8,则编码范围0-255,才能显示图像
  91. for (i = 0;i<dy;i++)
  92. {
  93. for (j = 0;j<dx;j++)
  94. {
  95. target->imageData[i*dx+j] = (unsigned char)result[i*dx+j];
  96. //printf("%d\n",(unsigned char)target->imageData[i*width+j]);
  97. }
  98. }
  99. cvSaveImage("result.jpg",target);
  100. }
  101. //显示直方图
  102. for (i=0;i<cols;i++)
  103. {
  104. val_hist[i]=0.0;
  105. }
  106. for (i=0; i<dy*dx;i++)
  107. {
  108. val_hist[result[i]]++;
  109. }
  110. double temp_max=0.0;
  111. for (i=0;i<cols;i++)         //求直方图最大值,为了归一化
  112. {
  113. //printf("%f\n",val_hist[i]);
  114. if (temp_max<val_hist[i])
  115. {
  116. temp_max=val_hist[i];
  117. }
  118. }
  119. //画直方图
  120. CvPoint p1,p2;
  121. double bin_width=(double)hist->width/cols;
  122. double bin_unith=(double)hist->height/temp_max;
  123. for (i=0;i<cols;i++)
  124. {
  125. p1.x=i*bin_width;p1.y=hist->height;
  126. p2.x=(i+1)*bin_width;p2.y=hist->height-val_hist[i]*bin_unith;
  127. cvRectangle(hist,p1,p2,cvScalar(0,255),-1,8,0);
  128. }
  129. cvSaveImage("hist.jpg",hist);
  130. }

实验结果:

3.2 旋转不变性:

[cpp] view plaincopy
  1. void rotation_invariant_mapping(int range,int num_sp,int *Mapping)
  2. {
  3. int newMax,rm,r;
  4. int *tmpMap;
  5. newMax = 0;
  6. tmpMap = (int *)malloc(sizeof(int)*range);
  7. memset(tmpMap,-1,sizeof(int)*range);
  8. for (int i = 0 ; i < range ; i++)
  9. {
  10. rm = i;
  11. r = i;
  12. for (int j = 0 ; j < num_sp -1 ;j++)
  13. {
  14. //将r向左循环移动一位,当r超过num_sp位时,舍弃
  15. r = r << 1;
  16. if (r > range -1)
  17. {
  18. r = r - (range -1);
  19. }
  20. //printf("%d,%d\n",r,rm);
  21. if (r < rm)
  22. {
  23. rm = r;
  24. }
  25. }
  26. if (tmpMap[rm] < 0)
  27. {
  28. tmpMap[rm] = newMax;
  29. newMax++;
  30. }
  31. Mapping[i] = tmpMap[rm];
  32. }
  33. free(tmpMap);
  34. }
  35. void rotation_invariant_lbp(IplImage *src,int height,int width,int num_sp,MyPoint *spoint,int *Mapping)
  36. {
  37. IplImage *target,*hist;
  38. int i,j,k,box_x,box_y,orign_x,orign_y,dx,dy,tx,ty,fy,fx,cy,cx,v;
  39. double min_x,max_x,min_y,max_y,w1,w2,w3,w4,N,x,y;
  40. int *result;
  41. float dishu;
  42. dishu = 2.0;
  43. max_x=0;max_y=0;min_x=0;min_y=0;
  44. for (k=0;k<num_sp;k++)
  45. {
  46. if (max_x<spoint[k].x)
  47. {
  48. max_x=spoint[k].x;
  49. }
  50. if (max_y<spoint[k].y)
  51. {
  52. max_y=spoint[k].y;
  53. }
  54. if (min_x>spoint[k].x)
  55. {
  56. min_x=spoint[k].x;
  57. }
  58. if (min_y>spoint[k].y)
  59. {
  60. min_y=spoint[k].y;
  61. }
  62. }
  63. //计算模版大小
  64. box_x = ceil(MAX(max_x,0)) - floor(MIN(min_x,0)) + 1;
  65. box_y = ceil(MAX(max_y,0)) - floor(MIN(min_y,0)) + 1;
  66. if (width<box_x||height<box_y)
  67. {
  68. printf("Too small input image. Should be at least (2*radius+1) x (2*radius+1)");
  69. return;
  70. }
  71. //计算可滤波图像大小,opencv图像数组下标从0开始
  72. orign_x = 0 - floor(MIN(min_x,0));//起点
  73. orign_y = 0 - floor(MIN(min_x,0));
  74. dx = width - box_x+1;//终点
  75. dy = height - box_y+1;
  76. target = cvCreateImage(cvSize(dx,dy),IPL_DEPTH_8U,1);
  77. result = (int *)malloc(sizeof(int)*dx*dy);
  78. memset(result,0,sizeof(int)*dx*dy);
  79. CvRect roi =cvRect(orign_x, orign_y, dx, dy);
  80. cvSetImageROI(src, roi);
  81. cvCopy(src, target);
  82. cvResetImageROI(src);
  83. cvSaveImage("haha.jpg",target);
  84. for ( k = 0; k<num_sp;k++)
  85. {
  86. x = spoint[k].x+orign_x;
  87. y = spoint[k].y+orign_y;
  88. //二线性插值图像
  89. fy = floor(y);  //向下取整
  90. fx = floor(x);
  91. cy = ceil(y);   //向上取整
  92. cx = ceil(x);
  93. ty = y - fy;
  94. tx = x - fx;
  95. w1 = (1 - tx) * (1 - ty);
  96. w2 = tx  * (1 - ty);
  97. w3 = (1 - tx) * ty ;
  98. w4 = tx * ty ;
  99. v = pow(dishu,(float)k);
  100. for (i = 0;i<dy;i++)
  101. {
  102. for (j = 0;j<dx;j++)
  103. {
  104. //灰度插值图像像素
  105. N = w1 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+fx]+
  106. w2 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+cx]+
  107. w3 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+fx]+
  108. w4 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+cx];
  109. if( N >= (double)(unsigned char)target->imageData[i*dx+j])
  110. {
  111. result[i*dx+j] = result[i*dx+j] + v * 1;
  112. }else{
  113. result[i*dx+j] = result[i*dx+j] + v * 0;
  114. }
  115. }
  116. }
  117. }
  118. //将result的值映射为mapping的值
  119. for(i = 0; i < dy ;i++)
  120. {
  121. for (j = 0; j < dx ;j ++)
  122. {
  123. result[i*dx+j] = Mapping[result[i*dx+j]];
  124. }
  125. }
  126. //显示图像
  127. int cols = 0;//直方图的横坐标,也是result数组的元素种类
  128. int mapping_size = pow(dishu,(float)num_sp);
  129. for (i = 0;i < mapping_size; i++ )
  130. {
  131. if (cols < Mapping[i])
  132. {
  133. cols = Mapping[i];
  134. }
  135. }
  136. if (cols < 255)
  137. {
  138. //只有采样数小于8,则编码范围0-255,才能显示图像
  139. for (i = 0;i<dy;i++)
  140. {
  141. for (j = 0;j<dx;j++)
  142. {
  143. target->imageData[i*dx+j] = (unsigned char)result[i*dx+j];
  144. //printf("%d\n",(unsigned char)target->imageData[i*width+j]);
  145. }
  146. }
  147. cvSaveImage("result.jpg",target);
  148. }
  149. //计算直方图
  150. hist = cvCreateImage(cvSize(300,200),IPL_DEPTH_8U,3);//直方图图像
  151. double *val_hist = (double *)malloc(sizeof(double)*cols);   //直方图数组
  152. for (i=0;i<cols;i++)
  153. {
  154. val_hist[i]=0.0;
  155. }
  156. for (i=0; i<dy*dx;i++)
  157. {
  158. val_hist[result[i]]++;
  159. }
  160. double temp_max=0.0;
  161. for (i=0;i<cols;i++)         //求直方图最大值,为了归一化
  162. {
  163. //printf("%f\n",val_hist[i]);
  164. if (temp_max<val_hist[i])
  165. {
  166. temp_max=val_hist[i];
  167. }
  168. }
  169. //画直方图
  170. CvPoint p1,p2;
  171. double bin_width=(double)hist->width/cols;
  172. double bin_unith=(double)hist->height/temp_max;
  173. for (i=0;i<cols;i++)
  174. {
  175. p1.x=i*bin_width;p1.y=hist->height;
  176. p2.x=(i+1)*bin_width;p2.y=hist->height-val_hist[i]*bin_unith;
  177. cvRectangle(hist,p1,p2,cvScalar(0,255),-1,8,0);
  178. }
  179. cvSaveImage("hist.jpg",hist);
  180. }

实验结果:

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

[cpp] view plaincopy
  1. #include "stdafx.h"
  2. #include "cv.h"
  3. #include "highgui.h"
  4. #define  PI 3.1415926
  5. #define MAX(x,y) (x)>(y)?(x):(y)
  6. #define MIN(x,y) (x)<(y)?(x):(y)
  7. typedef struct MyPoint
  8. {
  9. double x;
  10. double y;
  11. }MyPoint;
  12. void calc_position(int radius,int num_sp,MyPoint *spoint)
  13. {
  14. double theta;
  15. theta = 2*PI/num_sp;
  16. for (int i = 0; i < num_sp; i++)
  17. {
  18. spoint[i].y = -radius * sin(i * theta);
  19. spoint[i].x = radius * cos(i * theta);
  20. }
  21. }
  22. int calc_sum(int r)
  23. {
  24. int res_sum;
  25. res_sum = 0;
  26. while (r)
  27. {
  28. res_sum = res_sum + r % 2;
  29. r /= 2;
  30. }
  31. return res_sum;
  32. }
  33. void rotation_uniform_invariant_mapping(int range,int num_sp,int *Mapping)
  34. {
  35. int numt,i,j,tem_xor;
  36. numt = 0;
  37. tem_xor = 0;
  38. for (i = 0; i< range; i++)
  39. {
  40. j = i << 1;
  41. if (j > range -1)
  42. {
  43. j = j - (range -1);
  44. }
  45. tem_xor = i ^ j;    // 异或
  46. numt = calc_sum(tem_xor);//计算异或结果中1的个数,即跳变个数
  47. if (numt <= 2)
  48. {
  49. Mapping[i] = calc_sum(i);
  50. }else{
  51. Mapping[i] = num_sp+1;
  52. }
  53. }
  54. }
  55. void rotation_uniform_invariant_lbp(IplImage *src,int height,int width,int num_sp,MyPoint *spoint,int *Mapping)
  56. {
  57. IplImage *target,*hist;
  58. int i,j,k,box_x,box_y,orign_x,orign_y,dx,dy,tx,ty,fy,fx,cy,cx,v;
  59. double min_x,max_x,min_y,max_y,w1,w2,w3,w4,N,x,y;
  60. int *result;
  61. float dishu;
  62. dishu = 2.0;
  63. max_x=0;max_y=0;min_x=0;min_y=0;
  64. for (k=0;k<num_sp;k++)
  65. {
  66. if (max_x<spoint[k].x)
  67. {
  68. max_x=spoint[k].x;
  69. }
  70. if (max_y<spoint[k].y)
  71. {
  72. max_y=spoint[k].y;
  73. }
  74. if (min_x>spoint[k].x)
  75. {
  76. min_x=spoint[k].x;
  77. }
  78. if (min_y>spoint[k].y)
  79. {
  80. min_y=spoint[k].y;
  81. }
  82. }
  83. //计算模版大小
  84. box_x = ceil(MAX(max_x,0)) - floor(MIN(min_x,0)) + 1;
  85. box_y = ceil(MAX(max_y,0)) - floor(MIN(min_y,0)) + 1;
  86. if (width<box_x||height<box_y)
  87. {
  88. printf("Too small input image. Should be at least (2*radius+1) x (2*radius+1)");
  89. return;
  90. }
  91. //计算可滤波图像大小,opencv图像数组下标从0开始
  92. orign_x = 0 - floor(MIN(min_x,0));//起点
  93. orign_y = 0 - floor(MIN(min_x,0));
  94. dx = width - box_x+1;//终点
  95. dy = height - box_y+1;
  96. target = cvCreateImage(cvSize(dx,dy),IPL_DEPTH_8U,1);
  97. result = (int *)malloc(sizeof(int)*dx*dy);
  98. memset(result,0,sizeof(int)*dx*dy);
  99. CvRect roi =cvRect(orign_x, orign_y, dx, dy);
  100. cvSetImageROI(src, roi);
  101. cvCopy(src, target);
  102. cvResetImageROI(src);
  103. cvSaveImage("haha.jpg",target);
  104. for ( k = 0; k<num_sp;k++)
  105. {
  106. x = spoint[k].x+orign_x;
  107. y = spoint[k].y+orign_y;
  108. //二线性插值图像
  109. fy = floor(y);  //向下取整
  110. fx = floor(x);
  111. cy = ceil(y);   //向上取整
  112. cx = ceil(x);
  113. ty = y - fy;
  114. tx = x - fx;
  115. w1 = (1 - tx) * (1 - ty);
  116. w2 = tx  * (1 - ty);
  117. w3 = (1 - tx) * ty ;
  118. w4 = tx * ty ;
  119. v = pow(dishu,(float)k);
  120. for (i = 0;i<dy;i++)
  121. {
  122. for (j = 0;j<dx;j++)
  123. {
  124. //灰度插值图像像素
  125. N = w1 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+fx]+
  126. w2 * (double)(unsigned char)src->imageData[(i+fy)*src->width+j+cx]+
  127. w3 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+fx]+
  128. w4 * (double)(unsigned char)src->imageData[(i+cy)*src->width+j+cx];
  129. if( N >= (double)(unsigned char)target->imageData[i*dx+j])
  130. {
  131. result[i*dx+j] = result[i*dx+j] + v * 1;
  132. }else{
  133. result[i*dx+j] = result[i*dx+j] + v * 0;
  134. }
  135. }
  136. }
  137. }
  138. //将result的值映射为mapping的值
  139. for(i = 0; i < dy ;i++)
  140. {
  141. for (j = 0; j < dx ;j ++)
  142. {
  143. result[i*dx+j] = Mapping[result[i*dx+j]];
  144. }
  145. }
  146. //显示图像
  147. int cols = 0;//直方图的横坐标,也是result数组的元素种类
  148. int mapping_size = pow(dishu,(float)num_sp);
  149. for (i = 0;i < mapping_size; i++ )
  150. {
  151. if (cols < Mapping[i])
  152. {
  153. cols = Mapping[i];
  154. }
  155. }
  156. if (cols < 255)
  157. {
  158. //只有采样数小于8,则编码范围0-255,才能显示图像
  159. for (i = 0;i<dy;i++)
  160. {
  161. for (j = 0;j<dx;j++)
  162. {
  163. target->imageData[i*dx+j] = (unsigned char)result[i*dx+j];
  164. //printf("%d\n",(unsigned char)target->imageData[i*width+j]);
  165. }
  166. }
  167. cvSaveImage("result.jpg",target);
  168. }
  169. //计算直方图
  170. hist = cvCreateImage(cvSize(300,200),IPL_DEPTH_8U,3);//直方图图像
  171. double *val_hist = (double *)malloc(sizeof(double)*cols);   //直方图数组
  172. for (i=0;i<cols;i++)
  173. {
  174. val_hist[i]=0.0;
  175. }
  176. for (i=0; i<dy*dx;i++)
  177. {
  178. val_hist[result[i]]++;
  179. }
  180. double temp_max=0.0;
  181. for (i=0;i<cols;i++)         //求直方图最大值,为了归一化
  182. {
  183. //printf("%f\n",val_hist[i]);
  184. if (temp_max<val_hist[i])
  185. {
  186. temp_max=val_hist[i];
  187. }
  188. }
  189. //画直方图
  190. CvPoint p1,p2;
  191. double bin_width=(double)hist->width/cols;
  192. double bin_unith=(double)hist->height/temp_max;
  193. for (i=0;i<cols;i++)
  194. {
  195. p1.x=i*bin_width;p1.y=hist->height;
  196. p2.x=(i+1)*bin_width;p2.y=hist->height-val_hist[i]*bin_unith;
  197. cvRectangle(hist,p1,p2,cvScalar(0,255),-1,8,0);
  198. }
  199. cvSaveImage("hist.jpg",hist);
  200. }
  201. int _tmain(int argc, _TCHAR* argv[])
  202. {
  203. IplImage *src,*grey,*result;
  204. int samples,radius,range,*mapping;
  205. MyPoint *spoint;
  206. float Mi;
  207. samples = 8;
  208. radius = 10;
  209. Mi = 2.0;
  210. range = pow(Mi,samples);
  211. src = cvLoadImage("test2.jpg");
  212. grey = cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
  213. cvCvtColor(src,grey,CV_BGR2GRAY);
  214. mapping = (int *)malloc(sizeof(int)*range);
  215. memset(mapping,0,sizeof(int)*range);
  216. //计算采样点相对坐标
  217. spoint = (MyPoint *)malloc(sizeof(MyPoint)*samples);
  218. calc_position(radius,samples,spoint);
  219. //计算灰度不变性LBP特征,写回浮点数图像矩阵中
  220. //gray_invariant_lbp(grey,src->height,src->width,samples,spoint);
  221. //计算旋转不变形LBP特征
  222. //rotation_invariant_mapping(range,samples,mapping);
  223. //rotation_invariant_lbp(grey,src->height,src->width,samples,spoint,mapping);
  224. //计算旋转不变等价LBP特征
  225. rotation_uniform_invariant_mapping(range,samples,mapping);
  226. rotation_uniform_invariant_lbp(grey,src->height,src->width,samples,spoint,mapping);
  227. return 0;
  228. }

实验结果:

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

灰度不变性LBP( gray scale invariant) 旋转不变性LBP(rotation invariant)旋转不变等价LBP(rotation uniform invarian )相关推荐

  1. 局部二值模式(Local Binary Patterns)纹理灰度与旋转不变性

    Multiresolution Gray Scale and Rotation Invariant Texture Classification with Local Binary Patterns, ...

  2. LBP特征提取算子光照不变性和旋转不变性的具体解释与detectMultiScale参数说明【DataWhale学习记录】

    零 前言 LBP曾广泛应用于人脸检测以及人脸识别应用中,但在深度学习和卷积神经网络迅猛发展的今天,以LBP为特征的检测以及识别算法并不具有竞争力,但是作为学习案例还是很有借鉴意义的. 本文的重点部分是 ...

  3. ORB2单目读代码笔记5--利用灰度质心计算ORB特征点方向,实现旋转不变性

    5.利用灰度质心计算ORB特征点方向,实现旋转不变性 ComputeKeyPointOctTree 跳转 computeOrientation computeOrientation 跳转 IC_Ang ...

  4. 图像特征提取中的一些不变形,平移不变性,旋转不变性 光照不变性

    不变性:就是目标发生了变换,但是你依然可以识别出来. 在图像任务中,我们希望图像中的目标即使被平移.被旋转或者被缩放,模型都可以识别出来. 主要有以下几种不变性: 平移不变性 旋转不变性 尺度不变性 ...

  5. 【论文速递】“基于自适应辐射环编码柱状图大尺度和旋转不变性的模板匹配”

    本文用以记录研究僧生涯课题相关内容,主要是对论文进行翻译,再次对论文作者表示尊敬! 本篇论文在模板匹配方向取得了很不错的成果,可惜的是没有开源` 论文题目: Pattern recognition 2 ...

  6. 用机器学习的分类算法识别象棋棋子——兼论旋转不变性

    文章目录 1. 前言 2. 图像的矩特征 3. 采集样本 4. 模型训练 5. 模型应用 1. 前言 文本识别早已经不是问题了,不过却不能直接应用于象棋棋子的识别,因为棋盘上的棋子是随机摆放上去的,不 ...

  7. 一个与神经网络分类特征旋转不变性有关的实验

    继续用<用神经网络分类两条夹角为θ的直线>的办法分类两条直线. y=x*tanθ和y=x*tan(θ+20) 所不同的是这次让两条直线之间的夹角固定为20,让θ分别等于0,20...340 ...

  8. 深度学习中不变性是什么?平移不变性Translation Invariance、旋转/视角不变性Ratation/Viewpoint Invariance、尺度不变性Size、Illumination

    文章目录 不变性定义 不变性分类 为什么卷积神经网络具有平移不变性 不变性定义 意味着即使目标的外观发生了某种变化,但是你依然可以把它识别出来.这对图像分类来说是一种很好的特性,因为我们希望图像中目标 ...

  9. 图像特征提取中的平移不变性、旋转不变性、尺度不变性

    1.平移不变性是指对象的特征在平移变换下保持不变,不受平移的影响.实现平移不变性的方法可以是将对象的特征点相对于其中一个点的距离作为特征表示,这样就可以保证在平移变换下该距离不变. 2.旋转不变性是指 ...

最新文章

  1. 宁可寸寸断,不意绕指柔
  2. danfoss 变频器的profinet通讯调试_840D sl系统PLC 开机调试
  3. mysql generic安装_MySQL 5.6 Generic Binary安装与配置
  4. testng提供的Assert类断言使用
  5. 最优乘车pascal程序
  6. pmp每日三题(2022年2月21日)
  7. Oracle SQL Trace 和 10046 事件 .
  8. Hangfire 任务调度
  9. Asp.net MVC3.0 基于不同的角色显示不同的菜单
  10. Java的注解机制——Spring自动装配的实现原理
  11. Git submodule 的笔记
  12. 用webstorm自动编译less产出css和sourcemap
  13. js 难点之call,apply实现
  14. rango php,韩天峰(Rango)的博客
  15. [转载] 嵌入式文件系统
  16. python之地基(一)
  17. 三菱mode bus tcp通讯_邢台三菱MR-J4-200B4
  18. 装机人员常用软件工具大全
  19. 关注程序员健康,使用中医十二经络来解释一个神奇的梦境!
  20. 泛泰binx和ota升级包下载工具Android版[2013.6.7提供源代码]

热门文章

  1. 干货|一文读懂中国7大支付体系(附27页流程图)
  2. PowerMock 简介--转载
  3. c# webservice生成客户端及使用时碰到decimal类型时的特殊处理
  4. Vue 里的$如何理解
  5. 揭秘高效协作工具背后的技术架构
  6. jvm性能调优实战 -56没有WHERE条件的SQL语句引发的OOM MAT 排查步骤
  7. Apache Kafka-事务消息的支持与实现(本地事务)
  8. 60进制计算器在线_超长假期用华为MatePad Pro在线听课是怎样的体验?
  9. Python的setuptools详解【1】
  10. php网站添加cnzz,cnzz代码添加元素到页面