HDR图像生成算法详解

HDR技术概述

高动态范围(HDR)图像生成是通过合成多张不同曝光度的图像,来捕捉超出传统显示设备范围的亮度信息。以下是主要的HDR生成算法及其MATLAB实现。

HDR成像基本原理

动态范围定义

动态范围 = 最大可记录亮度 / 最小可记录亮度

  • LDR图像:~100:1
  • HDR图像:可达100,000:1

HDR图像生成核心算法

1. 多曝光图像合成算法

function hdr_image = generate_hdr_multi_exposure(images, exposure_times)
% 基于多曝光图像的HDR合成
% 输入:
%   images - 不同曝光的图像序列 {N×1} cell array
%   exposure_times - 对应的曝光时间向量
% 输出:
%   hdr_image - 合成的HDR图像

    num_images = length(images);
    [height, width, channels] = size(images{1});
    
    % 初始化权重矩阵和HDR图像
    hdr_image = zeros(height, width, channels);
    total_weight = zeros(height, width, channels);
    
    % 相机响应函数估计(可选,如果未提供则使用默认权重)
    if ~exist('camera_response', 'var')
        % 使用三角权重函数
        weight_function = @(z) max(0, 1 - abs(2*z - 1));  % z在[0,1]范围内
    end
    
    fprintf('开始合成HDR图像...\n');
    
    for i = 1:num_images
        fprintf('处理第%d张曝光图像...\n', i);
        
        % 将图像转换为double类型并归一化
        img = im2double(images{i});
        
        % 计算权重
        weight_map = zeros(size(img));
        for c = 1:channels
            weight_map(:, :, c) = weight_function(img(:, :, c));
        end
        
        % 避免过曝和欠曝区域
        saturation_threshold = 0.95;
        underexposure_threshold = 0.05;
        
        % 降低过曝和欠曝区域的权重
        over_exposed = img > saturation_threshold;
        under_exposed = img < underexposure_threshold;
        
        weight_map(over_exposed) = 0.01;
        weight_map(under_exposed) = 0.01;
        
        % 累加到HDR图像
        hdr_image = hdr_image + weight_map .* img / exposure_times(i);
        total_weight = total_weight + weight_map;
    end
    
    % 避免除零错误
    total_weight(total_weight == 0) = 1e-8;
    
    % 归一化得到最终HDR图像
    hdr_image = hdr_image ./ total_weight;
    
    fprintf('HDR图像合成完成\n');
end

2. 相机响应函数估计

function [g, lnE] = estimate_camera_response(images, exposure_times, lambda)
% 使用Debevec方法估计相机响应函数
% 输入:
%   images - 不同曝光的图像序列
%   exposure_times - 曝光时间
%   lambda - 平滑度参数
% 输出:
%   g - 估计的相机响应函数
%   lnE - 场景辐照度的对数

    num_images = length(images);
    [height, width, channels] = size(images{1});
    num_pixels = height * width;
    
    % 采样像素点(避免过曝和欠曝)
    sample_indices = sample_pixels(images, 1000);
    num_samples = length(sample_indices);
    
    % 构建线性系统
    n = 256;  % 量化级别 (8-bit)
    A = zeros(num_samples * num_images + n + 1, num_samples + n);
    b = zeros(size(A, 1), 1);
    
    k = 1;
    
    % 添加数据项约束
    for i = 1:num_images
        img = images{i};
        for j = 1:num_samples
            [row, col] = ind2sub([height, width], sample_indices(j));
            z = round(img(row, col, 1) * (n-1)) + 1;  % 使用单个通道
            
            w_z = weighting_function(z/n);
            
            A(k, z) = w_z;
            A(k, n + j) = -w_z;
            b(k) = w_z * log(exposure_times(i));
            
            k = k + 1;
        end
    end
    
    % 添加平滑度约束
    for z = 2:n-1
        w_z = weighting_function(z/n);
        
        A(k, z-1) = lambda * w_z;
        A(k, z) = -2 * lambda * w_z;
        A(k, z+1) = lambda * w_z;
        k = k + 1;
    end
    
    % 添加锚点约束(设置g(128)=0)
    A(k, round(n/2)) = 1;
    k = k + 1;
    
    % 求解线性系统
    x = A \ b;
    
    g = x(1:n);
    lnE = x(n+1:end);
end

function indices = sample_pixels(images, num_samples)
% 采样像素点,避免过曝和欠曝区域
    [height, width, ~] = size(images{1});
    
    % 计算像素的可靠性分数
    reliability = ones(height, width);
    num_images = length(images);
    
    for i = 1:num_images
        img = im2double(images{i});
        
        % 中间曝光度最可靠
        mid_tone = 0.5;
        reliability = reliability .* (1 - abs(img - mid_tone));
    end
    
    % 随机采样,权重为可靠性
    reliability_flat = reliability(:);
    probabilities = reliability_flat / sum(reliability_flat);
    
    indices = randsample(height * width, num_samples, true, probabilities);
end

function w = weighting_function(z)
% 权重函数:中间调高权重,过曝和欠曝低权重
    z = max(0, min(1, z));
    if z <= 0.5
        w = z;
    else
        w = 1 - z;
    end
end

3. 色调映射算法

function ldr_image = tone_mapping(hdr_image, method, varargin)
% 色调映射:将HDR图像映射到LDR显示范围
% 输入:
%   hdr_image - HDR输入图像
%   method - 色调映射方法
% 输出:
%   ldr_image - 映射后的LDR图像

    switch lower(method)
        case 'reinhard'
            ldr_image = reinhard_tone_mapping(hdr_image, varargin{:});
        case 'durand'
            ldr_image = durand_tone_mapping(hdr_image, varargin{:});
        case 'drago'
            ldr_image = drago_tone_mapping(hdr_image, varargin{:});
        case 'gamma'
            ldr_image = gamma_tone_mapping(hdr_image, varargin{:});
        otherwise
            error('不支持的色调映射方法');
    end
    
    % 确保输出在[0,1]范围内
    ldr_image = max(0, min(1, ldr_image));
end

function ldr_image = reinhard_tone_mapping(hdr_image, L_white, a)
% Reinhard全局色调映射算法
% 参考: Photographic Tone Reproduction for Digital Images

    if nargin < 2
        L_white = max(hdr_image(:));  % 最大亮度值
    end
    if nargin < 3
        a = 0.18;  % 关键值
    end
    
    % 转换为亮度
    L = 0.2126 * hdr_image(:,:,1) + 0.7152 * hdr_image(:,:,2) + 0.0722 * hdr_image(:,:,3);
    
    % 计算场景平均亮度(对数平均)
    delta = 1e-6;
    L_avg = exp(mean(log(L + delta)));
    
    % 尺度缩放
    L_scaled = (a / L_avg) * L;
    
    % Reinhard色调映射算子
    L_display = L_scaled .* (1 + L_scaled / (L_white^2)) ./ (1 + L_scaled);
    
    % 恢复颜色
    ldr_image = zeros(size(hdr_image));
    for c = 1:3
        ldr_image(:,:,c) = (hdr_image(:,:,c) ./ L) .* L_display;
    end
end

function ldr_image = durand_tone_mapping(hdr_image, base_contrast, detail_contrast)
% Durand快速双边滤波色调映射
% 分离基础层和细节层

    if nargin < 2
        base_contrast = 5.0;
    end
    if nargin < 3
        detail_contrast = 1.5;
    end
    
    % 转换为亮度
    L = 0.2126 * hdr_image(:,:,1) + 0.7152 * hdr_image(:,:,2) + 0.0722 * hdr_image(:,:,3);
    
    % 对数变换
    log_L = log10(L + 1e-6);
    
    % 双边滤波分离基础层和细节层
    base_layer = bilateral_filter(log_L, 0.4, 0.1);
    detail_layer = log_L - base_layer;
    
    % 压缩基础层的动态范围
    log_base_compressed = (base_layer - max(base_layer(:))) * base_contrast + max(base_layer(:));
    
    % 增强细节层
    detail_enhanced = detail_layer * detail_contrast;
    
    % 重建对数亮度
    log_output = log_base_compressed + detail_enhanced;
    
    % 指数变换回线性空间
    L_output = 10.^(log_output);
    
    % 恢复颜色
    ldr_image = zeros(size(hdr_image));
    for c = 1:3
        ldr_image(:,:,c) = (hdr_image(:,:,c) ./ L) .* L_output;
    end
end

function filtered = bilateral_filter(image, sigma_spatial, sigma_range)
% 双边滤波实现
    [height, width] = size(image);
    filtered = zeros(size(image));
    
    % 空间高斯核
    spatial_size = ceil(3 * sigma_spatial);
    [X, Y] = meshgrid(-spatial_size:spatial_size, -spatial_size:spatial_size);
    spatial_kernel = exp(-(X.^2 + Y.^2) / (2 * sigma_spatial^2));
    
    for i = 1:height
        for j = 1:width
            % 计算局部窗口
            i_min = max(1, i - spatial_size);
            i_max = min(height, i + spatial_size);
            j_min = max(1, j - spatial_size);
            j_max = min(width, j + spatial_size);
            
            % 提取局部区域
            local_region = image(i_min:i_max, j_min:j_max);
            
            % 范围核
            range_kernel = exp(-(local_region - image(i,j)).^2 / (2 * sigma_range^2));
            
            % 组合核
            combined_kernel = spatial_kernel(...
                (i_min:i_max)-i+spatial_size+1, ...
                (j_min:j_max)-j+spatial_size+1) .* range_kernel;
            
            % 归一化并滤波
            combined_kernel = combined_kernel / sum(combined_kernel(:));
            filtered(i,j) = sum(sum(local_region .* combined_kernel));
        end
    end
end

4. 完整的HDR生成系统

function hdr_pipeline_demo()
% 完整的HDR图像生成演示系统

    fprintf('=== HDR图像生成管道演示 ===\n\n');
    
    % 1. 生成或加载多曝光图像序列
    fprintf('1. 准备多曝光图像序列...\n');
    [images, exposure_times] = generate_test_exposure_sequence();
    
    % 2. 估计相机响应函数
    fprintf('2. 估计相机响应函数...\n');
    [g, lnE] = estimate_camera_response(images, exposure_times, 50);
    
    % 3. 合成HDR图像
    fprintf('3. 合成HDR图像...\n');
    hdr_image = generate_hdr_multi_exposure(images, exposure_times);
    
    % 4. 色调映射
    fprintf('4. 色调映射处理...\n');
    ldr_results = apply_tone_mapping_methods(hdr_image);
    
    % 5. 质量评估和结果显示
    fprintf('5. 评估和显示结果...\n');
    evaluate_and_display_results(images, hdr_image, ldr_results, exposure_times, g);
    
    fprintf('HDR管道处理完成!\n');
end

function [images, exposure_times] = generate_test_exposure_sequence()
% 生成测试多曝光图像序列
% 如果没有真实数据,使用合成图像演示

    fprintf('生成合成多曝光图像序列...\n');
    
    % 创建合成HDR场景(高动态范围)
    [X, Y] = meshgrid(1:512, 1:512);
    center_x = 256; center_y = 256;
    
    % 创建不同亮度的区域
    hdr_scene = zeros(512, 512, 3);
    
    % 暗区域
    dark_region = ((X - 100).^2 + (Y - 100).^2) < 50^2;
    hdr_scene(:,:,1) = hdr_scene(:,:,1) + 0.1 * dark_region;  % 很暗的红色
    
    % 中等亮度区域
    mid_region = ((X - 256).^2 + (Y - 256).^2) < 100^2;
    hdr_scene(:,:,2) = hdr_scene(:,:,2) + 1.0 * mid_region;   % 中等绿色
    
    % 高亮区域
    bright_region = ((X - 400).^2 + (Y - 400).^2) < 30^2;
    hdr_scene(:,:,3) = hdr_scene(:,:,3) + 10.0 * bright_region; % 很亮的蓝色
    
    % 背景纹理
    background = 0.3 + 0.1 * sin(X/20) .* cos(Y/15);
    hdr_scene = hdr_scene + repmat(background, [1, 1, 3]);
    
    % 生成不同曝光的LDR图像
    exposure_times = [0.03125, 0.0625, 0.125, 0.25, 0.5, 1, 2, 4, 8];
    num_exposures = length(exposure_times);
    images = cell(num_exposures, 1);
    
    for i = 1:num_exposures
        % 模拟相机响应(简单的gamma曲线)
        exposed = min(1, hdr_scene * exposure_times(i));
        exposed = exposed .^ (1/2.2);  % gamma校正
        
        % 添加噪声
        exposed = exposed + 0.01 * randn(size(exposed));
        images{i} = max(0, min(1, exposed));
        
        fprintf('  曝光时间 %.4f: 动态范围 [%.3f, %.3f]\n', ...
                exposure_times(i), min(exposed(:)), max(exposed(:)));
    end
end

function ldr_results = apply_tone_mapping_methods(hdr_image)
% 应用不同的色调映射方法
    
    fprintf('应用不同的色调映射算法...\n');
    
    ldr_results = struct();
    
    % Reinhard方法
    fprintf('  - Reinhard色调映射...\n');
    ldr_results.reinhard = tone_mapping(hdr_image, 'reinhard');
    
    % Durand方法
    fprintf('  - Durand色调映射...\n');
    ldr_results.durand = tone_mapping(hdr_image, 'durand');
    
    % Gamma方法(简单对比)
    fprintf('  - Gamma色调映射...\n');
    ldr_results.gamma = tone_mapping(hdr_image, 'gamma', 2.2, 0.5);
    
    % 直方图均衡化方法
    fprintf('  - 直方图均衡化...\n');
    ldr_results.histeq = histogram_equalization_tone_mapping(hdr_image);
end

function ldr_image = gamma_tone_mapping(hdr_image, gamma_value, scale)
% 简单的gamma色调映射
    if nargin < 2
        gamma_value = 2.2;
    end
    if nargin < 3
        scale = 1.0;
    end
    
    % 归一化并应用gamma校正
    ldr_image = scale * hdr_image / max(hdr_image(:));
    ldr_image = ldr_image .^ (1/gamma_value);
end

function ldr_image = histogram_equalization_tone_mapping(hdr_image)
% 基于直方图均衡化的色调映射
    ldr_image = zeros(size(hdr_image));
    
    for c = 1:3
        channel = hdr_image(:,:,c);
        
        % 对数变换压缩动态范围
        log_channel = log10(channel + 1e-6);
        log_channel = (log_channel - min(log_channel(:))) / ...
                     (max(log_channel(:)) - min(log_channel(:)));
        
        % 直方图均衡化
        ldr_image(:,:,c) = histeq(log_channel);
    end
end

5. 质量评估和可视化

function evaluate_and_display_results(images, hdr_image, ldr_results, exposure_times, camera_response)
% 评估HDR生成质量并显示结果

    fprintf('评估结果质量...\n');
    
    figure('Position', [100, 100, 1400, 1000]);
    
    % 1. 显示多曝光输入序列
    num_inputs = min(6, length(images));
    for i = 1:num_inputs
        subplot(4, num_inputs, i);
        imshow(images{i});
        title(sprintf('曝光: %.4f', exposure_times(i)));
    end
    
    % 2. 显示相机响应函数
    subplot(4, 3, 7);
    if exist('camera_response', 'var') && ~isempty(camera_response)
        plot(0:255, camera_response, 'b-', 'LineWidth', 2);
        title('估计的相机响应函数');
        xlabel('像素值');
        ylabel('log曝光量');
        grid on;
    end
    
    % 3. 显示HDR图像统计
    subplot(4, 3, 8);
    hdr_luminance = 0.2126 * hdr_image(:,:,1) + 0.7152 * hdr_image(:,:,2) + 0.0722 * hdr_image(:,:,3);
    hist(log10(hdr_luminance(:) + 1e-6), 50);
    title('HDR亮度分布(对数)');
    xlabel('log10(亮度)');
    ylabel('频率');
    grid on;
    
    % 4. 显示动态范围
    subplot(4, 3, 9);
    dr_info = calculate_dynamic_range(hdr_image);
    bar(dr_info.range_per_channel);
    title('各通道动态范围');
    xlabel('颜色通道');
    ylabel('动态范围 (log10)');
    grid on;
    
    % 5. 显示不同色调映射结果
    methods = fieldnames(ldr_results);
    for i = 1:length(methods)
        subplot(4, 3, 9 + i);
        imshow(ldr_results.(methods{i}));
        title([methods{i} ' 色调映射']);
    end
    
    % 6. 质量评估指标
    fprintf('\n=== 质量评估结果 ===\n');
    evaluate_tone_mapping_quality(hdr_image, ldr_results);
end

function dr_info = calculate_dynamic_range(hdr_image)
% 计算HDR图像的动态范围
    dr_info = struct();
    
    for c = 1:3
        channel = hdr_image(:,:,c);
        valid_pixels = channel > 0;
        
        if sum(valid_pixels(:)) > 0
            min_val = min(channel(valid_pixels));
            max_val = max(channel(valid_pixels));
            dr_info.range_per_channel(c) = log10(max_val / min_val);
        else
            dr_info.range_per_channel(c) = 0;
        end
    end
    
    dr_info.average_dynamic_range = mean(dr_info.range_per_channel);
    fprintf('平均动态范围: %.2f log10单位\n', dr_info.average_dynamic_range);
end

function evaluate_tone_mapping_quality(hdr_reference, ldr_results)
% 评估色调映射结果的质量
    
    methods = fieldnames(ldr_results);
    
    fprintf('\n%-15s %-12s %-12s %-12s\n', ...
            '方法', '对比度', '信息熵', '色彩饱和度');
    fprintf('%-15s %-12s %-12s %-12s\n', ...
            '------', '------', '------', '----------');
    
    for i = 1:length(methods)
        ldr_image = ldr_results.(methods{i});
        
        % 对比度(标准差)
        contrast = std(ldr_image(:));
        
        % 信息熵
        entropy_val = calculate_image_entropy(ldr_image);
        
        % 色彩饱和度
        color_saturation = calculate_color_saturation(ldr_image);
        
        fprintf('%-15s %-12.4f %-12.4f %-12.4f\n', ...
                methods{i}, contrast, entropy_val, color_saturation);
    end
end

function entropy_val = calculate_image_entropy(image)
% 计算图像的信息熵
    if size(image, 3) == 3
        image = rgb2gray(image);
    end
    
    % 计算直方图
    [counts, ~] = histcounts(image(:), 256);
    probabilities = counts / sum(counts);
    probabilities = probabilities(probabilities > 0);
    
    entropy_val = -sum(probabilities .* log2(probabilities));
end

function saturation = calculate_color_saturation(rgb_image)
% 计算图像的平均色彩饱和度
    hsv_image = rgb2hsv(rgb_image);
    saturation = mean(hsv_image(:,:,2), 'all');
end

6. 高级HDR技术

function advanced_hdr_techniques_demo()
% 高级HDR技术演示
    
    fprintf('=== 高级HDR技术演示 ===\n\n');
    
    % 1. 曝光融合(不生成显式HDR)
    fprintf('1. 曝光融合技术...\n');
    exposure_fusion_result = exposure_fusion(images, exposure_times);
    
    % 2. 抗鬼影处理
    fprintf('2. 抗鬼影处理...\n');
    ghost_free_hdr = ghost_removal_hdr(images, exposure_times);
    
    % 3. 单图像HDR重建
    fprintf('3. 单图像HDR重建...\n');
    single_image_hdr = single_image_hdr_reconstruction(images{ceil(end/2)});
    
    % 显示比较结果
    figure('Position', [100, 100, 1200, 800]);
    
    subplot(2, 2, 1);
    imshow(exposure_fusion_result);
    title('曝光融合结果');
    
    subplot(2, 2, 2);
    imshow(tone_mapping(ghost_free_hdr, 'reinhard'));
    title('抗鬼影HDR');
    
    subplot(2, 2, 3);
    imshow(tone_mapping(single_image_hdr, 'reinhard'));
    title('单图像HDR重建');
    
    subplot(2, 2, 4);
    % 显示算法比较
    plot_algorithm_comparison();
end

function fused_image = exposure_fusion(images, exposure_times)
% 曝光融合:直接在LDR空间融合多曝光图像
    
    num_images = length(images);
    weight_maps = cell(num_images, 1);
    
    % 为每张图像计算质量权重图
    for i = 1:num_images
        img = im2double(images{i});
        
        % 计算对比度(使用拉普拉斯滤波)
        contrast = abs(imfilter(rgb2gray(img), fspecial('laplacian')));
        
        % 计算饱和度(颜色标准差)
        saturation = std(img, [], 3);
        
        % 计算曝光良好度(高斯函数,以0.5为中心)
        well_exposed = exp(-(rgb2gray(img) - 0.5).^2 / (2 * 0.2^2));
        
        % 组合权重图
        weight_maps{i} = contrast .* saturation .* well_exposed + 1e-6;
    end
    
    % 归一化权重图
    total_weight = zeros(size(weight_maps{1}));
    for i = 1:num_images
        total_weight = total_weight + weight_maps{i};
    end
    
    % 多分辨率融合(金字塔融合)
    fused_image = pyramid_fusion(images, weight_maps);
end

function fused_image = pyramid_fusion(images, weight_maps)
% 使用拉普拉斯金字塔进行多分辨率融合
    
    num_levels = 5;
    num_images = length(images);
    
    % 为每张图像构建拉普拉斯金字塔和权重高斯金字塔
    laplacian_pyramids = cell(num_images, 1);
    gaussian_pyramids = cell(num_images, 1);
    
    for i = 1:num_images
        laplacian_pyramids{i} = laplacian_pyramid(images{i}, num_levels);
        gaussian_pyramids{i} = gaussian_pyramid(weight_maps{i}, num_levels);
    end
    
    % 融合金字塔
    fused_pyramid = laplacian_pyramids{1};
    for l = 1:num_levels
        level_weights = zeros([size(gaussian_pyramids{1}{l}), num_images]);
        for i = 1:num_images
            level_weights(:,:,i) = gaussian_pyramids{i}{l};
        end
        
        % 归一化权重
        level_weights = level_weights ./ sum(level_weights, 3);
        
        % 加权融合
        if l <= num_levels
            fused_level = zeros(size(laplacian_pyramids{1}{l}));
            for i = 1:num_images
                weight_expanded = repmat(level_weights(:,:,i), [1, 1, size(images{i}, 3)]);
                fused_level = fused_level + weight_expanded .* laplacian_pyramids{i}{l};
            end
            fused_pyramid{l} = fused_level;
        end
    end
    
    % 重建融合图像
    fused_image = reconstruct_laplacian_pyramid(fused_pyramid);
end

参考代码 HDR图像生成的算法 www.youwenfan.com/contentcnj/66127.html

使用方法

  1. 基本HDR生成
% 运行完整的HDR管道
hdr_pipeline_demo();
  1. 自定义图像序列
% 加载自己的多曝光图像
image_files = {'exp1.jpg', 'exp2.jpg', 'exp3.jpg'};
exposure_times = [1/30, 1/15, 1/8]; % 对应的曝光时间

images = cell(length(image_files), 1);
for i = 1:length(image_files)
    images{i} = imread(image_files{i});
end

% 生成HDR
hdr_image = generate_hdr_multi_exposure(images, exposure_times);
  1. 高级功能
% 运行高级HDR技术演示
advanced_hdr_techniques_demo();
posted @ 2025-10-15 16:53  yu8yu7  阅读(90)  评论(0)    收藏  举报