☰
图像上采样别只靠插值:用CVX凸优化重建高清图像
2026/10/13 17:21:37 网站建设 项目流程

简介:一份基于MATLAB与CVX库的图像上采样凸优化实现,面向具备基础图像处理知识、希望用优化方法替代传统插值提升画质的研究者或工程师。资源围绕凸优化建模与PSNR评估两条主线展开,清晰演示如何将插值权重求解转化为凸问题,借助CVX自动求解,从而抑制最近邻、双线性等方法易产生的伪影与边缘模糊。压缩包大小约22KB,平台未给出文件总数与类型明细,但从标题与描述看,内容以MATLAB脚本(.m)为主,代码结构紧凑,适合直接阅读、调试和二次改造。目前已有797人学习浏览。通过该资源可掌握CVX定义、求解和验证优化问题的基本流程,理解如何设计目标函数与约束条件来获得更优插值权重,并学会用PSNR量化比较上采样结果;相关思路还能迁移到图像去噪、超分辨率重建等任务中,为后续研究提供可复用的建模参考与实验起点。

1. 图像上采样别只想到插值:用 CVX 做凸优化,结果更稳

我第一次把放大倍数调到 4 的时候,双三次插值出来的边缘全是锯齿,换了好几种插值核也压不下去。后来我把图像上采样当成一个“由低分辨率观测反推高分辨率原图”的反问题,用 Matlab 里的 CVX 工具箱直接求解带正则项的凸优化目标,反而拿到了稳定、可控的结果。这套流程不需要深度学习框架,不依赖训练数据,换一台机器结果完全一致,特别适合做算法基线、对比实验和工业可复现场景。下面我从退化模型怎么建、目标函数怎么写、CVX 代码怎么落地三个角度展开,最后再把实际跑图时踩过的坑和调参经验一并交代清楚。

2. 建立模型之前:为什么图像上采样是反问题,又为什么凸优化能解

2.1 上采样的数学本质是把丢失信息当成约束估计

大多数成像过程都可以写成退化模型:

y = D B x + n

其中 x 是待求的高分辨率图像,B 表示光学模糊核,D 表示下采样矩阵,n 是噪声,y 是我们手里拿到的低分辨率图像。上采样的任务不是把像素填出来,而是根据 y 反推 x。这个反问题天然不适定:下采样已经丢失了高频信息,满足“下采样后等于 y”的高分辨率图像有无数张。插值只是从中选了一张看起来平滑的,没有任何物理约束。

凸优化的思路是加先验。我们把问题改写成带正则项的约束优化:

minimize 0.5 * ||D B x - y||² + λ * R(x)

前半部分是数据保真项,强制重建结果在退化后与观测一致;后半部分 R(x) 是正则项,把“边缘清晰、局部平滑”这类先验写进去。这个形式最大的好处是:当 R(x) 选 L1 范数或总变分范数时,整个问题保持凸,能保证收敛到全局最优,不依赖初始化。

从这个角度看,上采样和去噪、去模糊是同一个框架下的三个实例。区别只是 D 是不是下采样矩阵、B 是不是已知的模糊核。后面第 6 章我会专门说这个迁移,先记住这个模型,整篇文章都是围绕它在展开。

2.2 双三次插值在放大倍数变大时的边界:三个具体表现

双三次插值本质是局部核方法,用邻域像素的加权组合来估计未知像素。它在 1.5 到 2 倍放大时表现尚可,一旦超过 3 倍,问题就很明显:

第一是边缘出现锯齿和振铃。因为高频信息已经物理性丢失,局部核只能猜,而核的形状固定,遇到陡峭边缘就会过冲。第二是纹理区域糊成一片。头发丝、草地、栅格这类周期性纹理,双三次核会把相邻像素平均掉,细节全部抹平。第三是误差是结构性的,不是随机噪声。这个很关键:插值误差集中在边缘附近,且方向一致,后续做配准、测量、检测时会产生系统性偏差,不是加一点平滑就能补救的。

我并不是说双三次插值没有用。在做初值、显示预览、放大倍数小于 2 的场景下,它依然是最快的选择。但当你需要拿上采样结果去做定量分析,或者放大倍数逼近 3 以上,就必须换一个能约束全局一致性的方法。凸优化正好补上这个空档。

2.3 凸优化和 CVX 的适用边界:不是所有能量函数都能直接丢进去

CVX 是一个基于 Matlab 的建模框架,它要求你的目标函数符合 DCP 规则,也就是只能由凸函数、凹函数和仿射函数按固定规则组合。很多东西随手写出来是不符合规则的,比如我自己就犯过把二次型展开成 (Ax-y)'(A*x-y) 直接写进 CVX 的错,结果直接报 DCP 错误。

图像反问题里常见的几类算子都能在 CVX 里安全表达:

  • 数据保真项:L2 用 sum_square(Ax-b),L1 用 norm(Ax-b,1),都是标准写法
  • 正则项:L1 范数、各向同性或各向异性 TV,都可以拆成若干范数的组合
  • 约束条件:像素范围 0<=x<=255、能量守恒、线性等式约束,全部支持

因此这套方法很适合做原型验证和中小尺寸图像的正式实验。代价是 CVX 内部会做大幅度的问题转换,变量一多,内存和求解时间会急剧上升。这决定了它的应用边界:整图做适合几百像素见方的小图,大图必须拆 patch。第 4 章我会给出具体做法。

2.4 什么场景值得选 CVX 上采样

我的判断标准有三条:第一,你手里没有现成的深度学习环境,或者你想先跑一个不吃数据的强基线;第二,你的图像尺寸可控,或者可以接受分块重建;第三,你需要在论文或项目文档里写清楚“我的模型是凸的,解是全局最优的”,而不是“网络训练后效果变好了”。凡是满足其中两条的,都值得把 CVX 方案作为首选或对照方法。

反过来,如果你的低分辨率图是 1000 万像素、要求 4 倍放大且必须在秒级出结果,那凸优化不是好选择,patch 拼接带来的缝合问题会让你耗尽耐心。这种情况我一般直接劝退,去做深度学习或传统插值加锐化的组合,别硬用 CVX。

3. 搭建一个能复现的上采样目标:退化矩阵、正则项和 CVX 最小实现

3.1 准备一对有真值可对比的测试图像

做算法实验不能上来就处理真实低分辨率图,因为没有高分辨率真值,你根本分不清结果是变好了还是变难看了。我习惯先用一张高分辨率灰度图,人为加上模糊、下采样和噪声,生成一张低分辨率观测图。这样后面可以用真实高分辨率图算 PSNR。

clear; clc; s = 2; % 放大倍数,先不要超过 2 I_hr = im2double(imread('cameraman.tif')); % 模拟光学模糊:高斯核,尺寸和方差按相机 PSF 估计 h = fspecial('gaussian', 5, 1.2); I_blur = imfilter(I_hr, h, 'conv', 'replicate'); % 块平均降采样,等价于后面 D 矩阵定义的采样过程 I_lr = imresize(I_blur, 1/s, 'box'); % 加一点高斯噪声,模拟传感器噪声 I_lr = I_lr + 0.003 * randn(size(I_lr)); imwrite(I_lr, 'obs.png'); [m, n] = size(I_lr); M = m * s; N = n * s; % 高分辨率尺寸

这里有一个关键选择:低分辨率观测的生成方式必须和你后面构造的下采样矩阵 D 保持一致。我用了 box 降采样,它在每个 s×s 块内取平均。如果你在这里用双三次降采样,而后面 D 矩阵还是块平均,那模型和观测就对不上,结果一定出问题。这一点在真实图像上尤其重要,后面避坑章节还会展开。

3.2 构造下采样矩阵 D:块平均模型与向量化写法

D 的尺寸是 mn 行,MN 列。每一行对应低分辨率上的一个像素,行内非零位置是该像素对应的高分辨率 s×s 块,数值取 1/s²,也就是做块内平均。这个矩阵在数学上定义得很清楚,但直接写双循环在中等尺寸下也够慢,所以我把索引部分改成了向量化写法。

D = sparse(m*n, M*N); row = 0; for i = 1:m for j = 1:n row = row + 1; base = ((j-1)*s) * M + (i-1)*s; % 按列主序生成块内线性偏移,顺序为 (行偏移, 列偏移) offset = kron((0:s-1)', ones(s,1)) * M ... + kron(ones(s,1), (0:s-1)'); D(row, base + offset' + 1) = 1 / (s*s); end end B = speye(M*N); % 模糊矩阵先设为单位阵,跑通后再换成真实 PSF

代码里最需要注意的是 MATLAB 的线性索引按列主序排列。高分辨率图像第 i 行、第 j 列的像素,在线性向量中的位置是 (j-1)*M + i。所以一个块的基准点不是 (i-1)*s + (j-1)*s 这种行优先写法,必须先乘以 M。我在这边上过一次当,构造出的 D 矩阵转置后怎么都对不上,最后把第 20 行的非零位置打印出来才看出索引错位。

B 矩阵当前是单位阵,不代表后面不用换。它存在的意义是让模型保留“先模糊后降采样”的表达能力。等你在模拟数据上把流程验证通了,再把 B 替换成真实成像系统的 PSF 对应的循环矩阵。实际情况中,块平均的下采样模型本身已经隐含了一点模糊效果,所以很多人直接让 B 保持单位阵也能得到可接受结果。

3.3 构造差分矩阵并选择正则项:为什么先用各向异性 TV

TV 正则的解释是:图像在局部应该是分片平滑的,但边缘处允许突变。实现上需要两个稀疏差分矩阵,分别计算水平方向和垂直方向的相邻像素差。

Tv = sparse(M*N, M*N); % 垂直方向差分 Th = sparse(M*N, M*N); % 水平方向差分 for ii = 1:M for jj = 1:N idx = (jj-1)*M + ii; if ii < M Tv(idx, idx) = 1; Tv(idx, idx+1) = -1; end if jj < N Th(idx, idx) = 1; Th(idx, idx+M) = -1; end end end

这里用的是各向异性 TV,也就是垂直和水平方向分开算绝对值再相加:|Tvx| + |Thx|。另一个常见选择是各向同性 TV,形式是 sqrt((Tvx)²+(Thx)²),边缘更平滑,但表达式稍复杂。我推荐先用各向异性版本,理由很实际:它在 CVX 里的表达简单,不增加求解器负担,而且第一次写代码时不容易出错。等你把保真项、约束和 λ 都调顺了,再换各向同性版本对比效果不迟。

还有一个很容易混淆的点:为什么要用 L1 而不是 L2 来做正则项?L2 正则也叫 Tikhonov,它惩罚的是像素差平方,大梯度会被压得很狠,结果就是边缘变软。L1 范数对小幅值惩罚相对温和,对大幅值的惩罚与幅值成正比,能保留陡峭边缘。图像上采样最需要保的就是边缘,所以默认 TV 而不是 Tikhonov。

3.4 核心:CVX 最小上采样代码

下面这段就是整个流程的主干。把观测图像拉成向量,声明高分辨率变量,写出保真项和正则项的凸组合。

y = I_lr(:); lambda = 0.02; % 正则化权重,经验区间 0.005~0.05 cvx_begin quiet variable x(M*N, 1) minimize( 0.5 * sum_square(D * B * x - y) ... + lambda * (norm(Tv * x, 1) + norm(Th * x, 1)) ) subject to x >= 0; x <= 1; cvx_end I_rec = reshape(x, M, N);

这个目标函数里的三项各有分工。0.5 * sum_square(DBx - y) 是 L2 保真项,假设噪声是高斯分布,它的梯度是平滑的,不会引入椒盐噪声。norm(Tvx,1) 和 norm(Thx,1) 是 TV 正则,控制重建图的分片平滑程度。λ 是两者的权重,平衡“贴合观测”和“符合先验”。

边界约束 x >= 0 和 x <= 1 是很多人会忘记的一步。图像是 0 到 1 的归一化量,如果不加约束,优化器可能为了极小化保真项把某些像素推到负值或超过 1,结果图虽然 PSNR 看起来还行,但显示出来全是过曝或死黑的点。加了约束后,问题依然是凸的,CVX 处理起来没有任何障碍。

我特别强调一下:如果你的输入图是 0 到 255 的 uint8,请在进入 CVX 之前统一转成 double 并归一化到 0 到 1。否则 λ 的取法、约束边界、TV 项的尺度全都要跟着变,调参就是一场灾难。这也是我最早把代码写得像玄学的原因之一。

3.5 目标函数的三个细节:能量守恒、初始化与求解器

第一是能量守恒。构造 D 时,行和要严格等于 1,代表块内求平均后能量不变。验证方法是在 Matlab 里执行 full(sum(D,2)),如果某个块因为索引越界少写了像素,行和会小于 1,重建结果就会出现整体变暗或局部发灰。第二是初始化。CVX 本质上不使用我们的初始化做热启动,它的求解器从零向量开始。所以你在外面给 x 赋任何初值都不会影响求解结果,唯一能做的是通过 precompute 减少建模时间。第三是求解器选择。CVX 默认的 SDPT3 在中小规模问题上比较稳,如果碰到 L1 项导致模型转换后求解过慢,可以换成 SeDuMi 试试,同一个目标函数有时能快一倍,但精度略低。

4. 工程落地:参数设置、patch 拼接和客观评估

4.1 关键参数一览:放大倍数、模糊核、λ 的经验区间

参数作用经验取值
s放大倍数2 最稳妥;3 以上需配合更真实的 PSF
模糊核 B光学退化建模先设单位阵跑通;有 PSF 测量值再替换
λ正则化权重0.005~0.05,图像归一化到 0~1 时有效
图像尺寸决定变量个数整图建议 M*N 不超过 30000;大图拆 patch
求解精度cvx_precision原型验证用默认;批量实验用 low 加速

λ 这个参数没有万能值。我的习惯是先固定一张小图,把 λ 按 0.005、0.01、0.02、0.05、0.1 扫一遍,画出 PSNR 曲线。正常情况下曲线是单峰的,峰值对应的 λ 就是当前场景下的最优值。如果曲线一直单调上升或下降,说明保真项和正则项的量纲不一致,先检查 D 是否能量守恒,再检查图像是否归一化,而不是去继续调 λ。

4.2 大图跑不动时的 patch 拼接方案

CVX 的变量规模上去后,问题转换阶段就会耗尽内存。我常用的上限是 M*N 不超过 30000 个变量,也就是大约 173×173 的高分辨率图。实际工程中哪有这么小的图?所以必须拆块。把低分辨率图切成若干小块,每个小块独立做上采样,再拼回全图。拼接时用重叠和加权平均消除接缝。

function I_rec = upsample_cvx_patch(I_lr_patch, s, lambda) % 输入一个低分辨率小块,返回对应高分辨率块 [pm, pn] = size(I_lr_patch); pM = pm * s; pN = pn * s; % 这里省略 D、Tv、Th 的构造,直接复用第 3 章的代码 y = I_lr_patch(:); cvx_begin quiet variable x(pM*pN, 1) minimize( 0.5*sum_square(D*x - y) ... + lambda*(norm(Tv*x,1) + norm(Th*x,1)) ) subject to x >= 0; x <= 1; cvx_end I_rec = reshape(x, pM, pN); end

调用时按重叠步长滑动窗口,重建结果先累加,最后除以权重图。

patch_size = 48; % 低分辨率 patch 尺寸 overlap = 8; % 重叠像素 step = patch_size - overlap; acc = zeros(M, N); cnt = zeros(M, N); lambda = 0.02; for i = 1:step:(m-patch_size+1) for j = 1:step:(n-patch_size+1) sub = I_lr(i:i+patch_size-1, j:j+patch_size-1); rec = upsample_cvx_patch(sub, s, lambda); rows = (i-1)*s + (1:size(rec,1)); cols = (j-1)*s + (1:size(rec,2)); acc(rows, cols) = acc(rows, cols) + rec; cnt(rows, cols) = cnt(rows, cols) + 1; end end % 处理不够一个 patch 的右缘和下缘 if i + patch_size - 1 < m for j = 1:step:(n-patch_size+1) sub = I_lr(m-patch_size+1:m, j:j+patch_size-1); rec = upsample_cvx_patch(sub, s, lambda); rows = (m-patch_size)*s + (1:size(rec,1)); cols = (j-1)*s + (1:size(rec,2)); acc(rows, cols) = acc(rows, cols) + rec; cnt(rows, cols) = cnt(rows, cols) + 1; end end I_rec_patch = acc ./ max(cnt, 1);

重叠区域被多个 patch 重建了多次,取平均可以抑制接缝。如果接缝仍然可见,把重叠加大到 16 像素,或者对每个 patch 的贡献加一个以中心为高值的窗函数再加权融合。代价是计算量会上升,所以我在大多数场景下用重叠平均就够了。

4.3 用 PSNR 和边缘响应做客观评估

PSNR 是图像重建领域最常用的指标,但它对边缘的刻画很弱,两个 PSNR 相同的重建图可能在视觉上差别巨大。我建议同时计算 PSNR 和边缘响应差值。

function p = psnr_db(x, ref) % 输入图像范围 0~1 x = double(x); ref = double(ref); mse_val = mean((x(:) - ref(:)).^2); p = 10 * log10(1 / (mse_val + eps)); end I_bic = imresize(I_lr, s, 'bicubic'); fprintf('bicubic PSNR: %.2f dB\n', psnr_db(I_bic, I_hr)); fprintf('cvx PSNR: %.2f dB\n', psnr_db(I_rec, I_hr)); gx = fspecial('sobel')'; gy = fspecial('sobel'); edge_cvx = abs(imfilter(I_rec, gx, 'replicate')) + abs(imfilter(I_rec, gy, 'replicate')); edge_bic = abs(imfilter(I_bic, gx, 'replicate')) + abs(imfilter(I_bic, gy, 'replicate')); % 边缘强度均值差值,数值越小代表边缘形态越接近真值 delta_edge = mean(abs(edge_cvx(:) - edge_bic(:)));

拿到这几个数值后,判断标准是:PSNR 比双三次高至少 0.5 dB,同时边缘差值显著下降。如果你跑出来 PSNR 高了但边缘差值反而变大,多半是 λ 太小,放大噪声。如果 PSNR 和双三次持平但视觉上更干净,也说明方法本身有效,只是指标没体现出来。这种情况我会再截一块纹理区放大对比,主观判断在工程报告里同样要有据可依。

5. 五个避坑记录:从翻车里总结的 CVX 上采样经验

5.1 报错“Disciplined convex programming error”不见得是你目标函数写错

现象:CVX 在解析阶段直接报错,提示大意是“Cannot perform the operation {convex} ./ {convex}”。第一反应是目标函数选错了,但问题是这段代码明明在别人那里能跑。

原因:CVX 只认它自己的原子函数组合。你把二次型写成了(D*x-y)'*(D*x-y),或者把 L2 范数平方写成了norm(D*x-y,2)^2,这两种写法在普通 Matlab 里合法,在 CVX 里不被识别为凸表达。DCP 规则不允许直接对凸函数做任意幂次运算。

解决:二次型一律用sum_square(D*x-y),L1 项一律用norm(...,1),不要自己展开矩阵乘积。我还在目标里写过(D*x-y).^2这种逐元素平方,同样报错,换成sum_square立刻通过。记住一条原则:CVX 的表达式只能用原子函数搭积木,不能按数值计算的习惯展开。

5.2 小图能跑大图直接内存爆炸

现象:64×64 的低分辨率图跑得挺顺利,换到 256×256 的图,CVX 在建模阶段就卡住,后来直接提示内存不足。

原因:变量数等于高分辨率像素数。256×256 的低分辨率图,放大 2 倍后有 512×512=262144 个变量。CVX 处理 L1 项时会把问题转成一个大规模 SOCP,内部变量还会成倍扩张,内存消耗远不是稀疏矩阵表面看起来那么小。

解决:不要在整图上直接跑,把输入切成 48×48 或 64×64 的低分辨率 patch,逐块求解再拼接。如果业务不允许拼接,就接受现实,换成其他方法。CVX 适合做中小尺寸和原型验证,不适合做大图整张重建,这是方法论边界,不是代码优化能解决的。

5.3 重建图整体发灰,亮度对不上

现象:求解完成后,图像确实比双三次插值更清楚,但整体发灰,白色区域被压到了 0.8 左右,黑色区域抬到 0.2 左右。

原因:最常见的是 D 矩阵能量不守恒。比如你用双三次下采样生成低分辨率观测,但 D 矩阵却按块平均构造,这会导致 D*x 的值域和 y 的值域有系统偏差。另一个原因是输入是 uint8 的 0 到 255,直接放进了约束 0<=x<=255,但 λ 还是按 0~1 范围设的,正则项相对过强,把像素往中间值拉。

解决:先执行full(sum(D,2))检查每一行,确认非零和为 1。再统一数据范围,输入图在 im2double 转成 0~1 后,约束写 0<=x<=1,λ 按 0.005~0.05 扫描。如果问题依旧,把生成低分辨率观测的方式改成和 D 相同的 block 平均,模型先做到自洽,再谈真实退化。

5.4 输出图像像马赛克,拼接痕迹和网格状纹理明显

现象:重建结果边缘锐利,但能隐约看到低分辨率像素块的网格,像用积木拼出来的画。放大倍数越大,网格越明显。

原因:这是 D 矩阵块平均模型带来的伪影。块平均相当于用一个矩形的低通滤波器,它和现实中的光学 PSF 差别很大。当块边界和图像边缘恰好重合时,重建结果会强化这种格子感。另一个诱因是 λ 过大,平滑项把块内部的差异压平,块之间又靠边缘检测拉回,形成方块轮廓。

解决:把模糊矩阵 B 从单位阵换成高斯核对应的循环矩阵,让退化模型变成“先模糊、后块平均”,这样网格伪影会明显减弱。具体做法是用fspecial('gaussian',[5 5],1.0)生成核,再用稀疏 Toeplitz 结构构造 B。如果暂时不想引入 B,可以把 λ 调小到 0.01 量级,观察网格是否缓解,但这治标不治本。

5.5 跑完比双三次还差,PSNR 掉 0.5 dB 以上

现象:CVX 老老实实收敛了,可拿到 PSNR 一看,还不如imresize(...,'bicubic')。求解时间花了十几分钟,结果出来是负优化。

原因:大概率是正则项权重 λ 和噪声水平不匹配。λ 太小时,重建会把下采样引入的噪声放大;λ 太大时,边缘和纹理被过度平滑,丢失双三次还能保留的局部反差。另一个原因是观测图像本身已经被处理过,比如你拿来的是一个已经增强或锐化过的低分辨率图,它和 y = DBx+n 的假设不符,凸优化没有任何高频信息可以恢复。

解决:先把 λ 在 0.005 到 0.05 之间做一次小扫描,固定一张小图,画出 PSNR 曲线。如果曲线最高点仍低于双三次,那就检查退化模型。用合成数据进行闭环验证:从一张清晰图生成 y,再上采样,确认流程能超过双三次,然后再应用到真实图上。真实图若效果始终不理想,说明该退化场景下凸优化的假设不成立,放弃这条路,不要硬调参。这个判断标准也回答了很多人的疑问:凸优化上采样不是万能的,但它值得做,因为当你匹配好退化模型后,效果是稳定且可解释的。

6. 进阶:用边缘自适应权重把 TV 正则局部化,再把同一套框架迁移到去噪

固定 λ 的 TV 正则有一个尴尬:平滑区需要大 λ 来抑制噪声,边缘附近需要小 λ 来保留对比度,一个全局值无法同时满足。解决办法是给 TV 项加一个预计算的权重矩阵,让每一点的正则强度不同。权重来自双三次插值结果的边缘检测图,先算出一幅 0 到 1 的边缘响应图,再映射成惩罚权重。

x_init = imresize(I_lr, s, 'bicubic'); edge_map = abs(imfilter(x_init, fspecial('sobel'), 'replicate')); edge_map = edge_map(:) / max(edge_map(:) + eps); % 边缘响应大的地方权重小,保留边缘;平坦区权重大,加强平滑 w = 0.3 + 0.7 * (edge_map < 0.35); W = spdiags(w, 0, M*N, M*N); cvx_begin quiet variable x(M*N, 1) minimize( 0.5 * sum_square(D * x - y) ... + lambda * norm(W * Tv * x, 1) ... + lambda * norm(W * Th * x, 1) ) subject to x >= 0; x <= 1; cvx_end

注意权重矩阵 W 必须是在进入 CVX 之前就固定好的常数矩阵,不能用优化变量参与计算。如果你把 w 写成 x 的函数,模型立刻违反 DCP 规则。我在第一次尝试时就是想让权重跟着迭代变化,结果 CVX 报错,这才改成用插值结果做预估计,效果也不差。这个技巧让同一张图上的平坦区域和纹理区域不用再手工分成两个模型,综合效果比固定 λ 好一个档。

更重要的是,这套框架可以整体迁移。把 D 换成单位矩阵,低分辨率观测换成噪声图,目标函数就变成了一个带 TV 正则的去噪模型。把 B 换成运动模糊的卷积矩阵,它就变成了去模糊模型。我在做某跨平台系统的图像预处理模块时,把同一个 CVX 求解函数复制了三份,只改了 D 和 B 的构造部分,就同时交付了上采样、去噪、去模糊三个功能。数学核心完全一致,工程量只差在退化矩阵的构造上。

最后说一个血泪教训:我前几次跑出块状伪影时,一直以为是自己 λ 没调好,反复扫参扫了一个下午。后来才发现问题根本不在 λ,而在 D 矩阵的构造和观测图像的降采样方式不一致。从那以后,我再做任何上采样实验,都坚持先造一对“已知真值”的合成数据做闭环验证,再碰真实图像。希望这篇文章能帮你跳过这一段弯路,直接看到凸优化上采样真正有效的样子。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询