ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

稀疏表示与字典学习:图像超分辨率重建经典方法全解析

稀疏表示与字典学习:图像超分辨率重建经典方法全解析 图像超分辨率重建这些年几乎已经被深度学习方法“霸屏”偶尔有人提起传统算法第一反应就是“插值加正则化”。但真要追根溯源稀疏表示和字典学习这一支才是把“如何从低分辨率观测里补回高频细节”这个问题第一次讲得像个科学问题的工作。杨建超Jianchao Yang等人2010年发表在IEEE TIP上的论文Image Super-Resolution via Sparse Representation就是这一支里绕不开的经典。我前阵子因为项目需要把这套方法从头到尾推了一遍、复现了一遍发现里面值得抠的细节比想象中多得多。这篇就围绕稀疏表示、字典学习、图像超分辨率这三件事把论文的思想、公式、实现和坑一次性讲清楚。适合刚接触超分论文的读者也适合想用传统方法做基线对比的同学。1. 超分不是“放大”而是“猜细节”先搞清问题本身1.1 低分辨率图像到底丢了什么超分辨率在数学上是一个典型的病态逆问题。几乎所有超分论文都会给出同一个降质模型Y S H X n其中 X 是原始高分辨率图像H 是模糊算子光学模糊、传感器点扩散、运动模糊都有S 是下采样算子n 是加性噪声Y 是我们实际拿到的低分辨率观测。所谓“重建超分”就是从 Y 反推 X。这个模型乍看简单但它说明了一个关键事实低分辨率图像不是高分辨率图像“缩小”那么简单而是先模糊再丢弃像素。每一个低分辨率像素值其实是高分辨率图像一个小邻域在高斯核或者其他模糊核下的加权平均然后隔几个才取一个点。也就是说高频信息在成像那一步就已经被物理丢掉了不是单纯“藏”在图像里等着被放大。所以超分从来不是“放大”而是“猜细节”。一个低分辨率像素在模糊和下采样之后可能对应无穷多种高分辨率结构它可能来自一条边缘可能来自一块纹理也可能来自平坦区域。传统插值方法比如双三次插值本质上假设图像局部是平滑的用周围像素的多项式拟合来补点所以它对低频信息有效对边缘和纹理只会越插越糊。这也是为什么在实际项目里双三次放大后的图总是“肉肉的”印刷和医疗影像领域根本不敢用。1.2 稀疏表示凭什么能“猜”出高频既然问题是信息缺失那唯一可行的路线就是引入外部先验从大量自然图像里学习“高频结构长什么样”。稀疏表示就是这篇论文选用的先验模型。它的核心假设是自然图像中的任何一个小块都可以被一个过完备字典里的少数几个原子线性组合近似表示。注意“过完备”和“少数几个”这两个词。过完备意味着字典里的原子数量远大于图像块的维度换句话说表达方式有非常多的冗余而“少数几个”意味着尽管可选原子很多但实际用到的很少。两个条件加在一起就是在说自然图像块尽管形态极其多样但它们在结构上仍然有很强的规律性可以用极少的“结构零件”拼出来。为什么要用“少数几个”这个约束因为从低分辨率观测反推高分辨率块解不唯一。稀疏性是一个很好的选择标准在无数个可行解里挑那个“用最少零件拼出来”的解。这个思路和经验高度一致——一个图像块如果是平滑区域用一个平坦原子就能表达如果是边缘用一两个边缘原子就够了如果非要找个字典原子堆出噪声那恰恰更像过拟合而不是合理解。论文里反复强调的“局部稀疏先验”本质就是在说自然图像的结构复杂度远低于像素维度别把问题想太难。2. 稀疏编码与字典学习论文的两块基石2.1 稀疏编码的数学形式先看最基础的稀疏编码问题给定一个过完备字典 D对一组观测信号 y求一组系数 α使得 y ≈ D α且 α 尽量稀疏。所谓稀疏就是这个向量里绝大多数元素为0只有少数非零。最直接的数学表述是用 L0 范数约束非零元素个数min ||α||_0s.t. y D α但 L0 优化是 NP 难问题没法直接大规模求解。因此论文采用了凸松弛的做法把 L0 换成 L1 范数min ||α||_1s.t. ||D α - y||_2 ≤ ε或者在无约束版本里写成min ||D α - y||_2² λ ||α||_1λ 是正则化系数平衡重建误差和稀疏度。这个形式就是我们熟悉的 LASSO 回归。实际求解时可以用 OMP正交匹配追踪这类贪婪算法近似逼近稀疏解也可以用 ISTA、LARS 这类基于 L1 的优化算法。论文的做法是偏向后者的但我在复现时两种都试过后面会讲它们的差异。有个点值得多说一句为什么 L1 能诱导稀疏一个直观解释是L1 的等高线是带尖角的菱形在约束条件下解更容易落在坐标轴上从而让系数变成稀疏的。我见过很多人直接拿 Lasso 当黑盒用不理解这一层实际调参时就会很迷茫。2.2 过完备字典为什么比固定基更合适早年的信号表示都用固定基比如 DCT、小波。这些基函数有很好的数学性质但它们的表达能力在面对自然图像时是有限的。DCT 擅长表示低频和周期性结构小波擅长表示点奇异和水平/垂直边缘但自然图像里的边缘方向是任意的纹理也千奇百怪。拿固定基去表示非零系数会变多稀疏性就差了。字典学习改变了这个局面原子不再是人手设计的固定函数而是从训练数据里自动学出来的。学出来的原子往往是一些有意义的局部结构不同方向的边缘、角点、条纹、梯度过渡。由于这些原子是从真实图像里统计提炼的它们对目标域的适配性远好于通用基函数。打个比方固定基像一套通用工具箱什么都能修但每件工具都不太顺手字典学习出来的原子像你针对某类常见故障专门定制的工具可能确实偏科但对目标场景效率极高。这也是为什么同样的块大小和稀疏度学习字典的重建效果通常明显优于 DCT 字典。2.3 高低分辨率为什么要共享一套稀疏系数这篇论文最关键的前提是假设同一图像内容的高分辨率块和低分辨率特征块在各自字典下的稀疏编码系数是相同或者非常接近的。为什么敢做这个假设因为降质过程模糊加下采样从频域上看是低通滤波它主要削弱的是高频幅度对图像块的主要结构布局影响较小。一个图像块里“哪条边更重要”“哪个纹理占主导”这些结构性信息在低分辨率域仍然保留着。因此如果高分辨率块 x 可以用系数 α 在字典 D_h 下稀疏表示那么对应的低分辨率特征块 y很大程度上也能用同一组 α 在字典 D_l 下稀疏表示。当然这个假设并不严格成立它只是工程上一种非常有效的近似。论文并没有花大篇幅去证明它而是用大量实验说明在自然图像上这个共享系数假设能带来很好的重建效果。后来的很多方法试图进一步放宽或者改进这个假设但基本思路一直延续到现在。3. 完整链路拆解字典怎么学重建怎么做3.1 训练样本制备高低分辨率块怎么配对整个算法分训练和重建两个阶段。训练阶段的第一步是准备高低分辨率块对。具体做法是这样的从一批高质量训练图像里随机裁剪出大量高分辨率小块记为 x_i。然后对整张训练图像人为施加降质模型高斯模糊加下采样得到对应的低分辨率图像。接下来有一个关键细节不要把低分辨率图像直接作为“低分辨率块”来用而是先把它插值放大回目标分辨率网格再在插值后的图像上提取特征块。这一步是很多人复现时容易想不通的地方。原因不难理解我们希望低分辨率特征块和高分辨率像素块一一对应、坐标完全对齐并且有相同的块尺寸。如果直接把低分辨率的 5×5 块映射到高分辨率的某个区域坐标对不齐后续稀疏编码的系数共享就无从谈起。论文中处理的策略就是先把低分辨率图插值放大到高分辨率网格然后在这个公共网格上提取特征。我复现的时候也是按这个思路处理的效果确实正常。低分辨率侧的特征不能直接用像素值论文用的是四个梯度滤波器来提取结构信息一阶梯度算子 [-1, 0, 1] 及其转置二阶梯度算子 [1, 0, -2, 0, 1] 及其转置。这四个滤波器分别捕捉水平一阶、垂直一阶、水平二阶、垂直二阶的局部结构。这样做有两个好处一是去掉低频能量让稀疏编码更关注纹理和边缘二是对光照变化更鲁棒。高分辨率侧则直接取原始像素块不需要做特征变换。最终我们得到一批“低分辨率特征块 y_i 高分辨率像素块 x_i”的训练对。3.2 联合字典学习的目标函数拿到训练对之后要同时学习两个字典 D_h 和 D_l让高低分辨率共享系数 α_i。论文的联合优化目标可以写成min Σ_i ||D_h α_i - x_i||₂² Σ_i ||D_l α_i - y_i||₂² λ Σ_i ||α_i||₁这个目标函数有三项意思很清楚第一项要求高分辨率字典加系数能很好重建高分辨率像素块第二项要求低分辨率字典加同一组系数能很好重建低分辨率特征块第三项要求系数本身稀疏。这个优化问题不是联合凸的但分别固定一部分变量再优化另一部分时是凸的所以用交替迭代来做先固定字典对所有训练块求稀疏系数然后固定所有系数更新字典不断重复。字典更新的环节论文的思路和 K-SVD 一脉相承对每个原子做奇异值分解并去掉对已有表示的影响一个原子一个原子地精修。我在实现的时候为了控制复杂度直接用了批量更新的方式效果虽有细微差别但整体收敛趋势一致。需要注意训练块的数量。论文的实验里训练块往往有数万到十几万个而字典一般只有几百个原子。这么一组小数量的原子要覆盖自然图像的所有结构训练样本必须足够多样否则学出来的字典会有明显的偏置——比如只擅长图像中心区域或者在边缘方向分布上不均匀。3.3 重建阶段逐块编码加全局约束训练结束后进入重建阶段。给定一张待放大的低分辨率图流程如下第一步把输入图插值放大到目标分辨率。第二步在放大后的图像上按步长滑动裁块对每个块做同样的梯度特征提取。第三步对每个低分辨率特征块求解稀疏编码问题得到系数 α。第四步用同一个 α 乘以高分辨率字典 D_h得到高分辨率像素块。第五步把所有高分辨率块放回原位置重叠区域取平均得到初步重建图 X0。这里有一个非常容易忽略但很重要的收尾操作全局一致性约束。前面五步做的是逐块局部重建块与块之间难免出现不一致而且整体结果未必严格满足降质模型。论文最后的做法是迭代反投影back-projection通过求解一个全局优化问题让最终图像在重新降质后仍然与输入低分辨率图一致。这个全局约束可以写成min ||S H X - Y||₂² c ||X - X0||₂²其中 X0 是逐块重建得到的参考图。公式的意思是最终结果一方面要能在降质后还原回输入 Y另一方面不能离局部重建结果太远。实际实现时用梯度下降迭代几次就能收敛。我初次复现时曾经偷懒跳过这一步结果重见图的边缘虽然锐利但整体结构和原图出现明显偏差PSNR 掉了大约 0.3dB。加回去之后问题消失。4. 论文里没明说但复现一定要知道的事4.1 块尺寸、字典大小和重叠像素怎么配论文给的典型参数是 5×5 的块、512 个字典原子放大倍数通常是 2 或 3。但我实测下来参数之间是联动的不能照搬。块尺寸决定了原子表达的空间尺度。5×5 在放大 2 倍时够用但放大 4 倍时低分辨率块包含的信息更少单一小块能表征的结构范围更有限重建结果会出现高频不足。我的经验是放大 4 倍时把块尺寸提到 7×7 或 9×9字典规模从 512 加到 1024。代价是训练时间变长重建时的稀疏编码也更慢但质量提升是实打实的。重叠像素直接影响块效应。滑动步长越小重叠区越大块与块之间的连续性越好但计算量成倍增加。我通常的做法是块 9×9 时用步长 3块 5×5 时用步长 2重叠区域直接平均就行不需要做复杂的加权。如果你发现重构图有明显的网格感第一件事不是改算法而是缩小步长。4.2 特征归一化和坐标对齐梯度特征和像素值的尺度完全不在一个量级。我做实验时对比过特征向量不归一化直接进稀疏编码训练和重建都不太稳定尤其是当训练图像整体偏暗或偏亮时字典原子的幅度会跟着漂移。后来我在编码之前对每个特征向量做 L2 归一化重建之后再按原始尺度还原稳定了不少。坐标对齐这个问题更加隐蔽。训练时从高分辨率图上裁剪块得到 x_i同时由降质图插值放大后提取 y_i这两个块在空间上必须严格对应同一个图像区域。如果裁剪坐标和插值偏移处理得不一致哪怕只差半个像素学出来的字典也会“两边不讨好”重建图上出现轻微的伪影。我一个朋友复现时出现整幅图所有边缘都有重影排查很久最后发现问题出在低分辨率插值放大时默认坐标对齐方式和裁剪坐标差了半个像素。4.3 全局约束不是可选项前面提到迭代反投影是全局约束但还有更细的工程细节迭代的步长和轮数。论文里没有给出很具体的推荐值我实验里的做法是步长取 0.4迭代 15 到 20 轮基本收敛。步长太大会导致结果在降质模型附近震荡太小则收敛太慢。需要留意的是全局约束不是万能的。如果局部重建质量本身就差反投影只会把错误均匀化并不会凭空补出细节。所以这个步骤应该理解为“兜底修正”而不是“救命稻草”。4.4 实操里最常见的三个坑第一个坑训练样本缺乏数据增强。随机裁剪后如果不做随机翻转和旋转学出来的字典对旋转方向的纹理泛化很差。尤其是人脸和建筑等方向性明显的图像没做增强时重建结果对图像翻转敏感。我后来在训练阶段加入八方向增强四个旋转方向乘以是否翻转效果改善明显。第二个坑正则化参数 λ 的选择。λ 太小稀疏性不足重建块会出现噪声放大λ 太大系数被过度压缩重建图平滑得像水彩画。我的经验是先跑一个小数据集观察块的重建误差和稀疏度曲线选在拐点附近。一般 λ 在 0.01 到 0.1 这个量级但跟特征归一化方式强相关换一种归一化就要重新调。第三个坑用 OMP 还是 L1 求解的问题。OMP 速度快但在噪声存在时容易把噪声也当成结构L1 求解对噪声更鲁棒重建图更干净。论文实验里的效果是 L1 为主。实际项目里如果追求效率可以用 OMP 先跑通流程最后再换成 L1 做最终参数验证。5. 实测结果与调参记录5.1 指标变化趋势我用 Set5 和 Set14 测试集做了简单对比放大倍数 3训练图像用了一组自然风景和数据增强后的混合集。作为参考我列一下大概的 PSNR 水平方法放大倍数Set5 平均 PSNR特点双三次插值3约 30.4 dB边缘模糊无新增纹理最近邻嵌入NE3约 31.2 dB有一定细节但偶发伪影稀疏表示字典学习3约 32.0 dB边缘清晰纹理更自然深度方法参考 SRCNN3约 32.7 dB重建速度快细节更稳定这个数字在不同训练集和参数下会有波动但趋势是稳定的稀疏方法相对插值有稳定提升相对深度方法仍有一截差距尤其在现代深度模型面前。它的价值更多体现在算法思想上。5.2 主观视觉比指标更诚实PSNR 只算像素误差不能完全反映视觉质量。我在实测中最大的体会是稀疏表示方法重建出来的边缘非常干净放大 3 倍时文字和建筑轮廓几乎没有明显锯齿这一点在 PSNR 上只体现了一点点优势但肉眼差异非常大。但在平滑区域比如天空和墙壁稀疏方法偶尔会“编造”出一些不存在的微弱纹理。这不是 bug而是稀疏先验的本性字典里没有专门表示“平坦区域”的足够重要性编码器有时会拿一两个纹理原子硬凑。论文作者其实也意识到这个问题所以后续工作里增加了对结构信息的引导。我在复现时通过在训练样本里多保留一些纯平区域块、加大平坦块的采样比例情况会好一些。5.3 我后续的工程化提速技巧稀疏编码阶段是整条链路里最慢的。如果对每个块单独调 LassoPython 实现会很痛苦。我的做法是把所有块的特征堆成一个二维矩阵一次性求解 Lasso 问题把循环改成矩阵运算速度可以快一个量级。另一个技巧是先对低分辨率特征做一次 PCA 降维把特征维度从 100 左右降到 40 左右稀疏编码的求解速度和稳定性都有帮助代价是丢失极少量细节。6. 这篇论文的边界以及它和深度学习的隐性继承6.1 它为什么没成为工业默认方案客观说这篇论文发表这么多年并没有直接在工业界大规模落地。原因主要有三个。一是速度慢重建一张图像要对每一个块做一次迭代优化即使优化得很好的实现也远达不到实时。二是对噪声敏感输入图像如果有较强噪声稀疏编码容易把噪声结构也编码进系数里导致重建噪声被放大。三是当放大倍数变大比如 4 倍以上单一字典的表达能力和共享系数假设都开始吃紧效果退化明显。但这些问题恰好为后来的方法指明了方向。深度学习方法在速度和端到端优化能力上全面超越了传统稀疏方法这是事实但这不意味着稀疏表示的思想过时了。6.2 SRCNN 和稀疏表示的隐性继承只要对比一下流程就能发现SRCNN 和这篇论文的处理路径几乎同构都是先把低分辨率图像插值到目标尺寸再提取特征再映射到高分辨率空间。SRCNN 的三层结构——特征提取、非线性映射、重建——恰好对应了这篇论文里的梯度特征提取、稀疏编码、字典重建三个阶段。从字典学习的视角看CNN 的前几层学到的卷积核和论文里手工设计的梯度滤波器在功能上高度重合中间层的非线性映射其实是在学一组比稀疏编码更灵活的特征变换最后一层则是在学重建字典。我经常建议刚接触超分的同学先复现一遍这篇论文再碰深度模型理由就在这里深度模型里的很多设计不是凭空出现的理解清楚稀疏表示这个源头你就知道为什么超分网络要把低分辨率图先插值再输入为什么损失函数要同时约束像素域和特征域为什么很多模型在 edge 上表现差异巨大。这些问题都可以在这篇经典论文里找到答案的雏形。最后再分享一个我个人的习惯现在做超分实验我依然会先用稀疏表示方法做一个基线结果。它慢但它能让我直观感受“哪些高频信息是数据里真实存在的哪些是模型自己编的”。这种对先验和观测之间关系的敏感度读论文是得不到的得亲手跑一遍代码才体会得到。希望你复现的时候也有类似的收获。
返回列表