Advertisement

A Hybrid ℓ1-ℓ0 Layer Decomposition Model for Tone Mapping—CVPR论文阅读

阅读量:

A Hybrid ℓ1-ℓ0 Layer Decomposition Model for Tone Mapping

目录

A Hybrid ℓ1-ℓ0 Layer Decomposition Model for Tone Mapping

摘要

1、介绍

2、相关工作

3、层分解方法

3.1 混合ℓ1 -ℓ0层分解模型

3.2 模型求解

3.3 扩展到多尺度分解

4. Tone Mapping

5. 实验和分析

5.1 参数选择

5.2 分解层

6、结论


摘要

色调映射旨在从高动态范围图像中保留视觉信息并模拟标准动态范围图像的效果。当前先进的色调映射算法通常会将输入图像分解为基础层和细节层,并对这两部分分别进行独立处理。由于现有方法通常缺乏对于基础层和细节层的适当先验信息,在实际应用中可能会导致光晕伪影现象以及过度增强的问题。为了克服现有问题,在本研究中我们提出了一种基于混合ℓ1-ℓ0分解的新模型。具体而言,在基础层上施加了一个ℓ1稀疏项来模拟该区域的分段平滑特性。该稀疏项被用作细节层上的结构先验信息,并在此基础上提出了一个多尺度 tone mapping方案。实验结果表明,在几乎消除光晕伪影的情况下达到了令人信服的视觉效果评价指标,并且在主观评估和客观测试指标方面均超越了现有的tone mapping算法。

1、介绍

在现实世界中的一些场景可能涉及超越常规成像设备能捕捉到的亮度范围[4]。随着近年来高动态范围(HDR)技术迅速发展[2,7],通过包围曝光融合技术可以在辐射图中完整地记录场景的所有相关信息。然而大多数显示设备都具有有限的对比度和亮度调节能力,在呈现辐射度图中的细节时不可避免地会失真[4]。因此我们需要一种高效的调色算法将HDR辐射度图转换为标准对比度(SDR)图像,在保证主要视觉信息不失真的情况下。

近年来,在图像处理领域取得了显著进展

基于HDR亮度图呈现了丰富的细节事实,在视觉感知过程中需要确定哪些信息应被优先处理这一问题与色调映射机制的设计密切相关。研究表明,在人类视觉系统中,边缘检测表现出显著的敏感性[1,13]. 本征分解方法通常假设反射层中的边缘稀疏性特性也体现了结构信息在图像中的重要性. 基于以上观察结果,在设计色调映射运算符时应首先解决结构信息的重建问题. 考虑到图层分解框架中细节层的空间特性对该运算符生成效果的影响程度较大因此我们在具体实现时将优先在细节层上施加结构稀疏性约束.

尽管色调映射研究中对细节层的空间先验报道有限[12,25] ,但在Retinex分解过程中长期采用ℓ1稀疏先验来建模反射层的结构特性 。 尽管ℓ1范数能够保留图像中的边缘特征 , 但其分段平滑性可能导致较弱的结构先验约束 。 相反地 , ℓ0范数展示了显著的分段平滑特性 [34] , 在结构先验方面表现出色 , 似乎更适合这一需求

在本研究中,我们开发了一种结合ℓ1-ℓ0范数分解的混合模型,旨在解决色调映射问题。通过在细节层次上引入ℓ0范数梯度稀疏性项,我们成功地建模了图像的结构信息,从而使得细节部分能够更加集中地承载这些结构性特征并被强化。与此同时,为减少视觉残留伪影效果,我们在基础层次上应用了ℓ1范数梯度稀疏性项以有效保留图像边界细节。基于所提出的分解框架,我们构建了一个多尺度化的色调映射方案。采用适当的先验技术使得我们的色调校正装置在主观评估和客观测试指标上均显著优于现有最先进的算法

本文的结构安排如下:文章共分为六个章节进行阐述。其中在第2节中介绍了若干相关领域的研究现状,在第3节着重阐述了所提出的层次分解模型的基本框架,在第4节中详细阐述了本研究所采用的多尺度色调映射算法的核心原理和实现方法,在后续各章则分别对应展开具体的技术细节与应用分析:其中第5节安排实验部分进行系统性验证,并在第6节总结全文并展望未来的发展方向

2、相关工作

我们的工作主要涉及色调映射、基于Retinex的层分解和边缘感知滤波。

颜色映射技术目前主要分为全局性和局部性两类方法。其中全局颜色映射方法主要模仿单个压缩曲线SDR图像[28, 32, 33]的行为模式进行复制。相比之下局部颜色映射方法则通过空间变化的方式实现这一目标并且在细节表现上更为出色。具体而言局部颜色映射方法通常基于层次分解策略基础层估计会在保留边缘的同时利用保留边框的滤波器完成这一过程而细节层则由原始图像与基础层之间的残差构成。在此类局部颜色映射算法中不同方案的主要区别主要体现在滤波器设计上早期研究多采用基于内核的设计方案后来建议引入带空间自适应比例参数的高斯类滤波器[29]以提升性能效果随后杜兰德等提出了采用双边滤波器估计基础层的方法[8]这种方法虽然能有效避免出现伪影现象但在增强小尺度细节方面却存在过度增强的问题为了平衡细节增强与整体图像质量Li等提出了基于多尺度小波方案的颜色映射方法[18]梅兰等人则开发了一种基于Retinex理论的自适应滤波器用于颜色调平工作[23]文献[14]中提出的加权导引滤波器同样面临小细节增强过激的问题此外还有学者提出采用全局优化策略设计的颜色调平滤波器如Farbman等提出的加权最小二乘(WLS)滤波器[10]这种方案不仅具有卓越的平滑能力还能很好地保留图像边缘特征除此之外其他局部颜色调平算法还包括基于全局线性窗口的方法[30]以及利用PCA分析原理构建的颜色调平方案[17]

改写说明

基于Retinex的图像分解方法最初源于视觉稳定性研究[16]。该方法旨在从单个图像中估计照明和反射成分,并通过变分模型对其进行建模。在这一领域中,Kimmel等人提出的ℓ2范数基Retinex分解模型被广泛应用于对比度增强任务中,在该模型中假设照明和反射均为全局平滑变化[15]。随后Ng等学者则假设反射层具有分段平滑特性,并采用总变分(total variation)项取代原来的ℓ2范数[25]。此外梁等学者则假设照明层为分段平滑函数,并提出了一种基于非线性扩散的光照估计方法[19]。该方法不仅保留了原始图像中的边缘信息,在处理光晕伪影方面也表现更为出色[19]。近年来傅等人进一步改进了该技术,在反射层上引入亮度倒数加权项以更精确地建模其分段常数特性[12]

Edge-preserving smoothing是一种图像处理技术。

3、层分解方法

我们构建了一个混合ℓ1 -ℓ0层分解模型,并设计了相应的求解器来实现求解。随后,我们将这一分解方法拓展至一个多尺度架构,在其中各个部分的图像能够控制其色调映射。

3.1 混合ℓ1 -ℓ0层分解模型

为了构建合适的分层分解框架,在细节层级遵循结构先验,在基础层级遵循保边先验。采用S、B以及S−B分别表示原始图像的基础层级、基础层级和细节层级。基于此提出了一种分层次优化模型:

其中p代表像素索引,在图像中总共有N个像素。
在模型中引入的第一项(Sp - Bp)²这一项确保了基础层能够贴近原始图像。
空间特性公式由ℓ₁范数下的梯度稀疏性决定:具体而言,在x和y两个方向上分别计算偏导数值,并取其绝对值之和作为衡量标准。
而细节层的空间特性则通过引入指示函数F(x)来体现其梯度稀疏性。

在性能上,我们的层分解模型通过融合ℓ_1ℓ_0正则化技术展现出显著优势。值得注意的是,在ℓ_1范数的稀疏性机制下[20],基层区域的大梯度得以保留,这使得基层区域呈现分段光滑特性。另一方面,已被实验证明会带来平滑化效应[26,34]。在细节层中,则通过施加ℓ_0范数约束使微小纹理元素逐渐消失,从而实现了对主要结构特征的有效保持。如图1(b)所示,这种设计策略不仅能够产生理想的分段恒定效应,还能成功地将先验知识融入到模型构建过程中。

在细节层的选择中还有一种可能是采用ℓ₁范数作为梯度稀疏度的一种替代方案,在文献[...]中对此进行了详细探讨。具体而言,在文献[]中提出了一种通过施加ℓ¹范数来增强细节恢复的方法,并观察到了显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显著的效果提升效果显着改善了图像的质量与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与清晰度与其他方法相比其他方法相比其他方法相比其他方法相比其他方法相比其他方法相比其他方法相比其他方法相比其他方法相比与其他方法相比与其他方法相比与其他方法相比与其他方法相比与其他方法相比与其他方法相比与其他方法相比与其他方面比较而言

3.2 模型求解

目标函数(1)凸, 由于ℓ0标准经过了正规化处理; 通过构建ADMM框架[5], 我们来解决该优化模型; 借于空间限制, 我们仅对每个子问题的求解进行了简要阐述; 若有进一步了解, 请参阅补充材料中的详细说明.

为了清晰起见,我们首先将目标函数(1)以矩阵向量形式重写为:

其中sb\mathbb{R}^N分别对应(1)SB的级联向量形式;全为一的向量\mathbf{1}\mathbb{R}^{2N}用于后续操作表示;梯度算子矩阵\nabla\nabla_x\nabla_y按行叠加构成:\nabla = [\nabla_x; \nabla_y]\mathbb{R}^{(2N) \times N};函数\mathcal{F}\big(\nabla(s - b)\big)将输入经过逐元素非零判断处理后输出一个二进制向量;在此基础上我们引入两个辅助变量c_1, c_2\mathbb{R}^{2N}分别替代梯度表达式\nabla b\nabla(s - b);我们的增强拉格朗日模型构建如下:

其中yi,i=1,2代表拉格朗日乘子,在第k次迭代阶段,我们通过求解多个原始子问题的最小值以及最大化对应的对偶函数来更新最优解。

(1) Solving bk+1:

当我们把向量\mathbf{c}_k^{(1)}划分为两条等长的部分时(\mathbf{c}_k^{(1)}被划分为\mathbf{c}_k^{(1), (1)}\mathbf{c}_k^{(1), (2)}),同时将\mathbf{c}_k^{(2)}划分为两个部分\mathbf{c}_k^{(2), (1)}\mathbf{c}_k^{(2), (2)}),即对每一部分进行进一步划分(具体来说是将\mathbf{y}_k^{(i,j)}划分成两个子部分)。目标函数基于\mathbf{b}_{k+1}是一个二次规划问题,并且可以通过快速傅里叶变换(FFT)来高效求解(此处指所用的方法)。

(2) Solving C1k+1 :

关于C1k+ 1的目标函数可以通过软缩法求解:

(3) Solving C2k+1:

基于文献[34]的研究结果表明,在涉及C2k + 1的目标函数中可以实现逐项计算其对应的目标值。这相当于要解决N个相互独立的一元标量方程问题。为了便于理解与操作,请采用下标j的方式将其向量元素依次标记为x_j(其中j=1,2,...,n)。

3.3 扩展到多尺度分解

基于混合ℓ1-ℓ0分解模型(1),我们将其应用于亮度图中以创建分段常量细节层以及分段平滑的基础层。然而,在单一尺度方案中虽然提供了色调映射的基本框架但将其分解应用到基础层面时会不断产生多尺度分解从而进一步优化了色调映射的效果。在此基础上我们可以调节不同比例图层所代表的图像属性进而获得更加灵活有效的色调重建效果。为了实现更高的效率与效果我们采用了两阶段的分解策略如图2所示该方法会产生一个一级细节层D₁、一个二级细节层D₂以及一个二级的基础B₂层。

如3.1节所述,D₁的空间特性在色调映射图像中具有显著作用.我们采用了该ℓ₁-ℓ₀模型的第一个层次分解:

ℓ₁, ℓ₀(⋅) 被定义为一种优化方法 (1),即该种方法是一种被广泛采用的优化策略。经过一次分解过程后,在细节层的结构信息仍然保持 D₁,并且主要的结构信息则转移到了基础层 B₁ 中。

这种简化主要归因于这样一个事实:我们的目标是在scale-2细节层D₂中保留图像的纹理信息。鉴于此,ℓ在结构层面之前并不适用于这一分解尺度;由此可知,在细节层D₂中保留了大量的纹理信息;而层B₂则记录了区域内的平均亮度值。

综上所述,我们的两尺度分解方案产生了三层D1、D2和B2,满足:

图3呈现了色调映射的效果,在本研究的一阶与二阶模型(详细方法将在第四部分介绍)中可见一斑。结果显示,在单层次融合的结果已足够适用的情况下,双层次模型能够更好地保持图像中频细节并呈现更为自然的整体外观。

在本研究中,我们采用了加速策略来提升处理效率。未对(9)式的精度作出严格限定,在后续处理中采用加速策略的基础上展开优化工作。首先,在处理过程中将B1层进行4倍的线性下采样,并通过(9)式分解模型获取到了B2的低分辨率版本;接着将该低分辨率结果恢复为原始分辨率;值得注意的是,在此过程中会导致边界区域出现轻微模糊;最终我们以原始B1作为引导图像对B2进行快速联合双边滤波操作,并成功提取到了清晰度较高的边界信息[27]。

4. Tone Mapping

基于提出了一种新的层次分解方法的基础上

基于亮度域中的动态范围具有显著影响性特征(原文强调"主要嵌入"),因此我们的核心算法专注于处理亮度通道并保留色度信息。具体而言,在颜色空间转换过程中(这里补充一个必要条件),将输入的RGB辐射度图转换为HSV空间,并对V通道实施色调调节操作。在逆变换阶段(进一步说明操作的时间点),我们通过将饱和度系数乘以0.6来实现对过饱和现象的有效抑制。

基于辐射度图的亮度通道处理算法如图2所示。该通道Vh经过对数域转换后并被归一化至(0,1)区间。此步骤模拟了人类视觉系统对亮度信息的感受机制,并一定程度上降低了图像的整体动态范围。随后我们通过应用两尺度分解模型(8)与(9),成功获得了三个层次的空间表示:即第一层D1、第二层D2以及最终确定的基本层B₂。由于基本层B₂可被视作图像局部亮度水平的核心指标:因此我们采用伽玛函数对其实施压缩运算:

在我们的研究中,在亮度等级方面我们采用了归一化方法处理(即令L = 1)。在最底层细节特征D₁上(即首尺度细节层D₁),我们进行了非线性拉伸函数的增强处理。

该函数对参数旋向为零的定位信号具有延展性。当内径缩小时,相应的拉伸程度会增大;反之亦然。基于分解模型(1),通过施加结构先验于D1来强化原始图像的空间残差细节。这种设计策略能够显著提升整体视觉效果。随后,在重建过程中将生成一个亮度型超分图像。

最后,将0.5%和99.5%强度下的V值分别映射为0和1。超出此范围的值将被剪切。

5. 实验和分析

本节设计并实施了一系列实验来系统评估性能混合ℓ1 -ℓ0层分解模型(1)与所提出的色调映射方案。HDR数据库作为测试平台收录了40幅辐射地图(其中的数据集来自不同来源[1][2]),用于系统性地验证该方法的效果。这些测试辐射地图覆盖了丰富的室内与室外环境,并包含多种类型的物体实例:如绿色植物、各种车辆、天空背景以及建筑结构等。

5.1 参数选择

关键参数决定了ℓ1 -ℓ0λ1分解模型(1)和平滑程度由λ2调节,在基本层和细节层分别起作用。接下来我们采用了平均局部熵(MLE)3这一指标来客观评估两层的平滑度。具体而言,在MLE值较高的情况下(即图像中具有更多的纹理),相反的情况则不会发生。

图4展示了当固定模型1时, 模型2对细节层的影响情况。观察结果显示, 不同的模态2值会导致D_1的不同效果: 当bioc 2取值过高(如0.008)时, 部分结构会出现完全扁平化现象, 相应地MLE值较低(约0.97)。相比之下, 在设置过低(如0.0008)的情况下,D_1中会显现一些微小的纹理梯度, 同时MLE数值显著增大(至约2.33), 这种情况下结构先验的表现相对减弱。通过对数据库的系统性实验发现, 当将icsp 2设定为icsp 1的十分之一(即icsp 2= icsp 1/10)时, 分解效果始终令人满意。图5展示了在固定风害2值(例如:风害系数设为风害系数基准值的十分之一)的情况下, 参数变化对结果的影响趋势: 主要体现在控制D_1信号大小方面, 对分段平滑程度的影响则相对较小

其他需确定的关键参数包括第9项中的T3、第11项以及第12项中的相关内容。在最终设计的基底B2中对基底层平滑性进行优化研究。通过实验发现除了一些异常配置外音素T3对色调映射影响较小因此将图3固定为0.1作为基准值随后主要关注细节层D1的形变幅度通过合理设置将其形变幅度控制在中等水平即0.8附近以防止过强放大效应最后决定将γ设定为2.2这一数值并将其作为Retinex分解研究的标准参数引用如文献[12 15 25]所采用

5.2 分解层

为了评估我们的音调映射算法在多尺度分解方面的性能表现,我们将该算法与Gu所提出的多尺度音调映射器[14]进行了系统对比分析。具体而言,在Gu的方法中,默认情况下会对原始图像连续地应用加权梯度函数驱动的局部引导滤波器三次(共四层),以实现图像的空间分辨率逐步提升过程。值得注意的是,尽管Gu的方法声称包含三层比例关系(即四层滤波器应用),但实际上其最后一级基础层仍被定义为一个恒定不变的理想化图像基准层。因此,在实际应用中可识别的有效分解层次应为三层(两倍空间分辨率)。进一步观察发现,在基础层面(最低空间分辨率)上 Gu 的方法显著强化了边缘保持特性;但并未对高阶细节层级施加任何优先处理机制。

在图6中展示了Gu模型与我们方法在多尺度分解上的对比分析。图7的一维辅助显示,在每种方法的分解层中提取了一维轮廓信号(如图7(a)所示)。从图7(b)可以看到,在不考虑细节层的空间特性的情况下顾模型进行了渐进平滑处理(如图6(d)所示)。由此可见,在第一细节层(如图7(b)中的红色曲线)出现了小波动现象,并且色调映射图像被过度增强效果明显(请参见图6(d)中的放大显示)。这种现象是由局部过滤特性导致的缺陷所引起(如图6(d)所示)。相比之下,在第二层D2中我们的方法引入了小规模变化机制,并强制第一层D1呈现分段恒定特征(如图7(c)所示),从而有效避免了光晕伪影问题(如图6(h)所示),并实现了令人满意的视觉效果

5.3 色调映射比较

我们对比了本团队开发的色调映射器与其他前沿性色调映射器[10, 11, 14, 22, 30, 31]所收集的数据集。这些色调映射器分别包含基于WLS滤波器的方法[10]、全局线性窗方法(GLW)[30]、视觉自适应方法(VAD)[11]、向后兼容性增强方法(BWC)[22]、引导滤波法(GF)[14]以及梯度重建法(GR)[31]. 全部对比结果均附于补充文件中. 其中GF是我们团队实现的方法(因原始代码无法获取),BWC由pfstool4平台实现. 剩余的方法皆由其原始作者提供源代码实现.

主观感受方面进行评估时发现:图8、9详细展示了两种图像在色调映射结果上的对比情况。 通过观察可以看出,在细节增强与自然色彩保留之间实现了良好的平衡效果:相比之下其他色调映射算法则未能达到这一平衡点:其中WLS算法因过分强调局部对比度而导致图像失真;GLW方法则易受亮度变化影响出现明显的失真现象;VAD算法虽然能在一定程度上纠正色彩偏差但可能导致图像过度柔化;而GR与GF算法则各自存在过强的增强效果以及光晕伪像问题;对比实验中将我们的色调映射器与Photomatix5的默认设置进行对比结果表明两者的视觉效果都能达到令人满意的标准:但值得注意的是由于我们算法特别突出了图像结构信息因此在视觉解析性方面表现更为突出。

从客观的角度评估色调映射器性能时,我们采用了色调映射图像质量指数(TMQI)[35]这一量化工具。该指数首先考察了色调映射图像的结构保真度与自然度两个关键指标。随后将这两个量度经过幂函数处理后求平均值以得到最终得分范围为0至1之间。TMQI数值越高表示图像质量越好反之亦然。表1展示了我们在40张HDR图像数据库中测试的所有色调映射器对应的平均TMQI得分结果可以看到我们的方法不仅获得了最高的 TMQI 分数(0.8851)而且还达到了最高的自然度评分(0.5547)。这些令人瞩目的结果充分证明了我们算法所呈现的卓越视觉质量另一方面我们的色调映射器在保真度评分上表现尚可是因为保真度计算中采用不同比例局部窗口的标准差运算可能导致较高的敏感性从而在保证视觉效果的同时有效抑制了过增强现象。

该色调映射器在效率方面表现稳定且性能较为均衡,在基于ADMM求解器的应用场景下展现出良好的计算复杂度特性。其中最为复杂的运算模块是FFT变换算法,在处理大规模数据时其计算开销达到O(NlogN)的数量级。通过对现有技术进行系统性对比分析,在1920×1080分辨率下的典型图像处理任务中,本方案展现出显著的竞争优势(如图8(a)所示)。实验平台采用了搭载Intel i7-6850k处理器及16GB内存的个人电脑配置,在多线程运算环境下实现了较高的处理速度与稳定性

6、结论

我们提出了一种新型的混合ℓ1-ℓ0分解模型,并将其应用于色调映射领域的相关问题研究中。该模型通过先施加细节层上的结构约束,在基础层上则着重于保持边缘的清晰度。为了实现高效的优化计算过程,我们采用ADMM算法对这一优化问题进行了有效求解。基于上述ℓ1-ℓ0分解方法的输出结果,我们进一步开发出一种多尺度色调映射算法。该多尺度方法首先在基础层次对动态范围进行压缩,在细节层次则强化了图像的结构特性。值得注意的是,在本研究中我们成功地应用了两个关键性的改进措施:首先通过精确的设计消除了光晕伪影现象;其次所获得的结果不仅具有更高的视觉质量,并且显著优于现有的相关工作。

matlab代码

用到的函数:

复制代码
 function y = R_func(x,g,sigma,a,b)

    
  
    
 index_low = abs(x-g) <= sigma;
    
 temp = x(index_low);
    
 temp_low = g + fd( abs(temp - g)./sigma, a) .* sigma .* sign(temp - g);
    
 % temp_low = g + betainc( abs(temp - g)./sigma,a*2,a*4) .* sigma .* sign(temp - g);
    
  
    
 index_high = abs(x-g) > sigma;
    
 temp = x(index_high);
    
 temp_high = g + (fe( abs(temp - g) - sigma, b) + sigma) .* sign(temp - g);
    
  
    
  
    
 y = zeros(size(x));
    
 y(index_low) = temp_low;
    
 y(index_high) = temp_high;
    
  
    
  
    
 function y = fd(x,a)
    
     y = x.^a;
    
 end
    
  
    
 function y = fe(x,b)
    
     y = b*x;
    
 end
    
  
    
 end
    
    
    
    
    AI助手
复制代码
 function y  = nor(x)

    
  
    
  
    
     y = (x-min(x(:)))/(max(x(:))-min(x(:)));
    
  
    
  
    
  
    
 end
    
    
    
    
    AI助手
复制代码
 function [D1,D2,B2] = Layer_decomp(img,lambda1,lambda2,lambda3)

    
  
    
 %% first scale decomposition
    
 [hei,wid,~] = size(img);
    
 [D1,B1] = L1L0(img,lambda1,lambda2);
    
  
    
  
    
 %% second scale decomposition
    
 scale = 4;
    
 B1_d = imresize(B1,[round(hei/scale),round(wid/scale)],'bilinear');
    
 [~,B2_d] = L1(B1_d,lambda3);
    
 B2_r = imresize(B2_d,[hei,wid],'bilinear');
    
 B2 = bilateralFilter(B2_r,nor(B1),0,1,min(wid,hei)/100,0.05);
    
  
    
  
    
 D2 = B1 - B2; 
    
  
    
 end
    
    
    
    
    AI助手
复制代码
 %% This function performs the hybrid L1-L0 decomposition

    
  
    
 function [D,B]= L1L0(S,lambda1,lambda2)
    
  
    
 iter = 15;
    
 [hei,wid] = size(S);
    
  
    
 fx = [1, -1];
    
 fy = [1; -1];
    
 otfFx = psf2otf(fx,[hei,wid]);   
    
 otfFy = psf2otf(fy,[hei,wid]);
    
 DxDy = abs(otfFy).^2 + abs(otfFx).^2;
    
  
    
 B = S;
    
 C = zeros(hei,wid*2);
    
 E = zeros(hei,wid*2);
    
 L1 = zeros(hei,wid*2);
    
 L2 = zeros(hei,wid*2);
    
 ro1 = 1;
    
 ro2 = 1;
    
 DiffS = [-imfilter(S,fx,'circular'),-imfilter(S,fy,'circular')];
    
 for i = 1:iter
    
     
    
     CL = C + L1./ro1;
    
     EL = DiffS - E - L2./ro2;
    
     %% for B
    
     C1L1 = CL(:,1:wid);
    
     C2L2 = CL(:,1+wid:end);
    
     E1L3 = EL(:,1:wid);
    
     E2L4 = EL(:,1+wid:end);
    
     
    
     Nomi = fft2(S) + ro1.*conj(otfFx).*fft2(C1L1) + ro1.*conj(otfFy).*fft2(C2L2) ...
    
     + ro2.*conj(otfFx).*fft2(E1L3) + ro2.*conj(otfFy).*fft2(E2L4);
    
     Denomi = 1 + (ro1 + ro2) .* DxDy;
    
     B_new = real(ifft2(Nomi./Denomi));
    
     DiffB = [-imfilter(B_new,fx,'circular'),-imfilter(B_new,fy,'circular')];
    
     
    
     %% for C1, C2, shrinkage
    
     BL = DiffB - L1./ro1;
    
     C_new = sign(BL) .* max(abs(BL) - lambda1./ro1 ,0);
    
     
    
     %% for E1, E2
    
     BL = DiffS - DiffB - L2./ro2;
    
     E_new = BL;
    
     temp = BL.^2;
    
     t = temp < 2.*lambda2./ro2;
    
     E_new(t) = 0;
    
     
    
     %% for Li,i=1,2,3,4
    
     L1_new = L1 + ro1 * (C_new - DiffB);
    
     L2_new = L2 + ro2 * (E_new - DiffS + DiffB);
    
     
    
     %% for ro
    
     ro1 = ro1 *4;
    
     ro2 = ro2 *4;
    
     
    
     %% update
    
     B = B_new;
    
     C = C_new;
    
     E = E_new;
    
     L1 = L1_new;
    
     L2 = L2_new;
    
  
    
 end
    
  
    
 D = S - B;
    
  
    
  
    
 end
    
    
    
    
    AI助手
复制代码
 %% This function performs the TV like decomposition

    
  
    
 function [D,B] = L1(S,lambda)
    
  
    
 iter = 10;
    
 [hei,wid] = size(S);
    
  
    
 fx = [1, -1];
    
 fy = [1; -1];
    
 otfFx = psf2otf(fx,[hei,wid]);
    
 otfFy = psf2otf(fy,[hei,wid]);
    
 DxDy = abs(otfFy).^2 + abs(otfFx).^2;
    
 B = S;
    
 C = zeros(hei,wid);
    
 D = zeros(hei,wid);
    
 T1 = zeros(hei,wid);
    
 T2 = zeros(hei,wid);
    
 ro = 1;
    
 for i = 1:iter
    
     
    
     %% for B
    
     Nomi = fft2(S) + ro * conj(otfFx) .* fft2(C + T1./ro) + ro * conj(otfFy) .* fft2(D + T2./ro);
    
     Denomi = 1 + ro * DxDy;
    
     B_new = real(ifft2(Nomi./Denomi));
    
     
    
     GradxB = -imfilter(B_new,fx,'circular');
    
     GradyB = -imfilter(B_new,fy,'circular'); 
    
     %% for C, D
    
     BB1 = GradxB - T1./ro;
    
     BB2 = GradyB - T2./ro;
    
     C_new = sign(BB1) .* max(abs(BB1) - lambda.*1./ro ,0);
    
     D_new = sign(BB2) .* max(abs(BB2) - lambda.*1./ro ,0);
    
     
    
     %% for T1, T2
    
     T1_new = T1 + ro * (C_new - GradxB);    
    
     T2_new = T2 + ro * (D_new - GradyB);
    
     
    
     %% for ro
    
     ro = ro * 2;
    
     
    
     %% update
    
     B = B_new;
    
     C = C_new;
    
     D = D_new;
    
     T1 = T1_new;
    
     T2 = T2_new;
    
 end
    
  
    
 D = S - B;
    
  
    
 end
    
    
    
    
    AI助手
复制代码
  
    
 function y = compress(x,gamma,W)
    
  
    
 if nargin<3
    
     W = 1;
    
 end
    
     
    
 y = W * ((x./W) .^ (1./gamma));
    
  
    
 end
    
    
    
    
    AI助手
复制代码
 function y = clampp(x,a,b)

    
  
    
 [d1,d2] = size(x);
    
 low = round(a*d1*d2);
    
 high = round(b*d1*d2);
    
  
    
 so = sort(x(:));
    
  
    
 low = so(low);
    
 high = so(high);
    
  
    
  
    
 x(x>high) = high;
    
 x(x<low) = low;
    
 y = x;
    
 end
    
    
    
    
    AI助手
复制代码
 function output = bilateralFilter( data, edge, edgeMin, edgeMax, sigmaSpatial, sigmaRange, ...

    
     samplingSpatial, samplingRange )
    
  
    
 if( ndims( data ) > 2 ),
    
     error( 'data must be a greyscale image with size [ height, width ]' );
    
 end
    
  
    
 if( ~isa( data, 'double' ) ),
    
     error( 'data must be of class "double"' );
    
 end
    
  
    
 if ~exist( 'edge', 'var' ),
    
     edge = data;
    
 elseif isempty( edge ),
    
     edge = data;
    
 end
    
  
    
 if( ndims( edge ) > 2 ),
    
     error( 'edge must be a greyscale image with size [ height, width ]' );
    
 end
    
  
    
 if( ~isa( edge, 'double' ) ),
    
     error( 'edge must be of class "double"' );
    
 end
    
  
    
 inputHeight = size( data, 1 );
    
 inputWidth = size( data, 2 );
    
  
    
 if ~exist( 'edgeMin', 'var' ),
    
     edgeMin = min( edge( : ) );
    
     warning( 'edgeMin not set!  Defaulting to: %f\n', edgeMin );
    
 end
    
  
    
 if ~exist( 'edgeMax', 'var' ),
    
     edgeMax = max( edge( : ) );
    
     warning( 'edgeMax not set!  Defaulting to: %f\n', edgeMax );
    
 end
    
  
    
 edgeDelta = edgeMax - edgeMin;
    
  
    
 if ~exist( 'sigmaSpatial', 'var' ),
    
     sigmaSpatial = min( inputWidth, inputHeight ) / 16;
    
     fprintf( 'Using default sigmaSpatial of: %f\n', sigmaSpatial );
    
 end
    
  
    
 if ~exist( 'sigmaRange', 'var' ),
    
     sigmaRange = 0.1 * edgeDelta;
    
     fprintf( 'Using default sigmaRange of: %f\n', sigmaRange );
    
 end
    
  
    
 if ~exist( 'samplingSpatial', 'var' ),
    
     samplingSpatial = sigmaSpatial;
    
 end
    
  
    
 if ~exist( 'samplingRange', 'var' ),
    
     samplingRange = sigmaRange;
    
 end
    
  
    
 if size( data ) ~= size( edge ),
    
     error( 'data and edge must be of the same size' );
    
 end
    
  
    
 % parameters
    
 derivedSigmaSpatial = sigmaSpatial / samplingSpatial;
    
 derivedSigmaRange = sigmaRange / samplingRange;
    
  
    
 paddingXY = floor( 2 * derivedSigmaSpatial ) + 1;
    
 paddingZ = floor( 2 * derivedSigmaRange ) + 1;
    
  
    
 % allocate 3D grid
    
 downsampledWidth = floor( ( inputWidth - 1 ) / samplingSpatial ) + 1 + 2 * paddingXY;
    
 downsampledHeight = floor( ( inputHeight - 1 ) / samplingSpatial ) + 1 + 2 * paddingXY;
    
 downsampledDepth = floor( edgeDelta / samplingRange ) + 1 + 2 * paddingZ;
    
  
    
 gridData = zeros( downsampledHeight, downsampledWidth, downsampledDepth );
    
 gridWeights = zeros( downsampledHeight, downsampledWidth, downsampledDepth );
    
  
    
 % compute downsampled indices
    
 [ jj, ii ] = meshgrid( 0 : inputWidth - 1, 0 : inputHeight - 1 );
    
  
    
 % ii =
    
 % 0 0 0 0 0
    
 % 1 1 1 1 1
    
 % 2 2 2 2 2
    
  
    
 % jj =
    
 % 0 1 2 3 4
    
 % 0 1 2 3 4
    
 % 0 1 2 3 4
    
  
    
 % so when iterating over ii( k ), jj( k )
    
 % get: ( 0, 0 ), ( 1, 0 ), ( 2, 0 ), ... (down columns first)
    
  
    
 di = round( ii / samplingSpatial ) + paddingXY + 1;
    
 dj = round( jj / samplingSpatial ) + paddingXY + 1;
    
 dz = round( ( edge - edgeMin ) / samplingRange ) + paddingZ + 1;
    
  
    
 % perform scatter (there's probably a faster way than this)
    
 % normally would do downsampledWeights( di, dj, dk ) = 1, but we have to
    
 % perform a summation to do box downsampling
    
 for k = 1 : numel( dz ),
    
    
    
     dataZ = data( k ); % traverses the image column wise, same as di( k )
    
     if ~isnan( dataZ  ),
    
     
    
     dik = di( k );
    
     djk = dj( k );
    
     dzk = dz( k );
    
   110.         gridData( dik, djk, dzk ) = gridData( dik, djk, dzk ) + dataZ;
    
     gridWeights( dik, djk, dzk ) = gridWeights( dik, djk, dzk ) + 1;
    
     
    
     end
    
 end
    
   116. % make gaussian kernel
    
 kernelWidth = 2 * derivedSigmaSpatial + 1;
    
 kernelHeight = kernelWidth;
    
 kernelDepth = 2 * derivedSigmaRange + 1;
    
   121. halfKernelWidth = floor( kernelWidth / 2 );
    
 halfKernelHeight = floor( kernelHeight / 2 );
    
 halfKernelDepth = floor( kernelDepth / 2 );
    
   125. [gridX, gridY, gridZ] = meshgrid( 0 : kernelWidth - 1, 0 : kernelHeight - 1, 0 : kernelDepth - 1 );
    
 gridX = gridX - halfKernelWidth;
    
 gridY = gridY - halfKernelHeight;
    
 gridZ = gridZ - halfKernelDepth;
    
 gridRSquared = ( gridX .* gridX + gridY .* gridY ) / ( derivedSigmaSpatial * derivedSigmaSpatial ) + ( gridZ .* gridZ ) / ( derivedSigmaRange * derivedSigmaRange );
    
 kernel = exp( -0.5 * gridRSquared );
    
   132. % convolve
    
 blurredGridData = convn( gridData, kernel, 'same' );
    
 blurredGridWeights = convn( gridWeights, kernel, 'same' );
    
   136. % divide
    
 blurredGridWeights( blurredGridWeights == 0 ) = -2; % avoid divide by 0, won't read there anyway
    
 normalizedBlurredGrid = blurredGridData ./ blurredGridWeights;
    
 normalizedBlurredGrid( blurredGridWeights < -1 ) = 0; % put 0s where it's undefined
    
   141. % for debugging
    
 % blurredGridWeights( blurredGridWeights < -1 ) = 0; % put zeros back
    
   144. % upsample
    
 [ jj, ii ] = meshgrid( 0 : inputWidth - 1, 0 : inputHeight - 1 ); % meshgrid does x, then y, so output arguments need to be reversed
    
 % no rounding
    
 di = ( ii / samplingSpatial ) + paddingXY + 1;
    
 dj = ( jj / samplingSpatial ) + paddingXY + 1;
    
 dz = ( edge - edgeMin ) / samplingRange + paddingZ + 1;
    
   151. % interpn takes rows, then cols, etc
    
 % i.e. size(v,1), then size(v,2), ...
    
 output = interpn( normalizedBlurredGrid, di, dj, dz );
    
    
    
    
    AI助手

上面是所需的函数,下面是demo

复制代码
 clear;clc;

    
 %% Parameters
    
 lambda1 = 0.3;  
    
 lambda2 = lambda1*0.01;
    
 lambda3 = 0.1;
    
 %% read files
    
 hdr = hdrimread('Street_Art.hdr');
    
 [hei,wid,channel] = size(hdr);
    
 tic;
    
 %% transformation
    
 hdr_h = rgb2hsv(hdr);
    
 hdr_l = hdr_h(:,:,3);
    
 hdr_l = log(hdr_l+0.0001);
    
 hdr_l = nor(hdr_l);
    
 %%  decomposition
    
 [D1,D2,B2] = Layer_decomp(hdr_l,lambda1,lambda2,lambda3);
    
 %% Scaling
    
 sigma_D1 = max(D1(:));
    
 D1s = R_func(D1,0,sigma_D1,0.8,1);
    
 % sigma_D2 = max(D2(:));
    
 % D2s = R_func(D2,0,sigma_D2,0.9,1);
    
 B2_n= compress(B2,2.2,1);
    
 hdr_lnn = 0.8*B2_n + D2 + 1.2*D1s;
    
 %% postprocessing
    
 hdr_lnn = nor(clampp(hdr_lnn,0.005,0.995));
    
 out_rgb = hsv2rgb((cat(3,hdr_h(:,:,1),hdr_h(:,:,2)*0.6,hdr_lnn)));
    
 toc;
    
 figure,imshow(out_rgb)
    
    
    
    
    AI助手

运行结果:

左边原图,右边TMO后图像

代码来自GitHub,我只是互联网的搬运工!

全部评论 (0)

还没有任何评论哟~