基于字典学习的图像信号稀疏化分解方法(MATLAB 无工具箱版)

基于字典学习的图像信号稀疏化分解方法(MATLAB 无工具箱版)

流程:

  1. Overcomplete DCT 初始字典
  2. K-SVD 字典更新(逐原子+SVD)
  3. OMP 稀疏编码(逐块)
  4. 块坐标重建 + 重叠平均
  5. 输出:稀疏系数、学习字典、重构图像、PSNR/SSIM

一、文件列表说明

文件 功能
main_dict_learning.m 演示(去噪示例)
ksvd_dict_update.m K-SVD 字典更新
omp_sparse_coding.m OMP 稀疏编码
initial_dict.m Overcomplete DCT 初始字典
block_coord_recon.m 重叠块重建
psnr_ssim.m 基础评价指标

二、核心流程

原图 → 分块 → 初始字典 → OMP 稀疏编码 → K-SVD 更新字典 → 重叠重建 → 稀疏系数+重构

三、演示(main_dict_learning.m)

clear; clc; close all
%% 1. 读取图像(灰度)
img = imread('cameraman.png');
if size(img,3)==3, img=rgb2gray(img); end
img = im2double(img);  [H,W] = size(img);

%% 2. 参数
blockSize = 8;          % 8×8 块
overlap = 4;            % 50% 重叠
dictSize = 256;         % 字典原子数(2×完备)
maxIter = 20;           % K-SVD 迭代
sparsity = 4;           % OMP 稀疏度(非零系数)

%% 3. 初始字典(Overcomplete DCT)
D = initial_dict(blockSize, dictSize);

%% 4. 分块+向量化
blocks = im2col(img, [blockSize,blockSize], 'sliding');
nBlocks = size(blocks,2);

%% 5. 初始稀疏编码
X = zeros(dictSize, nBlocks);
for i = 1:nBlocks
    X(:,i) = omp_sparse_coding(blocks(:,i), D, sparsity);
end

%% 6. K-SVD 字典学习
for k = 1:maxIter
    % 稀疏保持,逐原子更新
    [D, X] = ksvd_dict_update(blocks, D, X, sparsity);
    fprintf('Iter %d  done\n', k);
end

%% 7. 重叠重建
img_rec = block_coord_recon(X, D, [H,W], blockSize, overlap);

%% 8. 评价
[psnrVal, ssimVal] = psnr_ssim(img_rec, img);
fprintf('PSNR = %.2f dB, SSIM = %.4f\n', psnrVal, ssimVal);

%% 9. 可视化
figure; montage({img, img_rec, abs(img-img_rec)}, 'Size', [1 3]);
title({'原图','重构','残差'});

四、核心函数

1. 初始字典(initial_dict.m)

function D = initial_dict(blockSize, dictSize)
% Overcomplete DCT 字典(列向量)
D0 = dctmtx(blockSize);              % 完备 DCT
D0 = D0(randperm(blockSize), :);     % 随机打乱行
D = [D0; D0];                         % 2×完备
D = D(1:dictSize, :);                % 取前 dictSize 行
D = D.';                             % 原子→列向量
D = D ./ vecnorm(D,2,1);             % 单位范数
end

2. OMP 稀疏编码(omp_sparse_coding.m)

function x = omp_sparse_coding(signal, D, sparsity)
% 标准 OMP(无工具箱)
[n, k] = size(D);
residual = signal;
x = zeros(k,1);
selected = [];

for i = 1:sparsity
    % 最大投影
    proj = abs(D.' * residual);
    [~, idx] = max(proj);
    selected = [selected; idx];
    % 最小二乘
    D_sel = D(:,selected);
    x_sel = (D_sel.' * D_sel) \ (D_sel.' * signal);
    residual = signal - D_sel * x_sel;
end
x(selected) = x_sel;
end

3. K-SVD 字典更新(ksvd_dict_update.m)

function [D, X] = ksvd_dict_update(Y, D, X, sparsity)
% 标准 K-SVD:逐原子更新
[n, k] = size(D);
for j = 1:k
    % 使用原子 j 的块
    used = find(X(j,:) ~= 0);
    if isempty(used), continue; end
    % 残差矩阵
    E = Y - D * X;  E(:,used) = E(:,used) + D(:,j) * X(j,used);
    % SVD
    [U,S,V] = svd(E(:,used), 'econ');
    D(:,j) = U(:,1);                  % 新原子
    X(j,used) = S(1,1) * V(:,1).';    % 新系数
    % 硬阈值保持稀疏
    [~, idx] = sort(abs(X(j,used)), 'descend');
    if numel(idx) > sparsity
        X(j,used(idx(sparsity+1:end))) = 0;
    end
end
end

4. 重叠重建(block_coord_recon.m)

function img = block_coord_recon(X, D, imgSize, blockSize, overlap)
% 重叠平均重建
[H,W] = imgSize;
step = blockSize - overlap;
count = zeros(H,W);
img = zeros(H,W);

colIdx = 0;
for r = 1:step:H-blockSize+1
    for c = 1:step:W-blockSize+1
        colIdx = colIdx + 1;
        blk = reshape(D * X(:,colIdx), blockSize, blockSize);
        img(r:r+blockSize-1, c:c+blockSize-1) = ...
            img(r:r+blockSize-1, c:c+blockSize-1) + blk;
        count(r:r+blockSize-1, c:c+blockSize-1) = ...
            count(r:r+blockSize-1, c:c+blockSize-1) + 1;
    end
end
img(count>0) = img(count>0) ./ count(count>0);
end

参考代码 通过字典学习更新的方法,对图像信号进行稀疏化分解 www.youwenfan.com/contentcsl/80213.html

五、常见扩展

  1. 去噪 → 在 main 里加高斯噪声,用相同流程低秩逼近
  2. 深度学习 → 把 K-SVD 换成 CNN 先验(留接口);
  3. 大图像 → 用 滑动窗口 + GPU 加速 SVD;
  4. 视频 → 沿时间轴做 3D 块 + Tucker 分解

 

专注于matlab/simulink,电子电路,编程