通过CNN计算大气散射模型中的透射率来实现图像去雾,是融合物理模型与深度学习的有效方法。
大气散射模型是描述雾天图像成像过程的物理模型,其数学表达式为:
其中:
图像去雾的核心任务就是从有雾图像I(x)中估计出透射率t(x)和大气光值A,然后通过逆运算恢复无雾图像J(x):
传统方法需要人工设计特征和先验(如暗通道先验、颜色衰减先验)来估计t(x)和A,但在复杂场景下往往表现不佳。
卷积神经网络(CNN)能够自动学习图像特征,非常适合用于估计透射率。其主要优势在于:
用于透射率估计的CNN通常采用编码器-解码器(Encoder-Decoder)结构,有时会加入跳跃连接(Skip Connections) 来融合低层和高层特征。
一个简单的网络结构示例:
训练CNN估计透射率时,常用的损失函数包括:
首先需要准备有雾图像和对应的真实透射率图数据集用于训练。由于真实透射率难以获取,通常使用合成数据集,如NYU Depth数据集和RESIDE数据集。
% 示例代码:加载和预处理数据
imds = imageDatastore('hazy_images_folder');
pxds = imageDatastore('transmission_maps_folder', 'ReadFcn', @(filename) im2gray(imread(filename)));
% 将图像和透射率图组合为训练数据
trainingData = combine(imds, pxds);
在MATLAB中定义一个简单的编码器-解码器网络:
function lgraph = createTransmissionNet(inputSize)
% 创建编码器-解码器网络用于透射率估计
layers = [
imageInputLayer(inputSize, 'Name', 'input')
% 编码器
convolution2dLayer(3, 64, 'Padding', 'same', 'Name', 'conv1')
reluLayer('Name', 'relu1')
maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool1')
convolution2dLayer(3, 128, 'Padding', 'same', 'Name', 'conv2')
reluLayer('Name', 'relu2')
maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool2')
convolution2dLayer(3, 256, 'Padding', 'same', 'Name', 'conv3')
reluLayer('Name', 'relu3')
% 解码器
transposedConv2dLayer(2, 128, 'Stride', 2, 'Name', 'tconv1')
reluLayer('Name', 'relu4')
transposedConv2dLayer(2, 64, 'Stride', 2, 'Name', 'tconv2')
reluLayer('Name', 'relu5')
convolution2dLayer(3, 1, 'Padding', 'same', 'Name', 'final_conv')
sigmoidLayer('Name', 'sigmoid') % 透射率值应在0-1之间
];
lgraph = layerGraph(layers);
end
配置训练选项并进行模型训练:
% 定义训练选项
options = trainingOptions('adam', ...
'InitialLearnRate', 1e-4, ...
'MaxEpochs', 30, ...
'MiniBatchSize', 8, ...
'Shuffle', 'every-epoch', ...
'Plots', 'training-progress', ...
'Verbose', false);
% 训练网络
net = trainNetwork(trainingData, lgraph, options);
大气光值A通常可以通过选取有雾图像中最亮像素或结合透射率图来估计:
function A = estimateAtmosphericLight(hazyImage, transmissionMap)
% 估计大气光值
% 选择透射率最低的像素(雾最浓的区域)对应的有雾图像中最亮的像素
[height, width] = size(transmissionMap);
numPixels = height * width;
numTopPixels = max(1, round(0.001 * numPixels)); % 前0.1%的像素
% 将透射率图转换为向量并排序
transmissionVector = reshape(transmissionMap, numPixels, 1);
[~, sortedIndices] = sort(transmissionVector);
% 选择透射率最低的像素
darkestIndices = sortedIndices(1:numTopPixels);
% 找到有雾图像中这些像素最亮的强度
hazyVector = reshape(hazyImage, numPixels, 3);
darkestPixels = hazyVector(darkestIndices, :);
% 取这些像素中最亮的作为大气光值
A = max(darkestPixels, [], 1);
end
使用估计的透射率图和大气光值进行图像复原:
function dehazedImage = recoverImage(hazyImage, transmissionMap, A)
% 根据大气散射模型恢复无雾图像
% 确保透射率不会太小(避免除零和噪声放大)
t = max(transmissionMap, 0.1);
% 扩展透射率图到三通道
t = repmat(t, [1, 1, 3]);
% 根据大气散射模型复原图像
dehazedImage = (hazyImage - A) ./ t + A;
% 确保像素值在有效范围内
dehazedImage = max(min(dehazedImage, 1), 0);
end
% 加载有雾图像
hazyImage = im2double(imread('hazy_image.jpg'));
% 使用训练好的网络估计透射率
transmissionMap = predict(net, hazyImage);
% 估计大气光值
A = estimateAtmosphericLight(hazyImage, transmissionMap);
% 复原图像
dehazedImage = recoverImage(hazyImage, transmissionMap, A);
% 显示结果
figure;
subplot(1, 3, 1); imshow(hazyImage); title('有雾图像');
subplot(1, 3, 2); imshow(transmissionMap); title('估计的透射率图');
subplot(1, 3, 3); imshow(dehazedImage); title('去雾结果');
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。