产生原因
方法
代码
GW灰度世界白平衡算法
灰度世界算法(Gray World)是以灰度世界假设为基础的,该假设认为对于一幅有着大量色彩变化的图像, R、 G、 B 三个分量的平均值趋于同一个灰度K。
然后通过k值来求各个通达的增益。
- 直接给定为固定值, 取其各通道最大值的一半,即取为127或128;
- 令 K = (Raver+Gaver+Baver)/3,其中Raver,Gaver,Baver分别表示红、 绿、 蓝三个通道的平均值。
算法的第二步是分别计算各通道的增益:
k = ( B a v g + G a v g + R a v g ) / 3 " role="presentation" style="text-align: center; position: relative;"> - 设定G通道不变,让R和B通道往G通道上靠,即:
R g a i n = R a v e / G a v e " role="presentation" style="text-align: center; position: relative;">
B g a i n = B a v e / G a v e " role="presentation" style="text-align: center; position: relative;">
新的像素的绿色通道不变,红色和蓝色通道通过绿色通道来求
- import cv2 as cv
- import numpy as np
-
- src = cv.imread('test.jpg')
-
- # 求出各个颜色分量的平均值
- b_avg = np.mean(src[:, :, 0])
- g_avg = np.mean(src[:, :, 1])
- r_avg = np.mean(src[:, :, 2])
- # 求出灰度世界的灰度值
- k = (b_avg + g_avg + r_avg)/3
- # 求出各个颜色分量的增益
- b_gain = k / b_avg
- g_gain = k / g_avg
- r_gain = k / r_avg
-
- # 定义一个新的矩阵存放变换后的图像
- src1 = np.zeros(src.shape)
- src1[:, :, 0] = src[:, :, 0] * b_gain
- src1[:, :, 1] = src[:, :, 1] * g_gain
- src1[:, :, 2] = src[:, :, 2] * r_gain
-
- # 计算后类型为浮点数,需要类型转换
- src1 = src1.astype(np.uint8)
-
- # 拼接两张图片,便于观察
- img = np.hstack([src, src1])
- cv.namedWindow('input_image', cv.WINDOW_AUTOSIZE)
- cv.imshow('input_image', img)
- cv.waitKey(0)
- cv.destroyAllWindows()
PR完全反射白平衡算法
图像中最亮的点为白点,那么各个通道的最大值应该趋近白色,可是设定一个K值,如255,那么图像中最两点的值应该趋于255,这样就可以计算出各通道的增益:
- import cv2 as cv
- import numpy as np
-
- src = cv.imread('test.jpg')
-
- # 求出各个颜色分量的增益
- b_gain = 255 / np.max(src[:, :, 0])
- g_gain = 255 / np.max(src[:, :, 1])
- r_gain = 255 / np.max(src[:, :, 2])
-
- # 定义一个新的矩阵存放变换后的图像
- src1 = np.zeros(src.shape)
- src1[:, :, 0] = src[:, :, 0] * b_gain
- src1[:, :, 1] = src[:, :, 1] * g_gain
- src1[:, :, 2] = src[:, :, 2] * r_gain
-
- # 计算后类型为浮点数,需要类型转换
- src1 = src1.astype(np.uint8)
-
- # 拼接两张图片,便于观察
- img = np.hstack([src, src1])
- cv.namedWindow('input_image', cv.WINDOW_AUTOSIZE)
- cv.imshow('input_image', img)
- cv.waitKey(0)
- cv.destroyAllWindows()
通过GW和PR两种算法的正交组合,从而保留两者的优点,具体的算法公式如下:
这是R通道的算法公式,求出u和v然后通过以下公式换算出新的值:
- import cv2 as cv
- import numpy as np
-
- src0 = cv.imread('..//images//NikonD5200_0001_G_AS.png')
- src = src0.astype(np.uint16) # 调整一下数据类型,防止算术运算溢出
-
- # 求出各个颜色分量的平均值
- b_ave = np.mean(src[:, :, 0])
- g_ave = np.mean(src[:, :, 1])
- r_ave = np.mean(src[:, :, 2])
-
- # 各个颜色分量的最大值
- b_max = np.max(src[:, :, 0])
- g_max = np.max(src[:, :, 1])
- r_max = np.max(src[:, :, 2])
-
- # 根据QCGP公式求出系数
- k_ave = (b_ave + g_ave + r_ave)/3
- k_max = (b_max + g_max + r_max)/3
- k_matrix = np.mat([[k_ave], [k_max]])
-
- # 通过矩阵求出B通道的转换矩阵,并计算出新图的B通道
- b_coefficient_matrix = np.mat([[b_ave * b_ave, b_ave],
- [b_max * b_max, b_max]])
- b_conversion_matrix = b_coefficient_matrix.I * k_matrix
-
- b = (src[:, :, 0]).transpose()
- bb = (src[:, :, 0] * src[:, :, 0]).transpose()
- b = np.stack((bb, b), axis=0).transpose()
- b_des = np.dot(b, np.array(b_conversion_matrix))
- b_des = b_des.astype(np.uint8).reshape([280, 471])
-
- # 通过矩阵求出G通道的转换矩阵,并计算出新图的G通道
- g_coefficient_matrix = np.mat([[g_ave * g_ave, g_ave],
- [g_max * g_max, g_max]])
- g_conversion_matrix = g_coefficient_matrix.I * k_matrix
-
- g = (src[:, :, 1]).transpose()
- gg = (src[:, :, 1] * src[:, :, 1]).transpose()
- g = np.stack((gg, g), axis=0).transpose()
- g_des = np.dot(g, np.array(g_conversion_matrix))
- g_des = g_des.astype(np.uint8).reshape([280, 471])
-
- # 通过矩阵求出R通道的转换矩阵,并计算出新图的R通道
- r_coefficient_matrix = np.mat([[r_ave * r_ave, r_ave],
- [r_max * r_max, r_max]])
- r_conversion_matrix = r_coefficient_matrix.I * k_matrix
-
- r = (src[:, :, 2]).transpose()
- rr = (src[:, :, 2] * src[:, :, 2]).transpose()
- r = np.stack((rr, r), axis=0).transpose()
- r_des = np.dot(r, np.array(r_conversion_matrix))
- r_des = r_des.astype(np.uint8).reshape([280, 471])
-
- # 用一个新的矩阵接受新的图片,注意数据类型要和原图一致
- src1 = np.zeros(src.shape).astype(np.uint8)
- src1[:, :, 0] = b_des
- src1[:, :, 1] = g_des
- src1[:, :, 2] = r_des
-
- # 显示图片
- img = np.hstack([src0, src1])
- cv.namedWindow("AWB", cv.WINDOW_AUTOSIZE)
- cv.imshow("AWB", img)
- cv.waitKey(0)
- cv.destroyAllWindows()