ARTICLE DETAIL

资讯详情

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

NeRCo代码解析:隐式神经网络如何实现低光照图像增强

NeRCo代码解析:隐式神经网络如何实现低光照图像增强 说到论文代码解析我发现每个人理解“解析”的方式差别挺大。有人喜欢反汇编那种逐行抠指令的思路也有人习惯像拆cartographer源码一样从系统顶层到底层实现铺开讲。但NeRCo这类深度学习论文的代码解析核心不是逐字符背代码而是把整个方法的高层意图和代码实现一一对应起来让你看完能自己动手复现。这篇博文就围绕2023 ICCV的NeRCo展开——隐式神经网络怎么做低光照图像增强。我会从方法动机讲起把网络结构、损失设计、训练细节、代码实现和踩坑记录全部串起来。适合正在做图像增强方向研究、准备复现论文或者想搞清楚“隐式表示除了NeRF还能怎么玩”这类问题的读者。全文不会回避数学和实现细节但也不会绕弯子。1. 项目背景低光照增强为什么开始拥抱隐式神经网络1.1 低光照增强到底难在哪低光照图像增强不是简单“把暗的调亮”这么直白。晚上或者逆光场景下拍出来的图往往同时存在几个纠缠在一起的问题整张图动态范围被压缩暗部细节完全埋在噪声里传感器在低照度下会产生大量彩色噪声而且噪声分布通常和信号相关还有颜色偏绿或偏黄、对比度不足、局部过曝等等。早期方法主要走两条路。一条是基于Retinex理论的物理建模把图像分解成光照图和反射图暗光增强变成光照图的重建问题。另一条是直方图均衡化、Gamma校正这类像素级方法简单但处理复杂场景容易失真。深度学习起来之后大量CNN方法用编解码器结构直接做低光照到正常光照的映射效果确实上了一个台阶。但也有瓶颈CNN在固定分辨率的离散像素网格上工作对全局光照过渡、跨尺度的语义信息利用有限增强结果经常出现局部偏色、亮暗过渡突兀、纹理过平滑这些毛病。1.2 隐式神经网络凭什么能上场隐式神经网络这几年因为NeRF火遍图形学它的核心思路是放弃“网格上存像素”的显式表示改用“坐标到值的连续函数”来描述图像、三维场或者光照。给网络一个坐标 (x, y)它返回这个位置的像素值或者某种物理量。这个函数是连续的、可微的天然支持任意分辨率采样。把这种思路迁移到低光照增强意味着我们可以把“暗图变亮图”看成学习一个连续的光照重映射函数。输入低光照图像某个位置的坐标和局部特征网络输出该位置的光照调整量或者增强后的颜色值。这比直接预测一整张feature map更贴合图像增强问题的本质——光照变化本身是空间连续的在真实世界中不存在像素级突变的均匀光照。NeRCo正是抓住这个点用隐式神经网络表示和优化低光照增强过程让模型学会的是一套连续的光照场重建能力而不是简单背训练集的亮度映射。这个思路天然解决了传统增强结果分辨率不可控的问题训练时用的低分辨率推理时可以任意尺度采样也不用插值放大导致边缘糊掉。1.3 为什么是非常有意思的尝试NeRCo选择的方向我理解是把Retinex的思想做了一次现代化升级。Retinex假设图像 反射率 × 光照反射率是物体固有属性光照决定了人眼感知亮度。传统方法里光照图经常用低通滤波来估计估计得不准最终增强效果就会发灰、发白或者有色偏。而NeRCo用隐式网络学习光照图网络拟合的是全局坐标场下的平滑光照分布比单纯滤波精细得多。从宏观上看这项工作和超分、重建等领域里“隐式表示替代离散表示”的潮流是一致的。它要解决的问题是一个模型如何在不同亮度条件、不同场景下都保持光照调整的连续性和自然性。这种对连续性的追求让它有了区别于其他增强方法的价值。2. NeRCo模型设计思路拆解从光照先验到隐式重构2.1 整体框架Retinex分解加隐式光照场NeRCo的整体流程可以分成三大块特征提取、隐式光照场生成、光照与颜色的合成。我这里按论文核心思想并结合常见实现惯例给出一个可复现的框架描述实际代码实现时不同版本会有些出入但主体逻辑是一致的。第一步是特征提取。低光照图像进入一个共享卷积骨干网络得到不同尺度的特征图。这些特征图不直接用来输出增强结果而是作为隐式网络的“条件信息”。为什么需要这一步因为低光照图像是高度不适定的同一个像素值可能来自不同的反射率也可能是不同光照下的结果全靠坐标去猜根本不可能。它需要利用邻域信息、语义信息来辅助判断这个角色就交给骨干网络。第二步是坐标映射。对图像中的每个像素我们拿到它的归一化坐标 (x, y)。为了增强坐标特征的表达能力通常会对坐标做位置编码把它映射到高维空间然后进入隐式MLP网络。MLP由多层全连接加SIREN正弦激活组成经过调节器处理后输出这一点的光照调整系数。第三步是合成。将网络预测的光照调整系数作用到图像上得到增强结果。训练时加上各种约束让网络学会在保持反射率细节和颜色信息的同时只调整光照部分。2.2 怎么理解隐式光照场的本质要理解NeRCo为什么有效关键在于转变一个思维它学的不是“低光照图 → 正常光照图”的像素级映射而是“图像域上的连续函数”。这个函数以低光照图像的特征为条件以像素坐标为输入输出该点的光照状态。为什么这样建模更合理因为真实世界的光照变化是缓慢且连续的物体的阴影边界、光源方向、光的衰减都有物理规律。CNN在处理时通过卷积核隐式建模这种连续性但没有显式约束。NeRCo把“连续光照场”作为一个结构先验写进模型里等于在网络结构上注入了一个强归纳偏置——相邻像素应该共享相似的光照状态远处像素可以逐渐变化。这个偏置显著减小了搜索空间让网络能更快收敛也不太容易输出局部突变的光照伪影。2.3 网络结构核心模块从代码实现角度看NeRCo里最重要的模块可以拆成三个第一个是定位编码模块。原始的二维坐标只有两个数值直接喂给MLP容易导致低频偏向即对图像边缘、纹理的拟合很差。这里使用高斯型傅里叶特征将坐标映射到高频空间这样MLP能拟合出锐利的边缘。位置编码频率的设置很关键频率太低学不到细节太高会引入噪声和过拟合。第二个是SIREN骨干网络。它是一个以正弦作为周期激活函数的多层感知机。普通的ReLU激活函数是分段线性的其导数不连续拟合复杂信号需要非常深或非常宽的网络。而正弦函数的导数还是正弦这种周期性天然适合表示图像、光照这类有丰富纹理和边界的物理量。SIREN层的初始化方式比较特殊需要根据输入输出维度以及频率做特殊初始化否则网络容易跑飞。第三个是条件调制层。骨干网络提取的特征如何注入隐式网络常见方式是FiLM通过两个分支预测每层特征的缩放因子和偏移量对隐式网络隐藏层做仿射变换。这种设计让隐式网络拥有一个“全局先验 局部条件”的融合机制既能保持光照场的全局连续又能适应不同区域的局部差异。2.4 训练策略与损失设计NeRCo训练的核心是把增强效果拆成几个维度来监督而不是让网络盲目对齐像素。第一个是重建损失通常使用L1和L2的混合。L1保细节、对异常值不敏感L2让整体色偏更小。很多实现会在低分辨率上用L2预训练再在高分辨率上用L1微调这个经验值得参考。第二个是感知损失。直接用像素损失训练出来的结果在语义上容易“不真实”因为人眼对局部对比度和纹理极为敏感。所以常规操作是拿预训练VGG网络提取高层特征在特征空间做约束让增强结果的语义内容和正常光照图尽量接近。第三个是颜色损失。低光照增强最怕颜色失真。一般做法是把图像转到LAB空间或者计算颜色矩阵的均值方差约束增强前后色相一致性。NeRCo里通常在对抗偏色时会在R、G、B通道分别计算颜色直方图损失幅度不用大但能有效抑制偏绿偏黄。第四个是平滑损失。光照场定义为连续平滑的场那预测的照度图就需要加一个全变分TV正则项抑制局部突变和增强产生的噪声放大。TV正则项的权重需要调太大会把纹理细节抹掉太小无法抑制噪声。3. 三个关键原理为什么SIREN和坐标场能work3.1 SIREN激活函数的数值稳定性处理SIREN用正弦做激活看似简单实际调参坑很多。网络每一层算的是 sin(ω₀ * (Wx b))ω₀是频率系数。当ω₀太大网络输出会在多个周期内振荡梯度变得极其不稳定太小又无法表达高频细节。NeRCo实现里对第一层和隐藏层的初始化是分开的。第一层权重要从均匀分布中采样范围是[-1/in_dim, 1/in_dim]。为什么第一层直接吃原始坐标如果初始化范围太大输入稍微偏移一点就会让正弦函数进入不同的周期分支网络会学得非常不稳定。隐藏层权重初始化范围则需要除以ω₀原因是让每一层的输入的方差控制在合理范围内确保梯度传播时既不会爆炸也不会消失。实际训练中我建议对ω₀做一个小的衰减也就是训练初期用较高的频率快速拟合轮廓后期适当降低频率稳定细节这在光照复杂的夜间场景中会明显减少频闪伪影。3.2 坐标编码直接输入坐标为什么不行隐式神经网络有一个普遍规律直接输入x、y坐标MLP会表现得很差学出来的结果是模糊的。这跟傅里叶特征受欢迎的原因有关。原始坐标信息密度太低特征值全部挤在低频空间里而图像边缘、纹理属于高频信息。高斯傅里叶特征把坐标映射成一组不同频率的三角函数网络就有了“调频”能力。这里有一个实现小技巧高斯傅里叶特征中随机采样的scale参数会直接影响最终图像纹理的重建效果。scale太小只能恢复平滑区域scale太大重建结果会出现网格状伪影。常见做法是设置多组不同频率的尺度或者直接动态学习每个频率的权重NeRCo类方法中这两种方案都有。3.3 Retinex先验如何与隐式学习协同NeRCo把Retinex的分解思想作为网络结构的一部分来用而不只是后处理。一个聪明的做法是把SIREN网络输出的光照场直接作为Retinex模型中的光照图然后用输入图像除以光照图得到反射图再做颜色校正得到最终结果。这样做的好处是模型不用凭空“脑补”丢失的纹理。低光照图像的暗部细节虽然很暗但只要没有过曝反射率信息还在只是被光照压住了。网络只需要估计光照场然后用输入图像反解反射率这个反解过程保证了纹理不丢失因为它是确定性操作而不是网络生成的结果。3.4 损失权重如何平衡多任务损失的关键在于“怎么乘”而不是“加不加”。我常用一个思路把所有损失项先归一化到相近的量级再设计权重。重建损失通常作为主损失权重最高感知损失在训练中后期加入用来微调纹理和语义颜色损失全程使用但权重很小只是提供偏色惩罚。平滑损失要特别注意它的梯度会推动光照图趋于常数如果权重过大最终增强结果会有一种“塑料感”——亮是亮了但没有任何层次。建议平滑损失只对光照图施加不作用于反射图。4. 代码级解析从数据管线到模型训练与推理4.1 环境准备与依赖NeRCo的复现依赖相对常规PyTorch 1.10以上、CUDA 11.x、OpenCV、NumPy以及预训练VGG权重的下载。不建议闭眼上最新版PyTorch某些旧代码里的SIREN初始化、grid_sample边界处理在不同版本之间有细微差异可能让训练结果与你参考的实现不一致。conda create -n nerco python3.8 conda activate nerco pip install torch1.12.0 torchvision0.13.0 --extra-index-url https://download.pytorch.org/whl/cu113 pip install opencv-python numpy tqdm tensorboard4.2 数据加载与预处理训练低光照增强通常用到LOL数据集包含低光/正常光图像对。预处理的核心步骤是保证低光图和标签图的空间对齐与尺度一致。图像的亮度分布对网络学习影响非常大我建议在送入网络之前把所有图像做一次自动白平衡减弱传感器偏色干扰让网络把精力放在光照结构学习上。数据增强上除了随机裁剪、翻转外还要加颜色抖动。低光照数据集里的标签图本身会有亮度不一致的问题颜色抖动可以帮助网络学到颜色不变性。随机裁剪时要注意裁块尺寸和位置编码的关系NeRCo训练时会用不同裁剪尺寸来增加感受野但坐标编码必须用图像内部归一化不能用全局坐标否则同一样本在不同裁剪位置会学到不同的映射关系模型很难收敛。# 简易数据集加载示例 class LOLDataset(Dataset): def __init__(self, low_path, normal_path, crop_size256, augmentTrue): self.low_files sorted(glob.glob(low_path /*.png)) self.normal_files sorted(glob.glob(normal_path /*.png)) self.crop_size crop_size self.augment augment def __getitem__(self, idx): low cv2.imread(self.low_files[idx]) normal cv2.imread(self.normal_files[idx]) low cv2.cvtColor(low, cv2.COLOR_BGR2RGB) normal cv2.cvtColor(normal, cv2.COLOR_BGR2RGB) # 随机裁剪 h, w low.shape[:2] x random.randint(0, h - self.crop_size) y random.randint(0, w - self.crop_size) low low[x:xself.crop_size, y:yself.crop_size] normal normal[x:xself.crop_size, y:yself.crop_size] # 转张量、归一化到[0,1] low torch.from_numpy(low).permute(2,0,1).float() / 255.0 normal torch.from_numpy(normal).permute(2,0,1).float() / 255.0 return {low: low, normal: normal, coords: self.generate_coords(self.crop_size)}坐标生成这里我单独说。每个batch的coords是一个与图像同尺寸网格的归一化坐标范围在[-1,1]shape是(B,H,W,2)。生成方式用meshgrid记得在dim1上把x和y拆开避免后面与图像特征做cat时维度对不上。4.3 隐式网络核心模块实现这是整篇代码解析里最重要的部分。NeRCo的隐式网络本质上是一个以坐标为输入、以图像特征为条件的条件SIREN。我给出的实现是这一类方法中最常用的参考写法与论文核心机制的对应关系我会逐行解释。import torch import torch.nn as nn import numpy as np class SineLayer(nn.Module): def __init__(self, in_features, out_features, omega_030.0, is_firstFalse): super().__init__() self.omega_0 omega_0 self.linear nn.Linear(in_features, out_features) self.init_weights(in_features, out_features, is_first) def init_weights(self, in_features, out_features, is_first): with torch.no_grad(): if is_first: bound 1.0 / in_features self.linear.weight.uniform_(-bound, bound) else: bound np.sqrt(6.0 / in_features) / self.omega_0 self.linear.weight.uniform_(-bound, bound) def forward(self, x): return torch.sin(self.omega_0 * self.linear(x))class NeRCo_ImplicitNet(nn.Module): def __init__(self, in_dim2, hidden_dim256, num_layers5, feat_dim128): super().__init__() self.feat_dim feat_dim layers [SineLayer(in_dim, hidden_dim, is_firstTrue)] for _ in range(num_layers - 2): layers.append(SineLayer(hidden_dim, hidden_dim)) layers.append(nn.Linear(hidden_dim, 1)) self.mlp nn.Sequential(*layers) # 条件特征调制由骨干特征生成每层的scale和shift self.condition nn.Sequential( nn.Conv2d(feat_dim, feat_dim, 3, padding1), nn.ReLU(), nn.Conv2d(feat_dim, feat_dim * 2, 3, padding1), ) def forward(self, coords, feat): # coords: (B, H, W, 2), feat: (B, C, H, W) B, C, H, W feat.shape cond self.condition(feat) # (B, 2C, H, W) scale, shift cond.chunk(2, dim1) # 各为 (B, C, H, W) scale scale.permute(0, 2, 3, 1) # (B, H, W, C) shift shift.permute(0, 2, 3, 1) # 坐标编码 coords positional_encoding(coords, L10) # (B, H, W, 40) x coords cnt 0 for layer in self.mlp[:-1]: x layer(x) if cnt scale.shape[-1]: # 条件注入等价于 FiLM逐通道调制 s scale[..., cnt:cnt1] b shift[..., cnt:cnt1] x x * s b cnt 1 out self.mlp[-1](x) # (B, H, W, 1) return out代码里有一个非常容易写错的细节条件注入的scale和shift通道数与隐层维度必须严格对齐否则会报维度错误。更重要的是在SIREN网络中插入FiLM的位置不同会带来完全不同的效果。如果放在每个隐藏层之后相当于对每个神经元的激活做全局条件重标定网络对条件的响应最强但也容易过拟合训练集的光照分布。如果只在靠近输出层的位置注入条件的影响会弱一些泛化性更好但增强效果可能不够精准。我自己的经验是将条件注入放在网络中间两层即可既保留前层对坐标的基础拟合又让后层有足够的容量去拟合条件变化。你如果在自己实验中发现增强结果发灰、对比度上不去可以先检查是不是FiLM注入过强把SIREN的固有波动压平了。位置编码函数也一并给出def positional_encoding(coords, L10): 输入坐标范围在[-1,1], shape: (B, H, W, 2) 返回高频特征, shape: (B, H, W, 2*(2*L)) encs [coords] for i in range(L): encs.append(torch.sin(2**i * np.pi * coords)) encs.append(torch.cos(2**i * np.pi * coords)) return torch.cat(encs, dim-1)位置编码之后的特征维度是坐标维度的(12L)倍L取10时44维。这里的频率用2的指数递增好处是覆盖从低频到高频的连续频段。注意coords必须是[-1,1]范围如果输入图像尺寸不是正方形归一化时不要全局归一化要分别按宽高归一化到[-1,1]避免坐标各向异性导致最终的增强结果出现拉伸形变。4.4 完整前向与损失计算把这个网络接到图像上时完整的NeRCo前向过程是低光图先过骨干特征网络提取特征生成坐标网格坐标编码后进入隐式网络结合特征调制预测光照场将预测光照场和原图做Retinex合成得到增强结果。class NeRCoModel(nn.Module): def __init__(self): super().__init__() # 骨干特征提取可以用简单的U-Net减重的版本 self.backbone Backbone(feat_dim128) self.implicit NeRCo_ImplicitNet(feat_dim128) def forward(self, low): feat self.backbone(low) # (B, 128, H, W) coords get_meshgrid(low.shape[2], low.shape[3], low.device) illum self.implicit(coords, feat) # (B, H, W, 1) illum illum.permute(0, 3, 1, 2) # (B, 1, H, W) # Retinex合成增强结果 低光图 / 光照图增加eps防止除零 enhanced low / (illum 1e-6) return enhanced, illum这里除以光照图的操作就是Retinex分解的确定性部分。有些实现会跟着做一个反射图的颜色矫正比如对反射图再做一次channel attention但核心框架不变。需要特别提醒的是illum的预测范围必须约束在合理的正数区间常见做法是在网络输出后接softplus让值恒大于零千万不要用ReLU因为ReLU直接截断负值会让梯度在负区间完全消失导致训练一段时间后大量神经元死亡光照场变成一块块的黑色区域。损失计算部分我给出比较常规的组合import torch.nn.functional as F from torchvision.models import vgg16 class LossComputation(nn.Module): def __init__(self): super().__init__() vgg vgg16(pretrainedTrue).features[:16].eval() for p in vgg.parameters(): p.requires_grad False self.vgg vgg def forward(self, enhanced, normal, illum): l_rec 0.5 * F.l1_loss(enhanced, normal) 0.5 * F.mse_loss(enhanced, normal) l_per F.l1_loss(self.vgg(enhanced), self.vgg(normal)) # 颜色损失在LAB空间比较ab通道的均值 enhanced_lab rgb_to_lab(enhanced) normal_lab rgb_to_lab(normal) l_color F.l1_loss(enhanced_lab[:, 1:], normal_lab[:, 1:]) # 光照平滑损失 tv torch.mean(torch.abs(illum[:, :, :, :-1] - illum[:, :, :, 1:])) \ torch.mean(torch.abs(illum[:, :, :-1, :] - illum[:, :, 1:, :])) loss l_rec * 1.0 l_per * 0.2 l_color * 0.1 tv * 0.05 return loss这里感知损失用VGG的前4个stage——浅层特征对应边缘和纹理深层特征对应内容语义。低光照增强和超分任务有个明显的区别不需要很深层的语义特征约束因为增强不改变物体类别只要保持结构和颜色一致就行用太深的层反而会把光照差异也当成内容差异来做强约束导致结果偏暗淡。4.5 推理阶段与细节处理训练完成后推理非常轻量。加载模型权重读入任意一张低光照图输入网络得到光照图然后做除法增强。推理时的一个优化点是可以对光照图做一次引导滤波或者双边滤波进一步强化光照图的平滑性而不会损失反射图的细节。这一步不算论文的贡献但在实际工程里很管用尤其是照片里的噪点偏多的时候。如果输入图像比较大显卡显存不够可以把图像切成patch分块推理等光照图全部生成后再拼回去。因为隐式网络是坐标驱动的patch的坐标要用全局坐标不能用局部坐标。否则相邻patch的光照预测会各自独立拼起来后出现明显的块状亮度差异。很多人在推理阶段翻车都是栽在这上面。5. 常见问题与排查技巧实录5.1 训练不收敛、损失震荡或Loss突然变NaNNeRCo这类隐式网络最经典的毛病就是训练不稳定。出现NaN大部分情况出在SIREN初始化上。我在代码里已经给出了正确的初始化方式建议你实现后先跑一次前向传播并打印输出的数值范围如果出现sin函数的输入超过几十上百基本就是喂进了未归一化的坐标。另一个常见原因是学习率太高SIREN这类周期性激活网络对学习率非常敏感建议从3e-4起步如果Loss震荡就降到1e-4。还有一点容易被忽略光照场除以零。前期网络没学好的时候illum可能趋近于0最终的高增益会产生极大值反馈给梯度造成爆炸。我习惯在退化操作前设置一个clamp把illum限制在[0.01, 1.0]之间这会在前几百步起到保命效果后期网络学稳了再慢慢放开。5.2 增强图像发灰、对比度不足这个现象我遇到太多次了。原因通常不在网络而在损失函数权重配比上。感知损失和TV损失权重过大会导致局部对比度被压制图像像蒙了一层雾。解决办法是适当调低TV权重提高重建损失的权重同时检查光照场的均值是否被压得过低。光照场均值如果一直小于0.5说明网络倾向“保守地照亮”——把所有像素都往中间亮度拉对比度自然就没了。这时可以在推理阶段对光照场做一个幂次调整illum illum ** gammagamma取0.8到0.9就能明显改善对比度而不会破坏模型本身的结构。5.3 颜色偏色严重低光照图像在增强过程中会放大小传感器的色偏这是所有方法的共性问题。如果增强后图像偏绿或者偏黄先别急着调模型检查数据预处理有没有做白平衡。其次是颜色损失的权重太低可以适当提高。还有一个很容易踩的坑在LAB颜色空间做约束时要保证输入图像没有被过度归一化因为LAB空间对异常值极其敏感如果像素范围超出[0,1]转换后的a、b通道会产生极大值把颜色损失直接拉爆。5.4 训练后推理结果有网格状伪影网格伪影十有八九是位置编码频率过高导致的。编码频率的周期小于图像像素间距时坐标的小数波动被放大成周期性的亮度波动看起来就是网格。解决方法是减小位置编码的最高频率把L从10降到6或者8或者改用随机傅里叶特征并设置合适的标准差。这种情况在低分辨率训练、高分辨率推理时尤其严重所以在推理超大图时要格外注意。下面是一个速查表方便排查现象可能原因解决方法Loss持续NaN坐标未归一化确保坐标映射到[-1,1]Loss持续NaNSIREN初始化不对按代码中的统一方式初始化光照图输出全为0ReLU截断导致梯度消失改用Softplus或直接exp图像发灰感知/VGG损失权重过高降低损失权重提高重建损失颜色偏绿/偏黄未做白平衡或颜色损失太弱预处理白平衡提高颜色损失网格伪影位置编码频率过高降低最高频率或适当减小Lpatch拼接触局部坐标代替全局坐标推理时使用全局归一化坐标6. 个人体会与工程化建议NeRCo是一个“内外”结合得很巧妙的方案。外有Retinex理论的物理可解释性内有隐式神经网络的连续表示能力。如果只把它当做一个增强网络来用你会觉得训练起来比普通CNN更费心思但在光照复杂、分辨率要求高的真实场景里它的优势会随着图像尺寸放大而越来越明显。从代码复现的角度我个人最大的心得是隐式网络的训练曲线和CNN完全不同不要用以前调ResNet的手感去套。它允许你用更激进的坐标编码去拟合高频细节但必须配合更细腻的训练技巧比如梯度裁剪、学习率衰减、条件特征归一化。每一步都像在走钢丝但一旦稳定跑通效果会给你惊喜。实际落地时如果资源有限不建议一开始就在全分辨率上训练。先在256或320的尺度上把光照场结构学稳再小学习率微调高分辨率。这个技巧在我自己的实验中节省了大量显存和调试时间。NeRCo后续值得探索的方向还有很多把光照场从单尺度扩展到多尺度金字塔解决大动态范围场景的局部过曝和暗部噪声问题推理时让用户交互式控制目标曝光度让增强结果真正变成一种可创作的光照编辑工具。这些路都离不开对这篇论文核心思想——“用连续函数重构光照”的深入理解。
返回列表