基于颜色衰减先验(Color Attenuation Prior, CAP)的图像去雾MATLAB程序。该算法通过分析图像中亮度和饱和度的关系来估计雾的浓度,从而实现高效的图像去雾。
function dehazed_image = colorAttenuationPriorDehazing(hazy_image)
% 基于颜色衰减先验的图像去雾算法
% 输入: hazy_image - 有雾的RGB图像 (0-255或0-1)
% 输出: dehazed_image - 去雾后的RGB图像
% 参数设置
omega = 0.95; % 保留雾的最小比例 (0-1)
t0 = 0.1; % 透射率最小值
color_bias = 0.0; % 颜色偏差补偿
% 转换为双精度浮点型
if ~isa(hazy_image, 'double')
hazy_image = im2double(hazy_image);
end
% 1. 将图像转换为HSV色彩空间
hsv_img = rgb2hsv(hazy_image);
V = hsv_img(:,:,3); % 明度分量
S = hsv_img(:,:,2); % 饱和度分量
% 2. 计算深度图 (基于颜色衰减先验)
depth_map = V - S;
% 3. 估计大气光A
A = estimateAtmosphericLight(hazy_image, depth_map);
% 4. 估计透射率t(x)
beta = 1.0; % 雾的衰减系数
transmission = exp(-beta * depth_map);
% 5. 应用引导滤波细化透射率
transmission = guidedfilter(hazy_image, transmission, 15, 0.0001);
% 6. 限制透射率范围
transmission = max(transmission, t0);
% 7. 恢复无雾图像
dehazed_image = recoverScene(hazy_image, A, transmission, omega);
% 8. 颜色校正
dehazed_image = colorCorrection(dehazed_image, color_bias);
% 9. 后处理
dehazed_image = postProcess(dehazed_image);
end
function A = estimateAtmosphericLight(img, depth_map)
% 估计大气光值A
[h, w, c] = size(img);
% 方法1: 选择深度图中最深的0.1%像素
num_pixels = h * w;
num_bright = round(0.001 * num_pixels); % 0.1%的像素
[~, indices] = sort(depth_map(:), 'ascend'); % 深度值小的像素更近
dark_indices = indices(1:num_bright);
% 获取这些像素的RGB值
[row, col] = ind2sub([h, w], dark_indices);
candidate_pixels = zeros(num_bright, 3);
for i = 1:num_bright
candidate_pixels(i, :) = img(row(i), col(i), :);
end
% 选择最亮的像素作为大气光
[~, idx] = max(sum(candidate_pixels, 2));
A = candidate_pixels(idx, :);
% 方法2: 使用图像中最亮的像素 (备选)
if all(A < 0.9) % 如果太暗,使用备选方法
gray_img = rgb2gray(img);
[~, bright_idx] = max(gray_img(:));
[bright_row, bright_col] = ind2sub([h, w], bright_idx);
A = squeeze(img(bright_row, bright_col, :))';
end
end
function refined_t = guidedfilter(I, p, r, eps)
% 引导滤波用于细化透射率
[hei, wid] = size(p);
N = boxfilter(ones(hei, wid), r);
mean_I = boxfilter(I, r) ./ N;
mean_p = boxfilter(p, r) ./ N;
mean_Ip = boxfilter(I.*p, r) ./ N;
cov_Ip = mean_Ip - mean_I .* mean_p;
mean_II = boxfilter(I.*I, r) ./ N;
var_I = mean_II - mean_I .* mean_I;
a = cov_Ip ./ (var_I + eps);
b = mean_p - a .* mean_I;
mean_a = boxfilter(a, r) ./ N;
mean_b = boxfilter(b, r) ./ N;
refined_t = mean_a .* I + mean_b;
end
function result = boxfilter(img, r)
% 盒式滤波器
[h, w] = size(img);
result = zeros(h, w);
% 累计和
cumsum_img = cumsum(img, 1);
result(1:r+1, :) = cumsum_img(1+r:2*r+1, :);
result(r+2:h-r, :) = cumsum_img(2*r+2:h, :) - cumsum_img(1:h-2*r-1, :);
result(h-r+1:h, :) = repmat(cumsum_img(h, :), r, 1) - cumsum_img(h-2*r:h-r-1, :);
cumsum_result = cumsum(result, 2);
result(:, 1:r+1) = cumsum_result(:, 1+r:2*r+1);
result(:, r+2:w-r) = cumsum_result(:, 2*r+2:w) - cumsum_result(:, 1:w-2*r-1);
result(:, w-r+1:w) = repmat(cumsum_result(:, w), 1, r) - cumsum_result(:, w-2*r:w-r-1);
end
function J = recoverScene(I, A, t, omega)
% 恢复无雾场景
[h, w, c] = size(I);
J = zeros(size(I));
for ch = 1:c
J(:,:,ch) = (I(:,:,ch) - A(ch)) ./ max(t, omega) + A(ch);
end
% 限制像素值在合理范围内
J = max(min(J, 1), 0);
end
function corrected_img = colorCorrection(img, bias)
% 颜色校正
lab_img = rgb2lab(img);
L = lab_img(:,:,1);
a = lab_img(:,:,2);
b = lab_img(:,:,3);
% 调整颜色通道
a = a + bias * (128 - mean(a(:)));
b = b + bias * (128 - mean(b(:)));
% 重组图像
corrected_lab = cat(3, L, a, b);
corrected_img = lab2rgb(corrected_lab);
% 处理无效值
corrected_img(isnan(corrected_img)) = 0;
end
function processed_img = postProcess(img)
% 后处理增强
% 1. 对比度拉伸
low_in = prctile(img(:), 2);
high_in = prctile(img(:), 98);
processed_img = imadjust(img, [low_in high_in], [0 1]);
% 2. 锐化
blurred = imgaussfilt(processed_img, 1);
sharpened = processed_img + 0.5 * (processed_img - blurred);
processed_img = min(max(sharpened, 0), 1);
% 3. 伽马校正
processed_img = imadjust(processed_img, [], [], 0.9);
end
%% 主函数 - 图像去雾演示
function hazeRemovalDemo()
% 读取有雾图像
hazy_img = imread('hazy_image.jpg');
% 执行去雾
dehazed_img = colorAttenuationPriorDehazing(hazy_img);
% 显示结果
figure('Position', [100, 100, 1200, 400]);
subplot(1,3,1);
imshow(hazy_img);
title('原始有雾图像');
subplot(1,3,2);
imshow(dehazed_img);
title('去雾后图像');
% 显示透射率图
hsv_img = rgb2hsv(im2double(hazy_img));
V = hsv_img(:,:,3);
S = hsv_img(:,:,2);
depth_map = V - S;
transmission = exp(-1.0 * depth_map);
transmission = guidedfilter(im2double(hazy_img), transmission, 15, 0.0001);
transmission = max(transmission, 0.1);
subplot(1,3,3);
imshow(transmission, []);
colormap jet;
colorbar;
title('透射率图');
% 保存结果
imwrite(dehazed_img, 'dehazed_image.jpg');
end
%% 辅助函数 - 创建示例有雾图像
function createSampleHazyImage()
% 创建无雾图像
[X, Y] = meshgrid(1:500, 1:300);
background = cat(3, 0.2*sin(0.01*X) + 0.3, 0.3*cos(0.02*Y) + 0.4, 0.4*sin(0.015*X.*Y) + 0.3);
% 添加前景物体
foreground = zeros(300, 500, 3);
foreground(50:250, 100:400, 1) = 0.8; % 红色矩形
foreground(150:280, 200:450, 2) = 0.7; % 绿色椭圆
% 合成图像
scene = background;
mask = foreground(:,:,1) > 0 | foreground(:,:,2) > 0 | foreground(:,:,3) > 0;
scene(mask) = foreground(mask);
% 添加雾效
depth = ones(300, 500);
depth(100:200, 150:350) = 0.5; % 中间区域较近
depth(50:150, 400:450) = 0.8; % 右上角较远
A = [0.9, 0.9, 0.9]; % 大气光
beta = 0.8; % 雾浓度
transmission = exp(-beta * depth);
hazy_scene = zeros(size(scene));
for c = 1:3
hazy_scene(:,:,c) = scene(:,:,c) .* transmission + A(c) * (1 - transmission);
end
% 添加噪声
hazy_scene = imnoise(hazy_scene, 'gaussian', 0, 0.01);
% 保存示例图像
imwrite(hazy_scene, 'sample_hazy_image.jpg');
disp('示例有雾图像已保存为 sample_hazy_image.jpg');
end
算法原理详解
1. 颜色衰减先验理论
颜色衰减先验基于以下观察:在雾天图像中,场景的深度与亮度和饱和度之差成正比。数学表示为:
$d(x)=v(x)−s(x)$
其中:
- v(x) 是HSV色彩空间的明度分量
- s(x)是HSV色彩空间的饱和度分量
- d(x)表示场景深度信息
雾的浓度与深度成正比:
$t(x)=e^{−βd(x)}$
其中 β是雾的散射系数。
2. 算法步骤
图像预处理:
- 将RGB图像转换为HSV色彩空间
- 提取明度(V)和饱和度(S)分量
深度图估计:
- 计算深度图:$d(x)=V(x)−S(x)$
大气光估计:
- 选择深度图中最小的0.1%像素(最远距离)
- 在这些像素中选择最亮的像素作为大气光$A$
透射率估计:
- 计算初始透射率:$t(x)=e^{−βd(x)}$
- 使用引导滤波细化透射率图
场景恢复:
使用大气散射模型恢复无雾图像:
$J(x)=\frac{I(x)−A}{max(t(x),ω)}+A$
其中 ω是保留的最小雾比例(通常0.95)
后处理:
- 颜色校正
- 对比度增强
- 锐化处理
3. 关键技术实现
引导滤波
function refined_t = guidedfilter(I, p, r, eps)
% 引导滤波用于细化透射率
[hei, wid] = size(p);
N = boxfilter(ones(hei, wid), r);
mean_I = boxfilter(I, r) ./ N;
mean_p = boxfilter(p, r) ./ N;
mean_Ip = boxfilter(I.*p, r) ./ N;
cov_Ip = mean_Ip - mean_I .* mean_p;
mean_II = boxfilter(I.*I, r) ./ N;
var_I = mean_II - mean_I .* mean_I;
a = cov_Ip ./ (var_I + eps);
b = mean_p - a .* mean_I;
mean_a = boxfilter(a, r) ./ N;
mean_b = boxfilter(b, r) ./ N;
refined_t = mean_a .* I + mean_b;
end
大气光估计
function A = estimateAtmosphericLight(img, depth_map)
% 选择深度图中最深的0.1%像素
[h, w, c] = size(img);
num_pixels = h * w;
num_bright = round(0.001 * num_pixels);
[~, indices] = sort(depth_map(:), 'ascend');
dark_indices = indices(1:num_bright);
% 获取这些像素的RGB值
[row, col] = ind2sub([h, w], dark_indices);
candidate_pixels = zeros(num_bright, 3);
for i = 1:num_bright
candidate_pixels(i, :) = img(row(i), col(i), :);
end
% 选择最亮的像素作为大气光
[~, idx] = max(sum(candidate_pixels, 2));
A = candidate_pixels(idx, :);
end
参考代码 基于颜色衰减先验的图像去雾代码 www.youwenfan.com/contentalg/95835.html
使用说明
1. 基本使用
% 读取有雾图像
hazy_img = imread('foggy_photo.jpg');
% 执行去雾
dehazed_img = colorAttenuationPriorDehazing(hazy_img);
% 显示结果
imshowpair(hazy_img, dehazed_img, 'montage');
title('有雾图像 (左) vs 去雾图像 (右)');
% 保存结果
imwrite(dehazed_img, 'dehazed_photo.jpg');
2. 参数调整
% 调整关键参数
function dehazed_image = colorAttenuationPriorDehazing(hazy_image)
omega = 0.9; % 降低此值使图像更清晰(但可能过度去雾)
t0 = 0.05; % 提高此值保留更多雾(更平滑)
beta = 1.2; % 增大此值增强去雾效果
color_bias = 0.1; % 增大此值增强颜色饱和度
% ...其余代码不变...
end
3. 处理视频序列
% 视频去雾处理
videoFile = 'foggy_video.mp4';
outputFile = 'dehazed_video.mp4';
reader = VideoReader(videoFile);
writer = VideoWriter(outputFile, 'Motion JPEG AVI');
writer.FrameRate = reader.FrameRate;
while hasFrame(reader)
frame = readFrame(reader);
dehazed_frame = colorAttenuationPriorDehazing(frame);
writeVideo(writer, dehazed_frame);
end
release(writer);
disp('视频去雾完成');
算法优化技巧
1. 自适应β估计
function beta = estimateBeta(depth_map, gray_img)
% 自适应估计雾浓度系数β
normalized_depth = (depth_map - min(depth_map(:))) / (max(depth_map(:)) - min(depth_map(:)));
gray_normalized = (gray_img - min(gray_img(:))) / (max(gray_img(:)) - min(gray_img(:)));
% 使用线性回归估计β
X = [ones(size(normalized_depth(:))), normalized_depth(:)];
coefficients = X \ gray_normalized(:);
beta = -coefficients(2);
% 限制β的范围
beta = max(0.5, min(1.5, beta));
end
2. 多尺度处理
function transmission = multiScaleTransmission(hazy_img, depth_map)
% 多尺度透射率估计
scales = [3, 5, 15];
weights = [0.3, 0.3, 0.4];
transmission = zeros(size(depth_map));
for i = 1:length(scales)
t = exp(-1.0 * depth_map);
t_refined = guidedfilter(hazy_img, t, scales(i), 0.0001);
transmission = transmission + weights(i) * t_refined;
end
end
3. 边缘保留去噪
function denoised = edgePreservingDenoising(img)
% 边缘保留去噪
denoised = imbilatfilt(img, 0.1, 0.1);
denoised = medfilt2(denoised, [3, 3]);
end
性能评估指标
1. 客观评价指标
function evaluatePerformance(orig_img, hazy_img, dehazed_img)
% 计算PSNR
psnr_orig_dehazed = psnr(orig_img, dehazed_img);
psnr_hazy_dehazed = psnr(hazy_img, dehazed_img);
% 计算SSIM
ssim_orig_dehazed = ssim(orig_img, dehazed_img);
ssim_hazy_dehazed = ssim(hazy_img, dehazed_img);
% 计算可见边数量
edges_orig = edge(rgb2gray(orig_img), 'Canny');
edges_hazy = edge(rgb2gray(hazy_img), 'Canny');
edges_dehazed = edge(rgb2gray(dehazed_img), 'Canny');
% 显示结果
fprintf('===== 性能评估 =====\n');
fprintf('PSNR (原始 vs 去雾): %.2f dB\n', psnr_orig_dehazed);
fprintf('PSNR (有雾 vs 去雾): %.2f dB\n', psnr_hazy_dehazed);
fprintf('SSIM (原始 vs 去雾): %.4f\n', ssim_orig_dehazed);
fprintf('SSIM (有雾 vs 去雾): %.4f\n', ssim_hazy_dehazed);
fprintf('可见边数量: 原始=%d, 有雾=%d, 去雾=%d\n', ...
nnz(edges_orig), nnz(edges_hazy), nnz(edges_dehazed));
end
2. 主观评价方法
- 视觉清晰度评估
- 颜色自然度评估
- 细节保留程度评估
- 雾残留程度评估
实际应用建议
1. 预处理优化
- 光照均衡:使用Retinex算法预处理图像
- 噪声去除:应用中值滤波或双边滤波
- 色彩校正:白平衡处理
2. 后处理增强
function enhanced = enhanceDetails(img)
% 细节增强
lab = rgb2lab(img);
L = lab(:,:,1)/100;
detail_layer = img - imfilter(img, fspecial('gaussian', 15, 5));
enhanced_L = L + 0.3*detail_layer(:,:,1);
enhanced_L = min(max(enhanced_L, 0), 1);
lab(:,:,1) = enhanced_L * 100;
enhanced = lab2rgb(lab);
end
3. 实时处理优化
- GPU加速:使用MATLAB Parallel Computing Toolbox
- 算法简化:降低图像分辨率或使用近似计算
- 硬件优化:针对嵌入式设备优化
4. 特殊场景处理
- 浓雾场景:降低$ω$值,增加$β$值
- 夜间场景:调整大气光估计方法
- 水下场景:修改散射模型参数
常见问题解决方案
去雾后图像颜色失真
- 解决方案:调整color_bias参数,增加颜色校正强度
- 代码示例:
corrected_img = colorCorrection(dehazed_img, 0.2);
图像边缘出现光晕
- 解决方案:增大引导滤波半径或使用双边滤波
- 代码示例:
transmission = guidedfilter(img, transmission, 30, 0.001);
远景去雾不彻底
- 解决方案:增大β值或使用自适应β估计
- 代码示例:
beta = estimateBeta(depth_map, rgb2gray(img));
图像整体偏暗
- 解决方案:降低ω值或调整大气光估计
- 代码示例:
omega = 0.85;或改进大气光估计方法
扩展应用
1. 视频去雾
function videoDehazing(inputVideo, outputVideo)
reader = VideoReader(inputVideo);
writer = VideoWriter(outputVideo);
writer.FrameRate = reader.FrameRate;
prevTransmission = [];
while hasFrame(reader)
frame = readFrame(reader);
[dehazed, transmission] = colorAttenuationPriorDehazing(frame);
% 时序平滑
if ~isempty(prevTransmission)
transmission = 0.7*transmission + 0.3*prevTransmission;
end
prevTransmission = transmission;
writeVideo(writer, dehazed);
end
release(writer);
end
2. 雾浓度估计
function fogDensity = estimateFogDensity(img)
% 估计雾浓度
hsv = rgb2hsv(img);
V = hsv(:,:,3);
S = hsv(:,:,2);
depth_map = V - S;
% 计算雾密度指标
fog_index = mean(depth_map(:));
fogDensity = 1 / (1 + exp(-10*(fog_index - 0.3))); % Sigmoid函数归一化
fprintf('雾浓度估计: %.2f%%\n', fogDensity*100);
end
3. 深度图估计
function depthMap = estimateDepthMap(img)
% 从单幅图像估计深度图
hsv = rgb2hsv(img);
V = hsv(:,:,3);
S = hsv(:,:,2);
% 基础深度估计
depth_map = V - S;
% 优化深度图
gray_img = rgb2gray(img);
depth_map = guidedfilter(gray_img, depth_map, 15, 0.0001);
% 归一化并显示
depthMap = mat2gray(depth_map);
figure; imshow(depthMap); title('估计的深度图');
end