图像去雾数据集透射率图生成
图像去雾数据集透射率图生成
生成透射率图的目的
图像去雾任务中透射率图的应用主要在以下方面:
- 传统方法利用先验和假设计算雾图像的透射率图,并带入到物理模型中进行去雾。
- 深度学习方法利用网络模型预测物理模型中的各项参数,并带入物理模型中进行去雾。
- 部分深度学习方法利用传统先验方法计算出透射率图并与雾图像一起送入网络模型中作为对雾图像中雾颗粒分布的指导。
然而:
使用先验知识估计的透射率图存在局限性(精确度较低、容易将天空区域误识别成雾等)。
图中天空区域具有跟浓雾区域非常相似的特征,先验知识估计透射率的过程中将该区域识别为了浓雾,预测了非常低的透射率值,在物理模型还原的过程中对应天空区域的亮度值被大幅降低了。
利用深度学习方法预测透射率缺少直接的训练数据,透射率往往是作为网络的中间结果,难以进行更直接的约束。
本文通过对现有数据集中样本进行预处理获取成对的 雾图像—透射率图 样本,进而实现透射率估计模型的直接训练,解决先验知识透射率估计方法精确度、误识别等方面的问题。
准备 雾图像—透射率图 样本对
需要精确的雾图像 $I(x)$—透射率图像 $t(x)$ 样本对来训练模型。需要利用现有可用数据预处理获取。
合成数据集中,利用清晰图像 $J(x)$ 的深度信息 $d(x)$,以及人工选取的全局大气光 $A$、大气散射系数 $\beta$,来合成雾图像 $I(x)$。
一种方法是直接利用 $d(x)$ 计算 $t(x)$,这样可以直接利用与 $d(x)$ 对应的 $I(x)$ 来和 $t(x)$ 组成成对数据。
$t(x)=e^{-\beta d(x)}$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29# 根据深度图生成透射率图
# d_path: 深度图所在目录
# name: 深度图文件名
# beta: 大气散射系数,与生成雾浓度相关
# t_path: 透射率图保存目录
def gen_t_form_depth(d_path, name, beta, t_path):
data = h5py.File(os.path.join(d_path, name), 'r') # 读取深度图.mat文件
# print(list(data.keys()))
depth = data['depth'][:] # 图片对应的深度图信息以二维矩阵的形式保存在depth变量中
data.close()
depth_matrix = np.array(depth)
depth_matrix = np.transpose(depth_matrix, (1, 0))
# print(depth_matrix.shape)
t = np.exp(-1 * float(beta) * depth_matrix) # t(x) = e^(-beta * d(x))
t = (t * 255).astype('uint8')
cv2.imwrite(os.path.join(t_path, name.split(".")[0] + "_" + beta + ".jpg"), t)
# 该代码用于实现根据RESIDE-beta(OTS)数据集中的hazy(主要是取出对应的beta)与depth生成与hazy对应的透射率图
if __name__ == '__main__':
hazy_path = "./data/RESIDE-beta/OTS/hazy/" # 雾图像所在目录
depth_path = "./data/RESIDE-beta/OTS/depth/" # 深度信息(.mat)所在目录
trans_path = "./data/RESIDE-beta/OTS/trans/" # 透射率图保存目录
hazy_list = os.listdir(hazy_path)
for hazy in tqdm(hazy_list):
if hazy.split("_")[1] == "1": # RESIDE-beta(OTS)数据集中hazy的命名格式为(图片编号_A_beta),这里是取出大气光值A为1的图片获取对应的beta值
gen_t_form_depth(d_path=depth_path, name=hazy.split("_")[0] + ".mat", beta=hazy.split("_")[-1][0:-4], t_path=trans_path)目前只有 RESIDE-$\beta$ (是原数据集RESIDE的扩展版本,OST中全部是室外场景,深度图以及雾的合成相较于原版RESIDE更合理一些)中的OST子集可以同时获取 $d(x)$ 和 $\beta$,但OST中的数据量足够大。
在缺少 $A$ 或 $\beta$ 但有 $d(x)$ 时,可以考虑自己选取 $A$ 和 $\beta$ 同时合成 $I(x)$ 和 $t(x)$ 。
注:尽管 $d(x)$ 深度信息可能存在不准确的情况,但是本任务关注的是透射率 $t(x)$ 与图中雾的分布对应是否一致,而雾是通过 $d(x)$ 进行添加的,所以即使 $d(x)$ 表示深度信息可能不准确,但表示雾的信息一定是准确的。
真实成对数据集中,利用成对的雾图像 $I(x)$ 和清晰图像 $J(x)$ 计算 $t(x)$。
$t(x)=\frac{A-I(x)}{A-J(x)}$ ,根据大气散射模型$I(x)=J(x)t(x)+A(1-t(x))$。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29# 根据雾图像hazy和清晰图像GT生成透射率图
# h_path: 雾图像目录
# c_path: 清晰图像目录
# name: 图像名
# t_path: 透射率图保存路径
def gen_t_from_hng(h_path, c_path, name, t_path):
inp = cv2.imread(os.path.join(h_path, name))
gt = cv2.imread(os.path.join(c_path, name))
inp = inp.astype('float64') / 255
gt = gt.astype('float64') / 255
t = (1 - inp) / (1 - gt + 0.0000001) # t(x) = (A - I(x)) / (A - J(x) + 防除0系数)
t = np.clip(t, 0, 1) # 由于真实中存在噪声等影响,截取0-1范围以排除个别异常点
t = (t * 255).astype('uint8')
gray_t = cv2.cvtColor(t, cv2.COLOR_RGB2GRAY)
cv2.imwrite(os.path.join(t_path, name), gray_t)
# 该代码用于实现根据清晰图像(GT)与雾图像(hazy)生成与hazy对应的透射率图
if __name__ == '__main__':
hazy_path = "./data/RESIDE-beta/OTS/hazy/" # 雾图像目录
clear_path = "./data/RESIDE-beta/OTS/clear/" # 清晰图像目录
trans_path = "./data/RESIDE-beta/OTS/trans/" # 透射率图保存目录
hazy_list = os.listdir(hazy_path)
for hazy in tqdm(hazy_list):
gen_t_from_hng(h_path=hazy_path, c_path=clear_path, name=hazy, t_path=trans_path)其中 $A$ 按照传统方式选择图中亮度最大的点的值。
注:真实数据集中仍然存在像素点不对齐的情况,可能给计算带来误差,必要时使用暗通道透射率来替代估计 $t(x)$,这种情况下需要手动剔除天空区域(类雾区域等暗通道误识别区域)。
最终经过预处理后的训练数据包含两部分,一部分具有精确标定的特性(合成数据集预处理),一部分对数据集中缺少的浓雾特征进行补充(真实数据集预处理)。
雾图像—透射率图样本对以及训练模型估计透射率图的效果
经过上述对现有数据集的处理后,可以获取以下雾图像—透射率图样本对:
在RESIDE-$\beta$合成数据集上处理后的雾图像—透射率图样本对。
在NH-HAZE等真实数据集上处理后的雾图像—透射率图样本对。
可以看到,相较于暗通道先验估计的透射率图,无论是合成数据集还是真实数据集上的样本,将天空区域误识别成雾的情况大幅减少了,且由于透射率图是通过物理模型计算而来的,像素点也是精确对应的。
在获取以上样本对之后,就可以进行透射率估计模型的训练,以雾图像作为模型输入 $I(x)$,以透射率图作为 $GT$ 约束模型输出的结果,在合成数据集上训练的模型效果如下图所示:
合成数据集中的雾浓度比较淡、且不均匀分布的情况不明显,但是在训练集上,模型的透射率预测结果与GT透射率图十分接近,能精准地估计出雾图像中透射率较低的区域,且未产生天空区域误识别的错误,初步说明透射率估计模型的有效性。