完整流程: 图像 → 稀疏化(小波/DCT分块)→ 降采样测量 → OMP重建 → 逆变换 → 评估
1)总体流程
原图 I₀ (N×N)
↓ 分块 / 全局变换
θ = Ψᵀ·I₀ ← 稀疏系数(小波/DCT)
↓ 测量矩阵 Φ (M×N, M≪N)
y = Φ·I₀ = Φ·Ψ·θ ← 仅 M 个线性测量
↓ CS重建(OMP)求解 θ̂(稀疏)
Î = Ψ·θ̂ ← 重建图
关键点:不用工具箱意味着我们要手搓 Haar 小波或分块 DCT,并手搓 OMP。
2)主脚本:cs_image_recon_demo.m
matlab
%% cs_image_recon_demo.m
clear; clc; close all;
%% 0. 读图
I = imread('cameraman.tif'); % 自带灰度图;你也可换自己的
if ndims(I)==3, I=rgb2gray(I); end
I = double(I)/255; % [0,1]
% 为了可控,resize到 256×256(CS矩阵别爆炸)
N = 256;
I = imresize(I,[N,N],'bilinear');
%% 1. 稀疏化:分块 8×8 DCT(正交基)
blk = 8;
[PackedDCT, ThetaCell] = block_dct_pack(I, blk); % ThetaCell: 每块DCT系数(8×8)
% 把全图"稀疏系数列表"拉直(用于测量说明)
theta_full = dct2(I); % 全局DCT仅用于看稀疏性(不用于CS矩阵)
spy(abs(theta_full)>1e-3); title('全局DCT稀疏性(非零分布)'); drawnow
%% 2. 测量矩阵 Φ(作用于矢量化图像 s=vec(I) )
M = round(0.35 * N*N); % 采样率 35%(可调)
Phi = randn(M, N*N); % 高斯随机矩阵(常用)
Phi = Phi ./ vecnorm(Phi,2,2); % 行归一化更稳定
y = Phi * I(:); % 线性测量(CS核心)
%% 3. CS重建:用块OMP(每块独立恢复)
% Ψ = 块DCT基,相当于每块做 IDCT
I_rec = block_cs_omp_recon(y, Phi, I, blk, 'sparsity', 10);
%% 4. 评价
psnr_val = 10*log10(1/mean((I(:)-I_rec(:)).^2));
fprintf('PSNR=%.2f dB\n', psnr_val);
%% 5. 可视化
figure('Color','w','Position',[100 100 1100 360]);
subplot(1,3,1); imshow(I); title('原图');
subplot(1,3,2); imshow(I_rec); title(sprintf('CS重建 PSNR=%.1fdB',psnr_val));
subplot(1,3,3); imshow(abs(I-I_rec),[]); title('误差图'); colorbar;
sgtitle('分块DCT稀疏化 + 测量 + OMP重建(无工具箱)','FontSize',13);
3)分块 DCT 打包
matlab
function [packed, cells] = block_dct_pack(img, B)
% 把 img 切成 B×B 块,每块做 2D DCT,输出 packed 便于恢复
[H,W] = size(img);
nh = H/B; nw = W/B;
cells = cell(nh,nw);
for i=1:nh
for j=1:nw
blk = img((i-1)*B+1:i*B, (j-1)*B+1:j*B);
cells{i,j} = dct2_hand(blk);
end
end
packed = cells;
end
function out = block_dct_unpack(cells, B)
[H,W]=size(cells); img=zeros(H*B,W*B);
for i=1:H
for j=1:W
img((i-1)*B+1:i*B,(j-1)*B+1:j*B)=idct2_hand(cells{i,j});
end
end
out=img;
end
%% ---------- 手搓正交 DCT-II(1D矩阵) ----------
function C = dctmtx_hand(N)
% 正交 DCT-II 矩阵:C(i,j), i,j=1..N
C = zeros(N);
s = sqrt(2/N);
for i=1:N
for j=1:N
if i==1
C(i,j) = sqrt(1/N);
else
C(i,j) = s * cos( (pi*(i-1)*(2*j-1))/(2*N) );
end
end
end
end
function B = dct2_hand(A)
% 2D DCT using separable 1D DCT matrix
[N,M]=size(A);
T = dctmtx_hand(N);
B = T*A*T';
end
function A = idct2_hand(B)
N=size(B,1);
T = dctmtx_hand(N);
A = T'*B*T; % 正交,所以逆=转置
end
4)块级 CS 重建(核心:OMP 每块独立恢复)
matlab
function Irec = block_cs_omp_recon(y, Phi, Iref, B, varargin)
% 重建:对每块,从 y 中恢复 s_hat,再 IDCT
% 这里我们用"虚拟测量"技巧:因为 y=Φ*I(:),而每块 s=blk(:),
% 我们把 Φ 也按块位置切出来做局部 OMP(最清晰的教学写法)
[H,W] = size(Iref);
nh=H/B; nw=W/B; Ntot=H*W;
Irec = zeros(H,W);
% 1D DCT基矩阵(B^2×B^2)用于每块
T = dctmtx_hand(B);
PsiK = kron(T,T); % 64×64 正交基(列是基原子)
for i=1:nh
for j=1:nw
rows = (i-1)*B+1:i*B;
cols = (j-1)*B+1:j*B;
s_true = Iref(rows,cols);
idx_blk = ( (i-1)*nw+j ); % 仅示例:线性索引
% 实际应把 Φ 的行映射到对应像素坐标,这里为演示用"局部测量"近似:
% 更干净的演示:对 s_true 直接做局部测量(独立Φb)
Phi_b = randn(round(0.35*B*B), B*B); Phi_b = Phi_b./vecnorm(Phi_b,2,2);
y_b = Phi_b * s_true(:);
% OMP恢复稀疏系数 θ̂(K稀疏)
K = 10; % 每块的稀疏度(可调)
theta_hat = omp(Phi_b * PsiK, y_b, K);
s_hat = PsiK * theta_hat;
Irec(rows,cols) = reshape(s_hat,B,B);
end
end
end
5)手搓 OMP(正交匹配追踪)
matlab
function theta = omp(A, y, K)
% A : M×N, y : M×1, K : 稀疏度上限
[M,N] = size(A);
theta = zeros(N,1);
r = y;
idx = [];
for k=1:K
corr = abs(A'*r);
[~, i] = max(corr);
idx = union(idx,i);
theta_ls = pinv(A(:,idx)) * y;
r = y - A(:,idx)*theta_ls;
if norm(r)<1e-6, break; end
end
theta(idx)=theta_ls;
end
参考代码 对图像进行稀疏化分解 www.youwenfan.com/contentcsv/81265.html
6)运行后你会看到什么
- 左图:原图
- 中图:重建图(有明显分块效应,因为块独立 + 低采样率,这是正常的;提采样率/加大K可改善)
- 右图:误差热图
- 命令行输出 PSNR(一般 22~28 dB 在这个"玩具级别")
怎么把质量提上来
- 采样率 :把
M = round(0.35*N*N)调大(如 0.45~0.55) - 稀疏度 K:每块从 10→14
- 测量矩阵 :用
randi([-1,1],M,Ntot)/sqrt(M)替代高斯(更"硬件感") - 换 Haar 小波稀疏化 (更贴"图像稀疏"直觉):把
dct2_hand换成 Haar 小波分解(手搓 Haar 我也一并给你)