1.【导读】

彩色图像在数字领域应用广泛,但易受噪声影响,且人类对色彩失真更敏感。深度学习模型虽能实现高精度去噪,却因高计算复杂度和内存需求难以在边缘设备部署;现有基于查找表(LUT)的方法虽高效,却要么忽略RGB通道相关性导致去噪效果差,要么因捕捉通道信息导致存储需求爆炸(如4D/12D LUT需数百TB存储)。

为此,本文提出DnLUT框架:通过Pairwise Channel Mixer(PCM)捕捉通道与空间关联,以L形卷积核减少存储开销,在保持LUT高效性的同时提升去噪质量。其意义在于填补了算法能力与边缘部署需求的缺口,为智能手机等资源受限设备提供了“质量-效率”平衡的解决方案,推动轻量化图像处理技术落地。

2. 【论文基本信息】

DnLUT: Ultra-Efficient Color Image Denoising via Channel-Aware Lookup Tables

  • 论文标题:DnLUT: Ultra-Efficient Color Image Denoising via Channel-Aware Lookup Tables
  • 论文链接:[2503.15931] DnLUT: Ultra-Efficient Color Image Denoising via Channel-Aware Lookup Tables
  • 项目链接:https://github.com/stephen0808/dnlut
  • 核心模块:这篇论文的核心模块包括Pairwise Channel Mixer(PCM),用于有效捕捉通道间相关性和空间依赖性,以及一种新颖的L形卷积设计,旨在最大化感受野覆盖的同时最小化存储开销。

➔➔➔➔点击查看原文,获取更多即插即用模块合集
在这里插入图片描述

3.【模块创新点】

3.1 Pairwise Channel Mixer (PCM)

核心功能

  • PCM模块通过将RGB通道组合成三对(RG、GB、BR),并在并行分支中使用1x2卷积核进行处理,有效地捕捉了通道间的相关性。
  • PCM的设计不仅能够平衡空间和通道信息的处理,还能通过级联的1x1卷积层进一步细化特征。

实现逻辑

  • PCM首先将RGB通道重新组织成三个通道对(RG、GB、BR)。
  • 每个通道对通过一个1x2卷积核进行处理,生成一个中间特征图。
  • 中间特征图再通过级联的1x1卷积层进行细化,最终生成去噪后的图像。

优势

  • PCM有效地捕捉了通道间的相关性,提升了去噪效果。
  • PCM的设计保持了较低的存储需求,适合在边缘设备上部署。
  • PCM可以作为现有LUT方法的插件模块,提升其性能约1dB。
3.2 L-shaped Convolution Kernel

核心功能

  • L形卷积核设计通过每次旋转处理两个额外的像素,确保每个周围像素仅贡献一次输出,最大化像素值的利用并减少存储需求。
  • L形卷积核能够在不牺牲有效感受野覆盖的情况下,将4D LUT转换为3D LUT,显著减少存储需求。

实现逻辑

  • 在每次旋转时,L形卷积核处理两个额外的像素,避免像素重叠。
  • 通过这种设计,L形卷积核能够有效地扩大感受野,同时保持与4D LUT相同的有效感受野大小。

优势

  • L形卷积核减少了存储需求,提升了计算效率。
  • L形卷积核的设计使得DnLUT能够在保持高质量去噪效果的同时,显著减少计算和存储资源的消耗。
3.3 PCM Plug-in Module

核心功能

  • PCM插件模块旨在增强现有LUT方法的性能,通过捕捉通道间的相关性来提升去噪效果。

实现逻辑

  • PCM插件模块在现有LUT方法的基础上,增加了PCM模块的处理步骤。
  • PCM模块在推理过程中与现有LUT方法并行运行,捕捉通道间的相关性。

优势

  • PCM插件模块可以无缝集成到现有的LUT方法中,无需进行结构修改。
  • PCM插件模块在提升性能的同时,仅增加了少量的运行时和存储开销。

4.【算法框架与核心模块】

4.1算法框架

DnLUT 的整体流程分为训练(DnNet)、转换(生成 LUTs)和推理(DnLUT)三个阶段。

  • 训练阶段(DnNet):构建包含 Pairwise Channel Mixer(PCM)和 L 形卷积的网络,输入图像经 4 种旋转(0°、90°、180°、270°)增强后,通过多尺度融合模块整合特征,以 MSE 为损失函数训练。
  • 转换阶段:将训练好的 DnNet 模块映射为 3D 和 4D LUTs,通过穷尽所有可能输入组合生成索引与对应输出,实现从网络到 LUT 的转换。
  • 推理阶段:输入图像经旋转生成索引,通过查询预存的 3D/4D LUTs 快速获取输出,经插值和旋转还原后得到最终去噪结果,避免复杂计算。
4.2核心模块
  1. Pairwise Channel Mixer(PCM)
    针对通道相关性建模不足的问题,PCM 将 RGB 通道重组为 RG、GB、BR 三对,通过并行分支处理:每对通道采用 1×2 卷积核(深度 2),每个操作处理 4 个像素值并输出 1 个通道特征,训练后转换为 4D LUTs(LUT RG、LUT GB、LUT BR)。

    该设计既捕捉了通道间噪声关联,又控制了存储开销(图 3 对比显示其优于单纯空间或通道 - wise 核),且可作为插件提升现有 LUT 方法性能超 1dB。

  2. L 形卷积核
    为解决传统旋转扩展感受野导致的像素冗余问题,L 形核在 4 种旋转中仅处理新增像素(无重叠),使每个像素仅贡献一次,等效于 4D LUT 的感受野但可转换为 3D LUT。

    图 4 对比显示,与 SR-LUT 的 2×2 核相比,L 形核消除了 50% 的像素重复访问,存储需求降低 17 倍(表 7 中 PCM+L 的 LUT 尺寸为 518KB,而 PCM+S 为 902KB)。

5.【框架适用任务】

  1. 高斯彩色图像去噪场景
    适用场景:处理受高斯噪声污染的彩色图像(如合成噪声场景,验证于 CBSD68、Kodak24、Urban100 等基准数据集)。
    核心作用:在低资源消耗(500KB 存储、仅 0.1% 于 DnCNN 的能耗)下,比现有 LUT-based 方法提升 1dB 以上的 CPSNR,平衡去噪质量与计算效率。
  2. 真实世界彩色图像去噪场景
    适用场景:处理智能手机等设备拍摄的含真实噪声的彩色图像(验证于 SIDD、DnD 等真实噪声数据集)。
    核心作用:解决传统 LUT 方法色彩失真和过平滑问题,在保留细节的同时维持色彩一致性,性能远超经典方法(如 CBM3D)近 5dB。
  3. 增强现有 LUT-based 方法性能场景
    适用场景:适配各类基于 LUT 的图像去噪方法(如 SR-LUT、MuLUT、SPFLUT 等)。
    核心作用:通过 PCM 插件模块无需修改原结构,即可提升 1dB 以上的去噪性能,弥补传统 LUT 对 RGB 通道相关性捕捉不足的缺陷。
  4. 边缘设备部署场景
    适用场景:资源受限的边缘设备(如智能手机、物联网终端等,验证于高通骁龙 8 Gen2 平台)。
    核心作用:通过 L 形卷积核(存储需求降低 17 倍)和 LUT 架构,实现 20× 于 CNN 的推理速度,满足实时、低功耗的处理需求。

6.【实验结果与可视化分析】

  1. 模型综合性能对比 :在 CBSD68 数据集(高斯噪声 σ=25)上,DnLUT 的 CPSNR 显著高于现有 LUT-based 方法(如 SPFLUT、MuLUT 等),超出超 1dB;同时存储需求仅约 500KB,运行时间远低于其他方法,且 PCM 插件能为现有 LUT 方法提升 1dB 以上性能,体现了 “高性能 - 高效率” 的平衡。、

  2. 高斯彩色图像去噪定量结果 :在 CBSD68、Kodak24 等 4 个基准数据集上,DnLUT 在各噪声水平(σ=15、25、50)下的 CPSNR 均为 LUT-based 方法中最高。例如,σ=25 时,CBSD68 上 DnLUT 的 CPSNR 为 29.88dB,超过 SPFLUT(28.56dB)1.32dB,且接近经典方法 CBM3D 和 DNN 方法 DnCNN 的性能。

  3. **真实世界彩色图像去噪定量结果 :在 SIDD 和 DnD 数据集上,DnLUT 的 CPSNR/PSNR 显著优于传统方法(如 CBM3D)和其他 LUT-based 方法。如 SIDD 数据集上,DnLUT 的 CPSNR 为 35.44dB,远超 SPFLUT 的 34.91dB,且接近 DnCNN 的 36.45dB;DnD 数据集上,其 PSNR 达 36.67dB,优于 SPFLUT 的 36.22dB。

  4. **定性结果 :图 5 显示在合成高斯噪声场景中,现有 LUT 方法存在明显色彩失真,而 DnLUT 的去噪效果接近 DnCNN 和 CBM3D;图 6 表明在真实世界噪声场景中,DnLUT 能更好保留色彩一致性和细节,避免了其他方法的过平滑问题。

  5. **PCM 插件效果

    表 4 显示 PCM 集成到现有 LUT 方法(如 SR-LUT、SPFLUT)后,CPSNR 提升 1dB 以上(如 SPFLUT 在 CBSD68 上从 28.56dB 提升至 29.72dB)

    图 7 可视化了添加 PCM 后,图像色彩失真减少, perceptual 质量显著提升。

  6. **效率评估 :DnLUT 存储仅 500KB,能耗为 DnCNN 的 0.1%、SPFLUT 的 30%,运行时间是 DnCNN 的 1/20,且在移动平台(骁龙 8 Gen2)上表现优异,适合边缘设备部署。

  7. **L 形卷积核效果 :与 2×2 空间核(PCM+S)相比,L 形核(PCM+L)在 CPSNR 接近的情况下(如 CBSD68 上 26.63dB vs 26.71dB),存储需求从 494+408KB 降至 494+24KB,减少 17 倍,验证了其存储效率优势。

7.【核心代码】

以下是某于提供的代码文件整理的“即插即用”核心模块介绍及关键代码段,涵盖模型加载、推理、训练三大核心场景,突出“即插即用”的便挂性。

7.1模型加载模块
功能

模型加载模块主要负责初始化模型,并在需要时加载之前保存的模型参数,以便继续训练或进行推理。

优势
  • 支持多 GPU 训练,提高训练效率。
  • 可以从指定的迭代次数开始继续训练,方便中断后恢复。
# 以 1_train_model_dnlut.py 为例
if __name__ == "__main__":
    opt_inst = TrainOptions()
    opt = opt_inst.parse()

    modes = [i for i in opt.modes]
    stages = opt.stages

    model = getattr(model, opt.model)

    model_G = model(nf=opt.nf, scale=opt.scale, modes=modes, stages=stages).cuda()

    if opt.gpuNum > 1:
        model_G = torch.nn.DataParallel(model_G, device_ids=list(range(opt.gpuNum)))

    # Load saved params
    if opt.startIter > 0:
        lm = torch.load(
            opt.expDir, 'Model_{:06d}.pth'.format(opt.startIter))
        model_G.load_state_dict(lm.state_dict(), strict=True)

        lm = torch.load(opt.expDir, 'Opt_{:06d}.pth'.format(opt.startIter))
        opt_G.load_state_dict(lm.state_dict())
7.2 模型训练部分
功能

模型训练部分负责对模型进行训练,包括数据加载、前向传播、计算损失、反向传播和参数更新等步骤,同时会定期进行验证和保存模型。

优势
  • 使用 Adam 优化器和学习率调度器,提高训练效果。
  • 支持多 GPU 训练,加速训练过程。
  • 定期保存模型和优化器状态,方便后续恢复训练。
  • 使用 TensorBoard 进行训练过程的可视化监控。
# 以 1_train_model_dnlut.py 为例
if __name__ == "__main__":
    # ... 模型加载部分代码 ...

    # Optimizers
    params_G = list(filter(lambda p: p.requires_grad, model_G.parameters()))
    opt_G = optim.Adam(params_G, lr=opt.lr0, betas=(0.9, 0.999), eps=1e-8, weight_decay=opt.weightDecay, amsgrad=False)

    # LR
    if opt.lr1 < 0:
        lf = lambda x: (((1 + math.cos(x * math.pi / opt.totalIter)) / 2) ** 1.0) * 0.8 + 0.2
    else:
        lr_b = opt.lr1 / opt.lr0
        lr_a = 1 - lr_b
        lf = lambda x: (((1 + math.cos(x * math.pi / opt.totalIter)) / 2) ** 1.0) * lr_a + lr_b
    scheduler = optim.lr_scheduler.LambdaLR(opt_G, lr_lambda=lf)

    # Training dataset
    train_iter = ProviderDN_C(opt.batchSize, opt.workerNum, opt.scale, opt.trainDir, opt.cropSize, opt.sigma)

    # Valid dataset
    valid = DNBenchmark(opt.valDir, sigma=opt.sigma)

    # TRAINING
    i = opt.startIter

    for i in range(opt.startIter + 1, opt.totalIter + 1):
        model_G.train()

        # Data preparing
        st = time.time()
        im, lb = train_iter.next()
        im = im.float().cuda()
        lb = lb.float().cuda()
        dT += time.time() - st

        # TRAIN G
        st = time.time()
        opt_G.zero_grad()

        pred = mulut_predict(model_G, im, 'train', opt)

        loss_G = F.mse_loss(pred, lb)
        loss_G.backward()
        opt_G.step()
        scheduler.step()

        rT += time.time() - st

        # For monitoring
        accum_samples += opt.batchSize
        l_accum[0] += loss_G.item()

        # Show information
        if i % opt.displayStep == 0:
            writer.add_scalar('loss_Pixel', l_accum[0] / opt.displayStep, i)

            logger.info("{} | Iter:{:6d}, Sample:{:6d}, GPixel:{:.2e}, dT:{:.4f}, rT:{:.4f}".format(
                opt.expDir, i, accum_samples, l_accum[0] / opt.displayStep, dT / opt.displayStep,
                                              rT / opt.displayStep))
            l_accum = [0., 0., 0.]
            dT = 0.
            rT = 0.

        # Save models
        if i % opt.saveStep == 0:
            if opt.gpuNum > 1:
                SaveCheckpoint(model_G.module, opt_G, opt, i)
            else:
                SaveCheckpoint(model_G, opt_G, opt, i)

        # Validation
        if i % opt.valStep == 0:
            # validation during multi GPU training
            if opt.gpuNum > 1:
                valid_steps(model_G.module, valid, opt, i)
            else:
                valid_steps(model_G, valid, opt, i)
7.3 推理模块
功能

推理模块负责使用训练好的模型对输入图像进行去噪处理,并计算输出图像的 PSNR 指标,同时将结果保存到指定目录。

优势
  • 支持多种数据集的推理。
  • 可以将输入图像、真实标签和模型输出保存为图像文件,方便可视化结果。
# 以 1_train_model_dnlut.py 为例
def valid_steps(model_G, valid, opt, iter):
    datasets = ['CBSD68', 'Kodak', 'Urban100', 'McMaster']

    with torch.no_grad():
        model_G.eval()

        for i in range(len(datasets)):
            psnrs = []
            files = valid.files[datasets[i]]

            result_path = os.path.join(opt.valoutDir, datasets[i])
            if not os.path.isdir(result_path):
                os.makedirs(result_path)

            for j in range(len(files)):
                key = datasets[i] + '_' + files[j][:-4]

                lb = valid.ims[key]
                input_im = valid.ims[key + '_noise']

                input_im = input_im.astype(np.float32) / 255.0
                im = torch.Tensor(np.expand_dims(
                    np.transpose(input_im, [2, 0, 1]), axis=0)).cuda()

                pred = mulut_predict(model_G, im, 'valid', opt)

                pred = np.transpose(np.squeeze(
                    pred.data.cpu().numpy(), 0), [1, 2, 0])
                pred = np.round(np.clip(pred, 0, 255)).astype(np.uint8)

                left, right = pred, lb
                psnrs.append(PSNR(left, right, opt.scale))  # CPSNR

                if iter < 10000:  # save input and gt at start
                    input_img = np.round(np.clip(input_im * 255.0, 0, 255)).astype(np.uint8)
                    Image.fromarray(input_img).save(
                        os.path.join(result_path, '{}_input.png'.format(key.split('_')[-1])))
                    Image.fromarray(lb.astype(np.uint8)).save(
                        os.path.join(result_path, '{}_gt.png'.format(key.split('_')[-1])))

                Image.fromarray(pred).save(
                    os.path.join(result_path, '{}_net.png'.format(key.split('_')[-1])))

            logger.info(
                'Iter {} | Dataset {} | AVG Val PSNR: {:02f}'.format(iter, datasets[i], np.mean(np.asarray(psnrs))))
            writer.add_scalar('PSNR_valid/{}'.format(datasets[i]), np.mean(np.asarray(psnrs)), iter)
            writer.flush()

➔➔➔➔点击查看原文,获取更多即插即用模块合集
在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐