一种简单的自动白平衡算法

                             一种简单的自动白平衡算法

目录

                   一种简单的自动白平衡算法

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

2. 基本原理

4. 直方图法

5.直方图法关键代码

6.直方图法图像效果

7. 排序法

8. 排序法效果图


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

 

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

 

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

    故上述公式可以改写为:

 

   实现原理图如下:

一种简单的自动白平衡算法_第1张图片

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

 

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

    其原理图如下所示:

一种简单的自动白平衡算法_第2张图片

 

 

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。然后再进行像素值得映射。

4. 直方图法

    算法实现的伪代码为:

一种简单的自动白平衡算法_第3张图片

5.直方图法关键代码

 

/*
*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=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\n");
        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\n");
        fprintf(stderr, "using (size - 1) / 2\n");
    }

	/* 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\n");
		return EXIT_FAILURE;
	}

	if (0. > smin || 100. <= smin || 0. > smax || 100. <= smax) {
        fprintf(stderr, "the saturation percentages must be in [0-100[\n");
        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 

 

 

6.直方图法图像效果

一种简单的自动白平衡算法_第4张图片一种简单的自动白平衡算法_第5张图片

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

一种简单的自动白平衡算法_第6张图片一种简单的自动白平衡算法_第7张图片

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

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

一种简单的自动白平衡算法_第8张图片一种简单的自动白平衡算法_第9张图片

彩色图像的对比度提升

一种简单的自动白平衡算法_第10张图片一种简单的自动白平衡算法_第11张图片

灰度图像的对比图提升

7. 排序法

 #simple color balance
def simple_color_balance(input_img,out_img,s1,s2):
    h,w = input_img.shape[:2]
    sort_img = input_img.copy()
    one_dim_array = sort_img.flatten()#转化为一维数组
    sort_array = sorted(one_dim_array)#对一维数组按升序排序

    per1 = int((h*w)*s1/100)
    minvalue = sort_array[per1]

    per2 = int((h*w)*s2/100)
    maxvalue = sort_array[(h*w)-1-per2]

    #实施简单白平衡算法
    if(maxvalue<=minvalue):
        for i in range(h):
            for j in range(w):
                out_img[i,j] = maxvalue
    else:
        scale = 255.0/(maxvalue-minvalue)
        for m in range(h):
            for n in range(w):
                if(input_img[m,n] < minvalue):
                    out_img[m,n] = 0
                elif(input_img[m,n] > maxvalue):
                    out_img[m, n] = 255
                else:
                    out_img[m, n] = scale*(input_img[m,n]-minvalue)#映射中间段的图像像素
    out_img = cv2.convertScaleAbs(out_img)


if __name__ == '__main__':
    img = cv2.imread("math_book.png")
    h,w = img.shape[:2]
    out_img_B = zeros((h,w),dtype = uint8)
    out_img_G = zeros((h, w), dtype=uint8)
    out_img_R = zeros((h, w), dtype=uint8)

    B = img[:,:,0]
    G = img[:,:,1]
    R = img[:,:,2]

    simple_color_balance(B, out_img_B,2,3)
    simple_color_balance(G, out_img_G, 2, 3)
    simple_color_balance(R, out_img_R, 2, 3)

    out = cv2.merge([out_img_B, out_img_G, out_img_R])

    cv2.namedWindow("original image")
    cv2.namedWindow("simple color balance image")
    cv2.namedWindow("Compare image")

    cv2.imshow("original image", img)
    cv2.imshow("simple color balance image", out)
    cv2.imshow("Compare image",hstack((img,out)))

    cv2.imwrite("simple_color_balance_math_book.png", out)
    cv2.w

8. 排序法效果图

一种简单的自动白平衡算法_第12张图片

一种简单的自动白平衡算法_第13张图片

一种简单的自动白平衡算法_第14张图片

参考文献:

simple white balance

Principles of Digital Image Processing-Fundamental Techniques

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(图像基础算法处理)