自动白平衡算法

编程实验

72人已加入

描述

 

  前言

  计算机图像处理技术已经广泛的应用于人们的日常生活当中,自动白平衡是计算机图像处理当中的一个重要技术,不同的白平衡算法根据不同的预设校正基准从原始偏色图像中得到图像的偏色信息,然后根据计算所得的偏色信息对图像进行校正恢复。自动白平衡算法主要应用在数码设备白平衡系统、扫描仪偏色图像校正以及计算机图像处理软件当中。在A0幅面平台彩色扫描仪中,由于扫描光照环境不标准、CCD头感光器件的光感参数偏差等原因,都会使扫描所得的数字图像色彩出现偏差。

  1.预备知识-----自动对比度调整原理

  自动对比度调整的方法中,我们假设alow和ahight为单前图像中的最小值和最大值,需要映射的范围为[amin,amax],为了使得图像映射到整个映射范围,我们首先把最小值alow映射到0,之后用比例因子(amax-amin)/(ahigh-alow)增加其对比度,随后加上amin使得计算出来的值映射到需要的映射范围。其具体公式为:

   白平衡算法

  对于8bit图像而言,amin = 0,amax = 255。

  故上述公式可以改写为:

   白平衡算法

  实现原理图如下:

 白平衡算法

  实际的图像中,上述的映射函数容易受到个别极暗或及亮像素的影响,导致映射可能出现错误。为了避免这种错误,我们选取较低像素和较亮像素的一定比例qlow,qhigh,并根据此比例重新计算alow和ahigh,以重新计算的alow和ahigh为原始的图像的亮度范围进行映射。我们可以通过累计直方图H(i)很方便的计算出最新的alow和ahigh。

 白平衡算法

  其中,0《=qlow ,qhigh《=1,qlow+qhigh《=1,M*N为图像的像素数量。

  其原理图如下所示:

 白平衡算法

  2. 基本原理

  这种简单的白平衡算法是基于这么一种假设:图像中R、G、B最高灰度值对应于图像中的白点,最低灰度值的对应于图像中最暗的点。这种算法类似于自动对比度增强的方法,使用映射函数ax+b,尽可能的把彩色图像中R、G、B三个通道内的像素灰度值映射到[0.255]的范围内。由于一般图像中已经有很多图像的灰度值已经在[0,255]范围内(对应24bit BMP图像而言,每个通道内的像素都在此范围内。但是对于每个像素用16bit或更高的32bit表示的话,需要进过上述的映射方法,把像素灰度值映射到[0,255]范围内),因此,这种方法选取较高亮度的像素一定比例赋予255,选取较暗亮度的像素的一定比例赋予0。

  具体实现方法:

  1.排序。为了获取高亮度一定比例像素和较低亮度的一定比例像素,不要对整个图像的灰度值进行排序,方便选择对应的像素。

  2.从排序的像素数组中选取一定比例的高亮和较暗像素。假设s = s1+s2 =[0,100],我们需要选取N*S/100个像素。其中Vmin和Vmax应该选择位于排序后数组的位置为N*S1 /100和N(1-*S2/100)-1处的像素灰度值。

  3.填充像素。由上一步定义的Vmin和Vmax,把原始图像中低于或等于Vmin的像素灰度值赋予0;把原始像素中高于或等于Vmax的像素灰度值赋予255。

  4.映射像素灰度值。使用函数f(x) =(x-Vmin)*(max-min)/(Vmax-Vmin)把原始图像中位于(Vmin,Vmax)的像素映射到[0,255]范围内。其中min,max分别为0和255。

  当图像较大的时候,图像的像素可达到百万级,对这么大数量的像素进行排序,往往效率比较低。另外一种方法可以像上述自动对比度调整那样,建立一个256大小的数组,再以数组中N*S1/100和N(1-*S2/100)-1处的像素灰度值赋予Vmin和Vma。然后再进行像素值得映射。

  算法实现的伪代码为:

 白平衡算法

  3.关键代码

  /*

  *Function: 一种简单的图像白平衡算法--对比度增强

  */

  void quantiles_u8(const T_U8 *data, size_t img_size,

  size_t nb_min, size_t nb_max,

  T_U8*ptr_min,T_U8 *ptr_max)

  {

  /*

  * the histogram must hold all possible “unsigned char” values,

  * including 0

  */

  size_t h_size = UCHAR_MAX + 1;

  size_t histo[UCHAR_MAX + 1];

  size_t i;

  /* make a cumulative histogram */

  memset(histo, 0x00, h_size * sizeof(size_t));

  for (i = 0; i 《 img_size; i++)

  histo[(size_t) data[i]] += 1;

  for (i = 1; i 《 h_size; i++)

  histo[i] += histo[i - 1];

  /* get the new min/max */

  if (NULL != ptr_min) {

  /* simple forward traversal of the cumulative histogram */

  /* search the first value 》 nb_min */

  i = 0;

  while (i 《 h_size && histo[i] 《= nb_min)

  i++;

  /* the corresponding histogram value is the current cell position */

  *ptr_min = (T_U8) i;

  }

  if (NULL != ptr_max) {

  /* simple backward traversal of the cumulative histogram */

  /* search the first value 《= size - nb_max */

  i = h_size - 1;

  /* i is unsigned, we check i《h_size instead of i》=0 */

  while (i 《 h_size && histo[i] 》 (img_size - nb_max))

  i--;

  /*

  * if we are not at the end of the histogram,

  * get to the next cell,

  * the last (backward) value 》 size - nb_max

  */

  if (i 《 h_size - 1)

  i++;

  *ptr_max = (T_U8) i;

  }

  return;

  }

  void minmax_u8(const T_U8 *data, size_t size,

  T_U8 *ptr_min, T_U8 *ptr_max)

  {

  T_U8 min, max;

  size_t i;

  /* compute min and max */

  min = data[0];

  max = data[0];

  for (i = 1; i 《 size; i++) {

  if (data[i] 《 min)

  min = data[i];

  if (data[i] 》 max)

  max = data[i];

  }

  /* save min and max to the returned pointers if available */

  if (NULL != ptr_min)

  *ptr_min = min;

  if (NULL != ptr_max)

  *ptr_max = max;

  return;

  }

  T_U8 *rescale_u8(T_U8 *data, size_t size,T_U8 min,T_U8 max)

  {

  size_t i;

  if (max 《= min)

  for (i = 0; i 《 size; i++)

  data[i] = UCHAR_MAX / 2;

  else {

  /* build a normalization table */

  T_U8 norm[UCHAR_MAX + 1];

  for (i = 0; i 《 min; i++)

  norm[i] = 0;

  for (i = min; i 《 max; i++)

  /*

  * we can‘t store and reuse UCHAR_MAX / (max - min) because

  * 105 * 255 / 126. -》 212.5, rounded to 213

  * 105 * (double) (255 / 126.) -》 212.4999, rounded to 212

  */

  norm[i] = (T_U8) ((i - min) * UCHAR_MAX

  / (double) (max - min) + .5);

  for (i = max; i 《 UCHAR_MAX + 1; i++)

  norm[i] = UCHAR_MAX;

  /* use the normalization table to transform the data */

  for (i = 0; i 《 size; i++)

  data[i] = norm[(size_t) data[i]];

  }

  return data;

  }

  T_U8 *balance_u8(T_U8* BMP8_data_img,size_t img_size,size_t nb_min, size_t nb_max)

  {

  unsigned char min, max;

  /* sanity checks */

  if (NULL == BMP8_data_img) {

  fprintf(stderr, “a pointer is NULL and should not be so ”);

  abort();

  }

  if (nb_min + nb_max 》= img_size) {

  nb_min = (img_size - 1) / 2;

  nb_max = (img_size - 1) / 2;

  fprintf(stderr, “the number of pixels to flatten is too large ”);

  fprintf(stderr, “using (size - 1) / 2 ”);

  }

  /* get the min/max */

  if (0 != nb_min || 0 != nb_max)

  quantiles_u8(BMP8_data_img,img_size, nb_min, nb_max, &min, &max);

  else

  minmax_u8(BMP8_data_img, img_size, &min, &max);

  (void)rescale_u8(BMP8_data_img, img_size, min, max);

  return BMP8_data_img;

  }

  int Simplest_24bitcolor_balance(IMAGE_TYPE *BMP24_img,DWORD width,DWORD height,float smin,float smax)

  {

  T_U32 lineByte,source_lineByte,source_index,dst_index;

  T_U16 k = 0,i,j;

  T_U8 *dst_Bmp24_img,*dst_BMP24_data,*R_img,*G_img,*B_img;

  int newbiBitCount =8;

  size_t img_size = width*height;

  float nb_min = img_size*smin/100.0,nb_max = img_size*smax/100.0;

  FILE *Simplest_color_balance_BMP8Bit_fp = fopen(“Simplest_24bitcolor_balance.bmp”,“wb”);

  if(NULL == Simplest_color_balance_BMP8Bit_fp)

  {

  printf(“Can’t open Simplest_color_balance.bmp ”);

  return EXIT_FAILURE;

  }

  if (0. 》 smin || 100. 《= smin || 0. 》 smax || 100. 《= smax) {

  fprintf(stderr, “the saturation percentages must be in [0-100[ ”);

  return EXIT_FAILURE;

  }

  lineByte = (width * 8 / 8 + 3) / 4 * 4;

  source_lineByte = ( (width * 24 / 8 + 3) / 4 * 4);

  dst_Bmp24_img = (T_U8*)malloc(source_lineByte*height+BMPHEADSIZE);

  R_img = (T_U8*)malloc(lineByte*height);

  G_img = (T_U8*)malloc(lineByte*height);

  B_img = (T_U8*)malloc(lineByte*height);

  Check_Malloc_TU8_Valid(dst_Bmp24_img);

  Check_Malloc_TU8_Valid(G_img);

  Check_Malloc_TU8_Valid(B_img);

  Check_Malloc_TU8_Valid(R_img);

  memcpy(dst_Bmp24_img,BMP24_img,source_lineByte*height+BMPHEADSIZE);

  dst_BMP24_data = dst_Bmp24_img+BMPHEADSIZE;

  for (i = 0; i 《 height;i++)

  {

  source_index = i*source_lineByte;

  dst_index = i*lineByte;

  for (j = 0; j 《 width;j++)

  {

  R_img[dst_index] = dst_BMP24_data[source_index+2];

  G_img[dst_index] = dst_BMP24_data[source_index+1];

  B_img[dst_index] = dst_BMP24_data[source_index+0];

  source_index += 3;

  dst_index += 1;

  }

  }

  (void)balance_u8(R_img,img_size,(size_t)nb_min,(size_t)nb_max);

  (void)balance_u8(G_img,img_size,(size_t)nb_min,(size_t)nb_max);

  (void)balance_u8(B_img,img_size,(size_t)nb_min,(size_t)nb_max);

  for (i = 0; i 《height;i++)

  {

  source_index = i*source_lineByte;

  dst_index = i*lineByte;

  for (j = 0; j 《width;j++)

  {

  dst_BMP24_data[source_index+2] = R_img[dst_index];

  dst_BMP24_data[source_index+1] = G_img[dst_index];

  dst_BMP24_data[source_index+0] = B_img[dst_index];

  source_index += 3;

  dst_index += 1;

  }

  }

  fwrite(BMP24_img,BMPHEADSIZE, 1, Simplest_color_balance_BMP8Bit_fp);

  fwrite(dst_BMP24_data, source_lineByte*height, 1, Simplest_color_balance_BMP8Bit_fp);

  fclose(Simplest_color_balance_BMP8Bit_fp);

  Simplest_color_balance_BMP8Bit_fp = NULL;

  free(dst_Bmp24_img);

  free(R_img);

  free(G_img);

  free(B_img);

  return 0;

  }
#p##e#

  4.图像效果

 

  A色温白平衡校正前后对比图

   

  TL84色温白平衡校正前后对比图

  如算法原理所述,使用的是类似于自动对比度调整的方法对图像进行白平衡校正。这种方法也能够很好的对比较朦胧的图像进行对比度的调整,提高图像的通透性。

   

  彩色图像的对比度提升

   

  灰度图像的对比图提升

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分