近期一直在准备研究生的开题,更新迟缓,现在关于这篇博文的后续终于来啦!!!!
这篇论文的颜色校正方法第一步是先进行颜色通道的补偿,第二步进行颜色通道的动态拉伸,从而达到颜色校正的目的,去除水下图像偏绿、偏蓝的色偏效果。第一步具体实施方法和效果可以移步到上次我写的博文,博文链接:《基于直方图分布特性的水下图像颜色校正方法》论文代码复现。本文是对后续的动态拉伸环节进行更新:
上次我们分析图像的直方图分布时提到,要想让水下的图像成像效果和陆地上的图像效果相近,起码要满足2个条件:
(1)三通道直方图分布相似;
(2)三通道直方图分布遍及整个动态范围;
其实还应该满足一个条件,那就是三通道直方图均值都近似等于128。衰减补偿后的图像直方图具有一定的相似性,但分布还比较集中,因此还需要对其动态拉伸,使拉伸后直方图分布符合前节所述所有特点。
动态范围的拉伸
统计学上,均值反映数据的集中趋势或者是期望值,标准差反映一个数据集的离散程度,因此我们采用均值和标准差来确定动态拉伸前的范围:
其中C表示红绿蓝三个颜色通道,Lmean和Lstd表示对应颜色通道的均值和标准差,Lmin和Lmax表示对应通道的最小值和最大值,u表示动态范围,经试验验证,动态范围不能太大也不能太小,取2~3之间就可以,这里取3,读者可以根据自己的水域环境进行更改。
然后进行颜色的校正,校正公式为:
Lout为校正后的颜色通道,Lin为校正后的颜色通道。根据公式我们可以看出,这是由传统的拉伸公式演化而来,不理解的可以查一查这个公式。
程序复现(总)
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread("ok4.jpg").astype(np.float32) / 255.0
# 将图像分为BGR三个颜色通道
B, G, R = cv2.split(image)
# 计算蓝色通道的像素平均值
Bavg = np.mean(np.mean(B))
# 计算绿色通道的像素平均值
Gavg = np.mean(np.mean(G))
# 计算红色通道的像素平均值
Ravg = np.mean(np.mean(R))
# 创建颜色通道平均值的列表
means = [Bavg, Gavg, Ravg]
# 根据平均值从高到低对颜色通道进行排序
sorted_channels = [B, G, R]
sorted_channels = [x for _, x in sorted(zip(means, sorted_channels), reverse=True)]
# 将排序结果分别表示为Pfirst(i,j)、Psecond(i,j)、Pthird(i,j)
Pfirst = sorted_channels[0] # 平均值最大的颜色通道
Psecond = sorted_channels[1]
Pthird = sorted_channels[2] # 平均值最小的颜色通道,此时的通道是二维数组
# 计算补偿因子a,b
a = (np.mean(Pfirst) - np.mean(Psecond)) / (np.mean(Pfirst) + np.mean(Psecond))
b = (np.mean(Pfirst) - np.mean(Pthird)) / (np.mean(Pfirst) + np.mean(Pthird))
# 对第二均值通道进行逐像素补偿
Psecond_compensated = Psecond + a * Pfirst
# 对第三均值通道进行逐像素补偿
Pthird_compensated = Pthird + b * Pfirst
# 将三个通道(第一均值颜色通道,补偿后的第二、三均值分布通道)进行组合
merged_image = np.dstack((Pfirst, Psecond_compensated, Pthird_compensated))
#计算各个通道的均值和标准差
min_first = np.mean(Pfirst) - 3 * np.std(Pfirst)
max_first = np.mean(Pfirst) + 3 * np.std(Pfirst)
min_second_compensated = np.mean(Psecond_compensated) - 3 * np.std(Psecond_compensated)
max_second_compensated = np.mean(Psecond_compensated) + 3 * np.std(Psecond_compensated)
min_third_compensated = np.mean(Pthird_compensated) - 3 * np.std(Pthird_compensated)
max_third_compensated = np.mean(Pthird_compensated) + 3 * np.std(Pthird_compensated)
#对三个颜色通道进行动态拉伸
Lfirstout = (Pfirst - min_first) * 255 / (max_first - min_first)
#将拉伸后的图像各个像素点限制在0~255之内,如果大于255会出现很多噪点和伪影,出现过曝的现象,影响整个图像
Lfirstout = np.clip(Lfirstout, 0, 255)
Lsecondout = (Psecond_compensated - min_second_compensated) * 255 / (max_second_compensated - min_second_compensated)
Lsecondout = np.clip(Lsecondout, 0, 255)
Lthirdout = (Pthird_compensated - min_third_compensated) * 255 / (max_third_compensated - min_third_compensated)
Lthirdout = np.clip(Lthirdout, 0, 255)
#将拉伸后的通道重新合并为图像
lashen_image = np.dstack((Lfirstout, Lsecondout, Lthirdout)).astype(np.uint8)
print("Lfirstout", Lfirstout)
print("Lsecondout", Lsecondout)
print("Lthirdout", Lthirdout)
# 展示原始图像和动态拉伸后的图像
cv2.imshow("original",image)
cv2.imshow("lashen_image", lashen_image)
cv2.imshow("firstout_image", Lfirstout.astype(np.uint8))
cv2.imshow("secondout_image", Lsecondout.astype(np.uint8))
cv2.imshow("thirdout_image", Lthirdout.astype(np.uint8))
# 等待按键,结束本次服务
cv2.waitKey()
cv2.destroyAllWindows()
运行结果
结果分析
不管是蓝色、还是绿色的水下环境,图像颜色都能很好的恢复,而且颜色校正后的图像相对衰减补偿后的图像效果更好,偏色现象去除更明显,颜色更自然。但是细节模糊和对比度还是存在问题,可以在后续加入直方图均衡化等算法加大图像的对比度。
欢迎大佬们提出意见,侵权联系速删。