MATLAB TV去噪程序

基于全变分(Total Variation, TV)的图像去噪MATLAB实现

%% TV去噪程序
% 功能: 实现多种TV模型的图像去噪
% 模型: ROF, LLT, CD, FGP-TV等

clear; clc; close all;

%% 1. 参数设置
% 图像参数
imagePath = 'lena_gray.png'; % 输入图像路径
noiseLevel = 0.1;            % 噪声水平 (0-1)
useCustomImage = true;       % 使用自定义图像

% TV模型参数
lambda = 0.07;               % 正则化参数 (典型值: 0.01-0.2)
modelType = 'ROF';           % 模型类型: 'ROF', 'LLT', 'CD', 'FGP'
iterations = 100;            % 迭代次数
stepSize = 0.125;            % 梯度下降步长
epsilon = 1e-3;              % 平滑参数 (避免除零)

% 高级参数
adaptLambda = true;          % 自适应调整lambda
displayInterval = 10;        % 显示间隔
saveResults = true;          % 保存结果

%% 2. 图像准备
if useCustomImage
    % 加载自定义图像
    try
        noisyImg = imread(imagePath);
        if size(noisyImg, 3) == 3
            noisyImg = rgb2gray(noisyImg);
        end
        noisyImg = im2double(noisyImg);
    catch
        warning('无法加载图像,使用默认测试图像');
        noisyImg = phantom(256);
        noisyImg = im2double(noisyImg);
    end
else
    % 生成测试图像
    [x, y] = meshgrid(linspace(-1, 1, 256));
    noisyImg = exp(-5*(x.^2 + y.^2));
    noisyImg = noisyImg/max(noisyImg(:));
end

% 添加高斯噪声
noisyImg = imnoise(noisyImg, 'gaussian', 0, noiseLevel);

% 显示原始噪声图像
figure('Name', '输入图像', 'NumberTitle', 'off');
subplot(121), imshow(noisyImg), title('含噪图像');
subplot(122), imhist(noisyImg), title('噪声图像直方图');

%% 3. TV去噪核心算法
% 初始化
denoisedImg = noisyImg;
[M, N] = size(noisyImg);

% 自适应调整lambda
if adaptLambda
    lambda = estimateOptimalLambda(noisyImg, modelType);
    fprintf('自适应调整lambda: %.4f\n', lambda);
end

% 选择模型
switch lower(modelType)
    case 'rof'
        denoisedImg = ROF_Denoising(noisyImg, lambda, iterations, stepSize, epsilon);
    case 'llt'
        denoisedImg = LLT_Denoising(noisyImg, lambda, iterations, stepSize, epsilon);
    case 'cd'
        denoisedImg = CD_Denoising(noisyImg, lambda, iterations, stepSize, epsilon);
    case 'fgp'
        denoisedImg = FGP_TV_Denoising(noisyImg, lambda, iterations, stepSize, epsilon);
    otherwise
        error('未知模型类型: %s', modelType);
end

% 显示结果
figure('Name', '去噪结果', 'NumberTitle', 'off', 'Position', [100, 100, 1200, 500]);
subplot(131), imshow(noisyImg), title('含噪图像');
subplot(132), imshow(denoisedImg), title(sprintf('%s去噪结果', modelType));
subplot(133), imshowpair(noisyImg, denoisedImg, 'montage'), title('对比');

%% 4. 结果评估
% 计算PSNR
psnrNoisy = psnr(noisyImg, denoisedImg);
psnrClean = psnr(idealImg, denoisedImg); % 需要原始干净图像

% 计算SSIM
ssimNoisy = ssim(denoisedImg, noisyImg);
ssimClean = ssim(denoisedImg, idealImg); % 需要原始干净图像

% 计算RMSE
rmse = sqrt(mean((denoisedImg(:) - noisyImg(:)).^2));

fprintf('===== 评估结果 =====\n');
fprintf('模型: %s\n', modelType);
fprintf('噪声水平: %.2f\n', noiseLevel);
fprintf('正则化参数λ: %.4f\n', lambda);
fprintf('PSNR: %.2f dB\n', psnrNoisy);
fprintf('SSIM: %.4f\n', ssimNoisy);
fprintf('RMSE: %.4f\n', rmse);

%% 5. 参数敏感性分析
% 扫描lambda参数
lambdaRange = linspace(0.01, 0.2, 10);
psnrValues = zeros(size(lambdaRange));
ssimValues = zeros(size(lambdaRange));

for i = 1:length(lambdaRange)
    tempImg = ROF_Denoising(noisyImg, lambdaRange(i), iterations, stepSize, epsilon);
    psnrValues(i) = psnr(tempImg, noisyImg);
    ssimValues(i) = ssim(tempImg, noisyImg);
end

% 绘制参数敏感性曲线
figure('Name', '参数敏感性分析', 'NumberTitle', 'off');
subplot(211), plot(lambdaRange, psnrValues, 'bo-');
xlabel('正则化参数λ');
ylabel('PSNR (dB)');
title('PSNR随λ的变化');
grid on;

subplot(212), plot(lambdaRange, ssimValues, 'rs-');
xlabel('正则化参数λ');
ylabel('SSIM');
title('SSIM随λ的变化');
grid on;

%% 6. 模型比较
models = {'ROF', 'LLT', 'CD', 'FGP'};
psnrComparison = zeros(1, length(models));
ssimComparison = zeros(1, length(models));

for i = 1:length(models)
    switch models{i}
        case 'ROF'
            result = ROF_Denoising(noisyImg, lambda, iterations, stepSize, epsilon);
        case 'LLT'
            result = LLT_Denoising(noisyImg, lambda, iterations, stepSize, epsilon);
        case 'CD'
            result = CD_Denoising(noisyImg, lambda, iterations, stepSize, epsilon);
        case 'FGP'
            result = FGP_TV_Denoising(noisyImg, lambda, iterations, stepSize, epsilon);
    end
    psnrComparison(i) = psnr(result, noisyImg);
    ssimComparison(i) = ssim(result, noisyImg);
end

% 绘制模型比较图
figure('Name', '模型比较', 'NumberTitle', 'off');
subplot(211), bar(psnrComparison);
set(gca, 'XTickLabel', models);
ylabel('PSNR (dB)');
title('不同模型的PSNR比较');
grid on;

subplot(212), bar(ssimComparison);
set(gca, 'XTickLabel', models);
ylabel('SSIM');
title('不同模型的SSIM比较');
grid on;

%% 7. 高级TV模型实现
% ROF模型 (Rudin-Osher-Fatemi)
function u = ROF_Denoising(f, lambda, maxIter, tau, eps)
    [M, N] = size(f);
    u = f; % 初始化
    
    for iter = 1:maxIter
        % 计算梯度
        ux = [diff(u, 1, 2), zeros(M, 1)];
        uy = [diff(u, 1, 1); zeros(1, N)];
        
        % 计算梯度模
        gradMag = sqrt(ux.^2 + uy.^2 + eps);
        
        % 计算散度
        px = ux ./ gradMag;
        py = uy ./ gradMag;
        div_p = [px(:,1), diff(px, 1, 2), -px(:,end)] + ...
                [py(1,:); diff(py, 1, 1); -py(end,:)];
        
        % 更新图像
        u = u + tau * (lambda * (f - u) + div_p);
        
        % 显示进度
        if mod(iter, displayInterval) == 0
            fprintf('ROF: Iteration %d/%d\n', iter, maxIter);
        end
    end
end

% LLT模型 (Local Laplacian Filter)
function u = LLT_Denoising(f, lambda, maxIter, tau, eps)
    [M, N] = size(f);
    u = f;
    
    for iter = 1:maxIter
        % 计算局部拉普拉斯算子
        laplacian = del2(u);
        
        % 更新图像
        u = u + tau * (lambda * (f - u) - laplacian);
        
        % 显示进度
        if mod(iter, displayInterval) == 0
            fprintf('LLT: Iteration %d/%d\n', iter, maxIter);
        end
    end
end

% CD模型 (Curvature Diffusion)
function u = CD_Denoising(f, lambda, maxIter, tau, eps)
    [M, N] = size(f);
    u = f;
    
    for iter = 1:maxIter
        % 计算梯度
        ux = [diff(u, 1, 2), zeros(M, 1)];
        uy = [diff(u, 1, 1); zeros(1, N)];
        
        % 计算曲率
        curvature = (uxx.*uyy - uxy.^2) ./ (ux.^2 + uy.^2 + eps).^(3/2);
        
        % 更新图像
        u = u + tau * (lambda * (f - u) + curvature);
        
        % 显示进度
        if mod(iter, displayInterval) == 0
            fprintf('CD: Iteration %d/%d\n', iter, maxIter);
        end
    end
end

% FGP-TV模型 (Fast Gradient Projection)
function u = FGP_TV_Denoising(f, lambda, maxIter, tau, eps)
    [M, N] = size(f);
    u = f;
    
    for iter = 1:maxIter
        % 计算梯度
        ux = [diff(u, 1, 2), zeros(M, 1)];
        uy = [diff(u, 1, 1); zeros(1, N)];
        
        % 计算梯度模
        gradMag = sqrt(ux.^2 + uy.^2 + eps);
        
        % 投影梯度
        proj = max(0, 1 - 1./(lambda*gradMag));
        px = ux .* proj;
        py = uy .* proj;
        
        % 计算散度
        div_p = [px(:,1), diff(px, 1, 2), -px(:,end)] + ...
                [py(1,:); diff(py, 1, 1); -py(end,:)];
        
        % 更新图像
        u = u + tau * (div_p - lambda * f);
        
        % 显示进度
        if mod(iter, displayInterval) == 0
            fprintf('FGP-TV: Iteration %d/%d\n', iter, maxIter);
        end
    end
end

%% 8. 辅助函数
% 估计最优lambda
function lambda_opt = estimateOptimalLambda(noisyImg, modelType)
    % 使用L曲线法估计最优lambda
    lambdaRange = logspace(-3, 0, 10);
    residualNorm = zeros(size(lambdaRange));
    regularizationNorm = zeros(size(lambdaRange));
    
    for i = 1:length(lambdaRange)
        tempImg = ROF_Denoising(noisyImg, lambdaRange(i), 50, 0.1, 1e-3);
        residualNorm(i) = norm(tempImg(:) - noisyImg(:), 2);
        regularizationNorm(i) = norm(gradient(tempImg), 'fro');
    end
    
    % 寻找曲率最大点
    curvature = computeCurvature(lambdaRange, residualNorm);
    [~, idx] = max(curvature);
    lambda_opt = lambdaRange(idx);
end

% 计算曲率
function curvature = computeCurvature(x, y)
    dx = gradient(x);
    dy = gradient(y);
    ddx = gradient(dx);
    ddy = gradient(dy);
    curvature = abs(dx .* ddy - dy .* ddx) ./ (dx.^2 + dy.^2).^(3/2);
end

% 计算SSIM
function ssimValue = ssim(img1, img2)
    K = [0.01, 0.03];
    L = 1; % 动态范围
    C1 = (K(1)*L)^2;
    C2 = (K(2)*L)^2;
    C3 = C2/2;
    
    mu1 = filter2(fspecial('average', 11), img1, 'same');
    mu2 = filter2(fspecial('average', 11), img2, 'same');
    
    mu1_sq = mu1.^2;
    mu2_sq = mu2.^2;
    mu1_mu2 = mu1.*mu2;
    
    sigma1_sq = filter2(fspecial('average', 11), img1.^2, 'same') - mu1_sq;
    sigma2_sq = filter2(fspecial('average', 11), img2.^2, 'same') - mu2_sq;
    sigma12 = filter2(fspecial('average', 11), img1.*img2, 'same') - mu1_mu2;
    
    luminance = (2*mu1_mu2 + C1) ./ (mu1_sq + mu2_sq + C1);
    contrast = (2*sqrt(sigma1_sq.*sigma2_sq) + C2) ./ (sigma1_sq + sigma2_sq + C2);
    structure = (sigma12 + C3) ./ (sqrt(sigma1_sq.*sigma2_sq) + C3);
    
    ssimValue = mean(luminance .* contrast .* structure, 'all');
end

%% 9. 可视化分析
% 残差分析
residual = denoisedImg - noisyImg;
figure('Name', '残差分析', 'NumberTitle', 'off');
subplot(221), imshow(residual, []), title('残差图像');
subplot(222), histogram(residual, 50), title('残差直方图');
subplot(223), imshow(log(abs(fftshift(fft2(residual)))), []), title('残差频谱');
subplot(224), plot(sort(residual(:))), title('残差排序');

% 梯度分析
[Gx, Gy] = gradient(denoisedImg);
gradientMagnitude = sqrt(Gx.^2 + Gy.^2);

figure('Name', '梯度分析', 'NumberTitle', 'off');
subplot(131), imshow(Gx, []), title('水平梯度');
subplot(132), imshow(Gy, []), title('垂直梯度');
subplot(133), imshow(gradientMagnitude, []), title('梯度幅值');

% 边缘保持分析
edgesNoisy = edge(noisyImg, 'canny');
edgesDenoised = edge(denoisedImg, 'canny');

figure('Name', '边缘保持分析', 'NumberTitle', 'off');
subplot(131), imshow(noisyImg), title('含噪图像');
subplot(132), imshow(edgesNoisy), title('噪声图像边缘');
subplot(133), imshow(edgesDenoised), title('去噪图像边缘');

%% 10. 高级应用
% 彩色图像去噪
function denoisedColor = tvDenoiseColor(colorImg, lambda, modelType)
    % 转换到Lab颜色空间
    labImg = rgb2lab(colorImg);
    L = labImg(:,:,1)/100;
    a = labImg(:,:,2)/120;
    b = labImg(:,:,3)/120;
    
    % 对每个通道去噪
    L_denoised = ROF_Denoising(L, lambda, 100, 0.1, 1e-3);
    a_denoised = ROF_Denoising(a, lambda*0.8, 100, 0.1, 1e-3);
    b_denoised = ROF_Denoising(b, lambda*0.8, 100, 0.1, 1e-3);
    
    % 合并通道
    labDenoised = cat(3, L_denoised*100, a_denoised*120, b_denoised*120);
    denoisedColor = lab2rgb(labDenoised);
end

% 视频去噪 (帧处理)
function denoisedVideo = tvDenoiseVideo(videoPath, lambda)
    videoReader = VideoReader(videoPath);
    denoisedVideo = VideoWriter('denoised_video.mp4', 'MPEG-4');
    denoisedVideo.FrameRate = videoReader.FrameRate;
    open(denoisedVideo);
    
    while hasFrame(videoReader)
        frame = readFrame(videoReader);
        if size(frame, 3) == 3
            denoisedFrame = tvDenoiseColor(frame, lambda, 'ROF');
        else
            denoisedFrame = ROF_Denoising(im2double(frame), lambda, 50, 0.1, 1e-3);
        end
        writeVideo(denoisedVideo, denoisedFrame);
    end
    close(denoisedVideo);
end

%% 11. 保存结果
if saveResults
    % 保存去噪图像
    imwrite(denoisedImg, sprintf('denoised_%s.png', modelType));
    
    % 保存评估结果
    results = struct('Model', modelType, ...
                    'NoiseLevel', noiseLevel, ...
                    'Lambda', lambda, ...
                    'PSNR', psnrNoisy, ...
                    'SSIM', ssimNoisy, ...
                    'RMSE', rmse);
    save('tv_denoising_results.mat', 'results');
    
    % 保存中间结果
    save('intermediate_results.mat', 'noisyImg', 'denoisedImg', 'lambdaRange', ...
         'psnrValues', 'ssimValues');
end

%% 12. 性能优化技巧
% 使用GPU加速
function u = ROF_GPU(f, lambda, maxIter, tau, eps)
    if gpuDeviceCount > 0
        f_gpu = gpuArray(f);
        u_gpu = f_gpu;
        
        for iter = 1:maxIter
            % GPU加速计算
            ux = [diff(u_gpu, 1, 2), zeros(size(u_gpu,1), 1, 'gpuArray')];
            uy = [diff(u_gpu, 1, 1); zeros(1, size(u_gpu,2), 'gpuArray')];
            
            gradMag = sqrt(ux.^2 + uy.^2 + eps);
            px = ux ./ gradMag;
            py = uy ./ gradMag;
            
            div_p = [px(:,1), diff(px, 1, 2), -px(:,end)] + ...
                    [py(1,:); diff(py, 1, 1); -py(end,:)];
            
            u_gpu = u_gpu + tau * (lambda * (f_gpu - u_gpu) + div_p);
        end
        
        u = gather(u_gpu);
    else
        u = ROF_Denoising(f, lambda, maxIter, tau, eps);
    end
end

% 多分辨率处理
function u = multiResTV(f, lambda, levels)
    % 金字塔下采样
    pyramid = cell(levels, 1);
    pyramid{1} = f;
    for i = 2:levels
        pyramid{i} = imresize(pyramid{i-1}, 0.5);
    end
    
    % 从粗到细处理
    u = pyramid{levels};
    for i = levels:-1:1
        if i < levels
            u = imresize(u, size(pyramid{i}));
        end
        u = ROF_Denoising(u, lambda/levels, 20, 0.1, 1e-3);
    end
end

TV去噪原理与模型

1. 全变分去噪基本原理

全变分去噪基于变分原理,通过最小化能量泛函来去除噪声:

E(u) = ∫_Ω |∇u| dx + λ/2 ∫_Ω (u - f)^2 dx

其中:

  • u是去噪后的图像
  • f是含噪图像
  • λ是正则化参数
  • |∇u|是梯度的L1范数(全变分)

2. 主要TV模型比较

模型 全称 特点 适用场景
ROF Rudin-Osher-Fatemi 基础TV模型,保留边缘好 通用去噪
LLT Local Laplacian Filter 局部自适应平滑 纹理保留
CD Curvature Diffusion 基于曲率的扩散 医学图像
FGP-TV Fast Gradient Projection 快速投影算法 实时处理

3. 数值求解方法

  • 梯度下降法:简单直观,但收敛慢
  • Chambolle对偶法:高效精确,适合ROF模型
  • Split-Bregman:处理复杂约束,速度快
  • Proximal梯度法:处理非光滑问题

关键功能模块

1. 核心去噪算法

function u = ROF_Denoising(f, lambda, maxIter, tau, eps)
    u = f; % 初始化
    for iter = 1:maxIter
        % 计算梯度
        ux = [diff(u, 1, 2), zeros(M, 1)];
        uy = [diff(u, 1, 1); zeros(1, N)];
        
        % 计算梯度模
        gradMag = sqrt(ux.^2 + uy.^2 + eps);
        
        % 计算散度
        px = ux ./ gradMag;
        py = uy ./ gradMag;
        div_p = computeDivergence(px, py);
        
        % 更新图像
        u = u + tau * (lambda * (f - u) + div_p);
    end
end

2. 参数优化模块

% 自适应调整lambda
function lambda_opt = estimateOptimalLambda(noisyImg, modelType)
    lambdaRange = logspace(-3, 0, 10);
    for i = 1:length(lambdaRange)
        tempImg = ROF_Denoising(noisyImg, lambdaRange(i), 50, 0.1, 1e-3);
        residualNorm(i) = norm(tempImg(:) - noisyImg(:), 2);
        regularizationNorm(i) = norm(gradient(tempImg), 'fro');
    end
    % 寻找L曲线拐点
    curvature = computeCurvature(lambdaRange, residualNorm);
    [~, idx] = max(curvature);
    lambda_opt = lambdaRange(idx);
end

3. 性能评估模块

% 计算PSNR
psnrValue = psnr(denoisedImg, noisyImg);

% 计算SSIM
ssimValue = ssim(denoisedImg, noisyImg);

% 计算RMSE
rmse = sqrt(mean((denoisedImg(:) - noisyImg(:)).^2));

4. 高级处理模块

% 彩色图像去噪
function denoisedColor = tvDenoiseColor(colorImg, lambda, modelType)
    labImg = rgb2lab(colorImg);
    L = labImg(:,:,1)/100;
    a = labImg(:,:,2)/120;
    b = labImg(:,:,3)/120;
    
    L_denoised = ROF_Denoising(L, lambda, 100, 0.1, 1e-3);
    a_denoised = ROF_Denoising(a, lambda*0.8, 100, 0.1, 1e-3);
    b_denoised = ROF_Denoising(b, lambda*0.8, 100, 0.1, 1e-3);
    
    labDenoised = cat(3, L_denoised*100, a_denoised*120, b_denoised*120);
    denoisedColor = lab2rgb(labDenoised);
end

参数选择与优化

1. 正则化参数λ

  • 过小:去噪不足,残留噪声
  • 过大:过度平滑,丢失细节
  • 选择策略: 经验值:0.01-0.2 自适应估计:estimateOptimalLambda() L曲线法:平衡残差和正则化项

2. 迭代次数

  • 过少:收敛不充分
  • 过多:计算开销大,可能引入伪影
  • 建议值:50-200次

3. 步长τ

  • 过大:发散不收敛
  • 过小:收敛缓慢
  • 建议值:0.05-0.25

4. 平滑参数ε

  • 过小:数值不稳定
  • 过大:边缘模糊
  • 建议值:1e-3-1e-2

参考代码 TV去噪程序 www.youwenfan.com/contentcnp/83418.html

扩展功能

1. 非局部TV去噪

function u = NLTV_Denoising(f, lambda, patchSize, searchWindow)
    % 非局部均值思想与TV结合
    % 1. 计算图像块相似度
    % 2. 加权平均TV去噪
end

2. 复合噪声处理

function u = mixedNoiseTV(f, lambdaImpulse, lambdaGaussian)
    % 脉冲噪声检测
    impulseMask = detectImpulseNoise(f);
    
    % 分别处理
    u = f;
    u(impulseMask) = medianFilter(f(impulseMask)); % 中值滤波处理脉冲噪声
    u = ROF_Denoising(u, lambdaGaussian); % TV处理高斯噪声
end

3. 盲去卷积

function [u, kernel] = blindDeconvTV(f, lambda, maxIter)
    % 交替优化图像和模糊核
    u = f;
    kernel = ones(5,5)/25; % 初始核
    
    for iter = 1:maxIter
        % 固定核,更新图像
        u = ROF_Denoising(deconvblind(f, kernel), lambda);
        
        % 固定图像,更新核
        kernel = updateKernel(f, u);
    end
end

4. 深度学习结合

function u = deepTV_Denoising(f)
    % 预训练CNN提取特征
    features = cnnFeatureExtractor(f);
    
    % TV正则化优化
    u = ROF_Denoising(features, 0.05);
    
    % 后处理
    u = guidedFilter(u, f, 5, 0.1);
end
posted @ 2026-01-06 12:00  yes_go  阅读(11)  评论(0)    收藏  举报