AWB(Auto White Banlance)——自动白平衡
产生原因
方法
代码
GW灰度世界白平衡算法
灰度世界算法(Gray World)是以灰度世界假设为基础的,该假设认为对于一幅有着大量色彩变化的图像, R、 G、 B 三个分量的平均值趋于同一个灰度K。
$$Rgain = k / Ravg $$
$$Ggain = k / Gavg $$
$$Bgain = k / Bavg $$
然后通过k值来求各个通达的增益。
- 直接给定为固定值, 取其各通道最大值的一半,即取为127或128;
- 令 K = (Raver+Gaver+Baver)/3,其中Raver,Gaver,Baver分别表示红、 绿、 蓝三个通道的平均值。
算法的第二步是分别计算各通道的增益:
$$k = (Bavg + Gavg + Ravg)/3$$ - 设定G通道不变,让R和B通道往G通道上靠,即:
$$Rgain = Rave / Gave$$
$$Bgain = Bave / Gave$$
新的像素的绿色通道不变,红色和蓝色通道通过绿色通道来求
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,这样就可以计算出各通道的增益:
$$Rgain = k / Rmax $$
$$Ggain = k / Gmax $$
$$Bgain = k / Bmax $$
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两种算法的正交组合,从而保留两者的优点,具体的算法公式如下:
$$ Kave = (Rave + Gave + Bave) / 3 $$
$$ Kmax = (Rmax + Gmax + Bmax) / 3$$
$$ u * Rave^2 + v * Rave = Kave $$
$$ u * Rmax^2 + v* Rmax = Kmax $$
这是R通道的算法公式,求出u和v然后通过以下公式换算出新的值:
$$Rnew = u * Rorg ^ 2 + v * Rorg$$
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()
主要是给自己看的,所以肯定会出现很多错误哈哈哈哈哈