当前位置:   article > 正文

一种动态阈值白平衡算法实现_opencv 白平衡 动态阈值算法 c++

opencv 白平衡 动态阈值算法 c++

一种自动阈值白平衡算法实现

1.算法原理

     白平衡是图像处理的一个极重要概念。所谓白平衡(英文名称为White Balance),就是对白色物体的还原。当我们用肉眼观看这大千世界时,在不同的光线下,对相同的颜色的感觉基本是相同的,比如在早晨旭日初升时,我们看一个白色的物体,感到它是白的;而我们在夜晚昏暗的灯光下,看到的白色物体,感到它仍然是白的。这是由于人类从出生以后的成长过程中,人的大脑已经对不同光线下的物体的彩色还原有了适应性。但是,作为拍摄设备,如数码相机,可没有人眼的适应性,在不同的光线下,由于CCD输出的不平衡性,造成数码相机彩色还原失真。一般情况下,我们习惯性地认为太阳光是白色的,已知直射日光的色温是5200K左右,白炽灯的色温是3000K左右。用传统相机的日光片拍摄时,白炽灯光由于色温太低,所以偏黄偏红。所以通常现场光线的色温低于相机设定的色温时,往往偏黄偏红,现场光线的色温高于相机设定时,就会偏蓝。

     为了解决不同色温下,引起的白色漂移现象。由于白色对色温变化的响应最大,通常用白色来作为调整的基色。通常的白平衡技术有:自动白平衡、钨光白平衡、荧光白平衡、室内白平衡、手动调节。本文仅介绍其中的一种自动白平衡。

     白平衡算法通常分为两步:白色点的检测,白色点的调整。本方法采用一个动态的阀值来检测白色点。详细算法过程为:

          1.  把图像w*h从RGB空间转换到YCrCb空间。

          2.  选择参考白色点:

                    a. 把图像分成宽高比为4:3个块(块数可选)。

                    b. 对每个块,分别计算Cr,Cb的平均值Mr,Mb。

                    c. 对每个块,根据Mr,Mb,用下面公式分别计算Cr,Cb的方差Dr,Db。


                    d. 判定每个块的近白区域(near-white region)。

                        判别表达式为:


                        设一个“参考白色点”的亮度矩阵RL,大小为w*h。

                         若符合判别式,则作为“参考白色点”,并把该点(i,j)的亮度(Y分量)值赋给RL(i,j);

                         若不符合,则该点的RL(i,j)值为0。

         3.  选取参考“参考白色点”中最大的10%的亮度(Y分量)值,并选取其中的最小值Lu_min.

         4.  调整RL,若RL(i,j)<Lu_min,  RL(i,j)=0; 否则,RL(i,j)=1;

         5.  分别把R,G,B与RL相乘,得到R2,G2,B2。  分别计算R2,G2,B2的平均值,Rav,Gav,Bav;

         6.  得到调整增益:  Ymax=double(max(max(Y)))/5;
                                    Rgain=Ymax/Rav;
                                    Ggain=Ymax/Gav;
                                    Bgain=Ymax/Bav;

        7.  调整原图像:Ro= R*Rgain; Go= G*Ggain; Bo= B*Bgain;

2.关键实现代码

  1. int RGB2YCbCr(IMAGE_TYPE *bmp_img,T_U8*Y_img,double *Cb_img,double *Cr_img,DWORD width,DWORD height)
  2. {
  3. T_U32 lineByte,Source_linebyte,source_index,dst_index;
  4. T_U16 i,j,Y;
  5. T_U16 k = 0;
  6. T_U8 *Source_img,R,G,B;
  7. double Cr;
  8. double Cb;
  9. lineByte = (width * 8 / 8 + 3) / 4 * 4;
  10. Source_img = bmp_img+54;
  11. Source_linebyte = WIDTHBYTES(width*24);
  12. for (i = 0; i < height;i++)
  13. {
  14. for (j = 0;j < width;j++)
  15. {
  16. source_index = Source_linebyte*i+3*j;
  17. dst_index = lineByte*i+j;
  18. R = Source_img[source_index+2];
  19. G = Source_img[source_index+1];
  20. B = Source_img[source_index];
  21. Y = 0.299*R+0.587*G+0.114*B;
  22. Cr = 0.5*R-0.419*G-0.081*B;
  23. Cb = -0.169*R-0.331*G+0.5*B;
  24. Y_img[dst_index] = (T_U8)Y;
  25. Cr_img[dst_index] = Cr;
  26. Cb_img[dst_index] = Cb;
  27. }
  28. }
  29. return 0;
  30. }
  31. int AutoWhiteBalance_Optimi(IMAGE_TYPE *bmp_img,DWORD width,DWORD height)
  32. {
  33. T_U8*Y_img,*Ydata_img,*SignData,R,G,B,*bmp_data,*Dstbmp_img,*Dstbmp_data;
  34. T_U16 height_step = height/3,witdth_step = width/4;
  35. DWORD PixNum = height_step*witdth_step,i,j,m,n,Threshold =0,YLumi[256] = {0};
  36. DWORD line_width,source_line_width,source_index,CbCr_indx,index,WhitePoint = 0,WhitePointCount = 0,WhitePoint10 = 0;
  37. int arrindex=0,YMax = -999;
  38. double Mr,Mb,Dr,Db,b1,b2,b,c,*Cb_img,*Cr_img,*Cbdata_img,*Crdata_img;
  39. double MeanSumr,MeanSumb;
  40. double absSumr,absSumb,Rave,Gave,Bave,RGain,GGain,BGain;
  41. FILE *AutoWhiteBalance_fp = fopen("AutoBalance.bmp","wb");
  42. if(NULL == AutoWhiteBalance_fp)
  43. {
  44. printf("Can't open AutoBalance.bmp\n");
  45. return -1;
  46. }
  47. line_width = (width * 8 / 8 + 3) / 4 * 4; //8位深的BMP图像输入图像
  48. source_line_width = ((width * 24 / 8 + 3) / 4 * 4 );
  49. Cb_img = (double*)malloc(width*height*sizeof(double));
  50. Cr_img = (double*)malloc(width*height*sizeof(double));
  51. Y_img = (T_U8*)malloc(line_width*height);
  52. Dstbmp_img = (T_U8*)malloc(source_line_width*height+BMPHEADSIZE);
  53. SignData = (T_U8*)malloc(line_width*height);
  54. memcpy(Dstbmp_img,bmp_img,source_line_width*height+BMPHEADSIZE);
  55. RGB2YCbCr(bmp_img,Y_img,Cb_img,Cr_img,width,height);
  56. Cbdata_img = Cb_img;
  57. Crdata_img = Cr_img;
  58. Ydata_img = Y_img;
  59. WhitePoint = 0;
  60. for (i= 0;i < height; i += height_step)
  61. {
  62. for (j = 0; j <width; j += witdth_step)
  63. {
  64. Mb = 0;
  65. Mr = 0;
  66. MeanSumr = 0;
  67. MeanSumb = 0;
  68. absSumr = 0;
  69. absSumb = 0;
  70. for (m = 0; m < height_step;m++)
  71. {
  72. for (n = 0; n <witdth_step;n++)
  73. {
  74. index = (m+i)*width+n+j;
  75. MeanSumr += (Crdata_img[index]);
  76. MeanSumb += (Cbdata_img[index]);
  77. }
  78. }
  79. //计每个块Cb,Cr的均值
  80. Mr = MeanSumr/(double)PixNum;
  81. Mb = MeanSumb/(double)PixNum;
  82. for (m = 0; m < height_step;m++)
  83. {
  84. for (n = 0; n <witdth_step;n++)
  85. {
  86. index = (m+i)*width+n+j;
  87. absSumr += abs(Crdata_img[index]-Mr);
  88. absSumb += abs(Cbdata_img[index]-Mb);
  89. }
  90. }
  91. //计算每个块绝对差累加值
  92. Dr = absSumr / PixNum;
  93. Db = absSumb / PixNum;
  94. if (Mb<0)//计算mb+db*sign(mb)
  95. {
  96. b=Mb+Db*(-1);
  97. }
  98. else
  99. b=Mb+Db;
  100. if (Mr<0)//计算1.5*mr+dr*sign(mb);
  101. {
  102. c=1.5*Mr+Dr*(-1);
  103. }
  104. else
  105. c=1.5*Mr+Dr;
  106. //候选白点像素计算
  107. for (m = 0; m < height_step;m++)
  108. {
  109. for (n = 0; n <witdth_step;n++)
  110. {
  111. index =(m+i)*line_width+n+j;
  112. CbCr_indx = (m+i)*width+n+j;
  113. if(abs(Cbdata_img[CbCr_indx]-b)<(1.5*Db) && abs(Crdata_img[CbCr_indx]-c)<(1.5*Dr))
  114. {
  115. YLumi[Ydata_img[index]]++;
  116. SignData[index] = Ydata_img[index];
  117. WhitePoint++;
  118. }
  119. }
  120. }
  121. }
  122. }
  123. //选取候选白点数的最亮10%确定为最终白点,并选择其前10%中的最小亮度值
  124. WhitePointCount = 0;
  125. for(i = 255; i >0; i--)
  126. {
  127. WhitePointCount += YLumi[i];
  128. if(WhitePointCount >= (double)WhitePoint/10)
  129. {
  130. Threshold = i;
  131. break;
  132. }
  133. }
  134. WhitePoint10 = 0;
  135. for(i = 0; i < height;i++)
  136. {
  137. for(j = 0;j < width;j++)
  138. {
  139. index = i*line_width+j;
  140. if(SignData[index] >= Threshold)
  141. {
  142. SignData[index] = 1;
  143. WhitePoint10++;
  144. }
  145. else
  146. SignData[index] = 0;
  147. }
  148. }
  149. bmp_data = bmp_img+54;
  150. Dstbmp_data = Dstbmp_img + 54;
  151. Rave = 0;
  152. Gave = 0;
  153. Bave = 0;
  154. //白点的RGB三分量的平均值
  155. for(i = 0;i < height;i++)
  156. {
  157. for(j = 0; j <width;j++)
  158. {
  159. source_index = i*source_line_width+3*j;
  160. index = i*line_width+j;
  161. Dstbmp_data[source_index+0] = bmp_data[source_index]*SignData[index];
  162. Dstbmp_data[source_index+1] = bmp_data[source_index+1]*SignData[index];
  163. Dstbmp_data[source_index+2] = bmp_data[source_index+2]*SignData[index];
  164. Rave += Dstbmp_data[source_index+2];
  165. Gave += Dstbmp_data[source_index+1];
  166. Bave += Dstbmp_data[source_index+0];
  167. }
  168. }
  169. Rave = Rave / (WhitePoint10);
  170. Gave = Gave / (WhitePoint10);
  171. Bave = Bave / (WhitePoint10);
  172. for(i = 0; i < height;i++)
  173. {
  174. for(j = 0; j < width;j++)
  175. {
  176. index = i*line_width+j;
  177. if(YMax < Ydata_img[index])
  178. YMax = Ydata_img[index];
  179. }
  180. }
  181. //增益调整
  182. YMax = YMax / 3.0;
  183. RGain = YMax / Rave;
  184. GGain = YMax / Gave;
  185. BGain = YMax / Bave;
  186. //白平衡校正
  187. for(i = 0; i <height; i++)
  188. {
  189. for(j = 0; j < width;j++)
  190. {
  191. source_index = i*source_line_width+3*j;
  192. bmp_data[source_index] = (T_U8)(BGain* bmp_data[source_index]);
  193. bmp_data[source_index+1] = (T_U8)(GGain* bmp_data[source_index+1]);
  194. bmp_data[source_index+2] = (T_U8)(RGain* bmp_data[source_index+2]);
  195. }
  196. }
  197. fwrite(bmp_img, source_line_width*height+BMPHEADSIZE, 1, AutoWhiteBalance_fp);
  198. fclose(AutoWhiteBalance_fp);
  199. free(Cb_img);
  200. free(Cr_img);
  201. free(Y_img);
  202. return 0;
  203. }

3.图像效果

A色温校正对比图


TL84色温校正对比图


D65色温校正对比图



参考文献:

1.http://www.cnblogs.com/haar/articles/1392227.html

2.基于灰度世界、完美反射、动态阈值等图像自动白平衡算法的原理、实现及效果

3.https://www.cnblogs.com/Imageshop/archive/2013/04/20/3032062.html




声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/287408
推荐阅读
相关标签
  

闽ICP备14008679号