基于颜色衰减先验的图像去雾MATLAB实现

简介: 基于颜色衰减先验(Color Attenuation Prior, CAP)的图像去雾MATLAB程序。该算法通过分析图像中亮度和饱和度的关系来估计雾的浓度,从而实现高效的图像去雾

基于颜色衰减先验(Color Attenuation Prior, CAP)的图像去雾MATLAB程序。该算法通过分析图像中亮度和饱和度的关系来估计雾的浓度,从而实现高效的图像去雾。

function dehazed_image = colorAttenuationPriorDehazing(hazy_image)
    % 基于颜色衰减先验的图像去雾算法
    % 输入: hazy_image - 有雾的RGB图像 (0-2550-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. 算法步骤

  1. 图像预处理

    • 将RGB图像转换为HSV色彩空间
    • 提取明度(V)和饱和度(S)分量
  2. 深度图估计

    • 计算深度图:$d(x)=V(x)−S(x)$
  3. 大气光估计

    • 选择深度图中最小的0.1%像素(最远距离)
    • 在这些像素中选择最亮的像素作为大气光$A$
  4. 透射率估计

    • 计算初始透射率:$t(x)=e^{−βd(x)}$
    • 使用引导滤波细化透射率图
  5. 场景恢复

    • 使用大气散射模型恢复无雾图像:

      $J(x)=\frac{I(x)−A}{max(t(x),ω)}+A$

    • 其中 ω是保留的最小雾比例(通常0.95)

  6. 后处理

    • 颜色校正
    • 对比度增强
    • 锐化处理

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. 特殊场景处理

  • 浓雾场景:降低$ω$值,增加$β$值
  • 夜间场景:调整大气光估计方法
  • 水下场景:修改散射模型参数

常见问题解决方案

  1. 去雾后图像颜色失真

    • 解决方案:调整color_bias参数,增加颜色校正强度
    • 代码示例:corrected_img = colorCorrection(dehazed_img, 0.2);
  2. 图像边缘出现光晕

    • 解决方案:增大引导滤波半径或使用双边滤波
    • 代码示例:transmission = guidedfilter(img, transmission, 30, 0.001);
  3. 远景去雾不彻底

    • 解决方案:增大β值或使用自适应β估计
    • 代码示例:beta = estimateBeta(depth_map, rgb2gray(img));
  4. 图像整体偏暗

    • 解决方案:降低ω值或调整大气光估计
    • 代码示例: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
相关文章
|
7天前
|
人工智能 安全 Linux
【OpenClaw保姆级图文教程】阿里云/本地部署集成模型Ollama/Qwen3.5/百炼 API 步骤流程及避坑指南
2026年,AI代理工具的部署逻辑已从“单一云端依赖”转向“云端+本地双轨模式”。OpenClaw(曾用名Clawdbot)作为开源AI代理框架,既支持对接阿里云百炼等云端免费API,也能通过Ollama部署本地大模型,完美解决两类核心需求:一是担心云端API泄露核心数据的隐私安全诉求;二是频繁调用导致token消耗过高的成本控制需求。
4859 7
|
14天前
|
人工智能 JavaScript Ubuntu
5分钟上手龙虾AI!OpenClaw部署(阿里云+本地)+ 免费多模型配置保姆级教程(MiniMax、Claude、阿里云百炼)
OpenClaw(昵称“龙虾AI”)作为2026年热门的开源个人AI助手,由PSPDFKit创始人Peter Steinberger开发,核心优势在于“真正执行任务”——不仅能聊天互动,还能自动处理邮件、管理日程、订机票、写代码等,且所有数据本地处理,隐私完全可控。它支持接入MiniMax、Claude、GPT等多类大模型,兼容微信、Telegram、飞书等主流聊天工具,搭配100+可扩展技能,成为兼顾实用性与隐私性的AI工具首选。
20642 113
|
10天前
|
人工智能 API 网络安全
Mac mini × OpenClaw 保姆级配置教程(附阿里云/本地部署OpenClaw配置百炼API图文指南)
Mac mini凭借小巧机身、低功耗和稳定性能,成为OpenClaw(原Clawdbot)本地部署的首选设备——既能作为家用AI节点实现7×24小时运行,又能通过本地存储保障数据隐私,搭配阿里云部署方案,可灵活满足“长期值守”与“隐私优先”的双重需求。对新手而言,无需复杂命令行操作,无需专业技术储备,按本文步骤复制粘贴代码,即可完成OpenClaw的全流程配置,同时接入阿里云百炼API,解锁更强的AI任务执行能力。
6567 2
|
11天前
|
人工智能 安全 前端开发
Team 版 OpenClaw:HiClaw 开源,5 分钟完成本地安装
HiClaw 基于 OpenClaw、Higress AI Gateway、Element IM 客户端+Tuwunel IM 服务器(均基于 Matrix 实时通信协议)、MinIO 共享文件系统打造。
7938 6
|
13天前
|
人工智能 JavaScript API
保姆级教程:OpenClaw阿里云/本地部署配置Tavily Search skill 实时联网,让OpenClaw“睁眼看世界”
默认状态下的OpenClaw如同“闭门造车”的隐士,仅能依赖模型训练数据回答问题,无法获取实时新闻、最新数据或训练截止日期后的新信息。2026年,激活其联网能力的最优方案是配置Tavily Search技能——无需科学上网、无需信用卡验证,每月1000次免费搜索额度完全满足个人需求,搭配ClawHub技能市场,还能一键拓展天气查询、邮件管理等实用功能。
7671 5
|
6天前
|
JavaScript Linux API
保姆级教程,通过GACCode在国内使用Claudecode、Codex!
保姆级教程,通过GACCode在国内使用Claudecode、Codex!
3633 1
保姆级教程,通过GACCode在国内使用Claudecode、Codex!

热门文章

最新文章