iWave-新一代图像压缩技术


✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨

🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。

我是Srlua小谢,在这里我会分享我的知识和经验。🎥

希望在这里,我们能一起探索IT世界的奥妙,提升我们的技能。🔮

记得先点赞👍后阅读哦~ 👏👏

📘📚 所属专栏:传知代码论文复现

欢迎访问我的主页:Srlua小谢 获取更多信息和资源。✨✨🌙🌙

​​

​​

目录

背景及动机

提出的方法

A.iWave变换

B.训练结构和损失函数

实验

实验设置

实验结果

代码复现

部署方式

代码演示流程

1.首先进行编码,同时指定存放二进制文件的文件夹

2.编码得到压缩后的二进制文件

3.配置文件内容如下

4.对二进制文件进行解码,同时指定输出图像的位置和名称

复现结果展示


 本文所有资源均可在该地址处获取。

本文选自"iWave:CNN-based Wavelet-like Transform for Image Compression",源码可以通过附件查看

背景及动机

小波变换作为一种强大的多分辨率时频分析工具,已经被广泛应用于许多图像处理任务,如去噪、增强、融合,特别是压缩。由于基的局部支持,小波变换在处理具有点奇异性的信号时,相比具有全局支持的傅里叶变换系列具有优势。小波变换引导了成功的图像编码标准JPEG-2000。然而,已经报道小波变换在处理自然图像时仍然存在局限性。
首先,小波变换对于二维图像通常通过沿水平和垂直方向分别进行两步一维变换。这导致了在处理既非水平又非垂直的图像特征时效率低下。
其次,小波变换通常在整个图像上均匀地执行,即同一组变换核应用于所有地方。然而,自然图像具有局部变化的特征,因此均匀变换和非均匀图像之间存在冲突。
为了克服上述局限性,提出了一些新的类似小波的变换,例如ridgelet、curvelet、contourlet等,它们为具有任意方向特征的图像提供了良好的表示。然而,这些变换采用了过完备基,导致了过多的变换系数,难以有效压缩。
另一系列专门为图像压缩设计的方法选择将图像分成块,为每个块选择一个方向,并沿该方向执行变换,这些方向将被发送到解码器。这些方法通常利用提升方案来实现任意方向变换的灵活性,例如基于自适应方向提升(ADL)的小波变换和基于加权自适应提升(WAL)的小波变换。这些方法比JPEG-2000实现了更高的压缩效率,但代价是增加了复杂性和辅助信息(块方向)。
最近,卷积神经网络(CNN)在不同的图像处理任务中取得了一系列成功,如识别、分割、超分辨率以及与图像压缩相关的任务。CNN在处理自然图像方面具有几个明显的优势。
首先,CNN中的二维卷积核使其能够捕捉图像中的任意方向二维特征。
其次,本地接收域和多个卷积核的集合使其能够同时有效地处理不同的局部特征。
第三,也是最重要的,CNN中的卷积核是从大量图像中学习到的,而不是手工设计的,这意味着CNN更适合处理自然图像。然而,CNN仍然存在一个未解决的问题,即其可解释性,特别是关于网络结构的解释:为什么CNN应该以这种方式构建,而不是那种方式?虽然有直观的解释和有见地的观察,但缺乏系统和数学的答案。
考虑到传统小波及其变种的缺点,以及CNN的成功,本文中提出了一种新的基于CNN的小波类变换,称为iWave。我们的关键思想来源于提升方案,该方案将小波变换分解为一系列预测和更新操作。对于传统小波变换,这些预测/更新操作是线性的;对于提出的iWave,这些预测/更新操作由训练的CNN实现,具有非线性和信号自适应性。
换句话说,iWave采用提升方案并将CNN作为构建块集成到提升方案中。只要CNN是专门为自然图像训练的,iWave在处理自然图像时比传统小波变换更有效。这通过论文的实验结果得到了证实,并且文章采用iWave进行图像压缩并与JPEG-2000进行了比较。
iWave与传统小波变换的区别仅在于基于CNN的预测/更新操作。
本文的技术贡献如下:

  1. 这是首个提出基于更新优先提升方案的CNN小波类变换的。iWave比作为“黑盒”训练的CNN更具可解释性。
  2. 为了图像压缩的目的,使用了一种新的训练策略,以端到端方式训练iWave。
  3. 论文进行了广泛的实验,以验证iWave的有效性,特别是在处理特定类型的不规则纹理时表现出色。

提出的方法

这一小节中提出了用于图像压缩的iWave方法。内容包括三部分:首先介绍iWave作为一种新型的小波类变换的结构;其次介绍获得iWave的训练方法和损失函数。

A.iWave变换

iWave通过在提升方案中引入CNN实现类似小波的变换。与第一代定义为一个函数的平移和缩放的传统小波相比,提升方案提供了更快的就地实现,并且保证了完美重建。论文从压缩任务的需求出发,设计了网络结构,采用了更新优先的提升方案。首先从比较两种提升结构(预测优先和更新优先)开始,随后介绍用于二维图像的iWave变换结构。

图1 预测为先的提升机制

图2 更新为先的提升机制

预测优先提升方案包括三个步骤:分割、预测和更新。
iWave采用了更新优先提升方案,实验表明其性能更好。本质上,用训练好的CNN替代了图1中的预测块。
iWave可以通过在行和列方向分别进行分解,从一维扩展到二维,类似于传统的小波变换。图3展示了iWave用于二维图像的整体变换结构。在行变换之后, iWave对图像进行分解的结果是四个子带:一个粗略子带LL,和三个细节子带HL、LH和HH。尽管iWave是分开进行二维变换,但由于CNN中使用的二维滤波器,它仍然能有效捕捉图像中的特征。
iWave的关键模块是由密集CNN(Dense CNN)实现的预测块,本文中具体的密集CNN结构如图4所示。由于小波具有局部支持基,这与传统提升方案中的滤波器阶数和iWave中CNN的接收域有关。较大的支持范围可以生成更平滑的粗略系数带,但也更可能无法表示图像的边缘。密集CNN实际上具有各种接收域,通过训练过程可以获得最适合自然图像的支持范围。选择使用密集CNN的另一个原因是,可以使用更少的卷积核,这有助于减少模型的规模。本文在每层使用tanh函数作为激活函数,除最后一层外,其他层均使用线性激活函数。需要注意的是,ReLU广泛使用,但在iWave中不适合。

图3 iWave的前向过程

图4 预测CNN的网络结构

B.训练结构和损失函数

本文选择逐步保留越来越多的系数,这使损失函数具有多个部分,每个部分测量在一定系数保留比例下的重建质量。重建过程选择渐进式重建,因为希望训练后的iWave能像传统小波变换一样应用于可伸缩的图像压缩。具体而言,在训练时,可以使用一次正向变换和多轮逆向变换,每轮使用部分系数进行重建。所有的重建误差被累加形成训练的损失函数。实际上,将每个子带视为一个单元,每次增加一个子带。假设进行N次分解,那么会得到3N+1个子带,根据上述方法,可以有如下损失函数:

LN=∑i=13Nd(X,Xi)LN​=i=1∑3N​d(X,Xi​)

dd表示均方差,XiXi​表示重建图像。
上述过程自然形成了一种端到端的训练策略。图5给出了这种训练结构的示意图,其中编码部分和解码部分分别对应于iWave的正向和逆向变换。需要注意的是,图5中显示了两次分解,但可以迭代使用iWave进行多次分解,以获得多分辨率表示。

图5 iWave的端到端训练

训练结构包括多次分解,即多次iWave变换,导致训练过程中采用的一组预测CNN块。选择让所有预测CNN块在多次分解中共享同一组参数。这使得iWave与分辨率无关,一旦获得iWave,可以用于任何次分解的图像压缩。共享参数也使得训练后的模型唯一,因此模型参数可以轻松存储和传输。

实验

实验设置

使用DIV2K数据集中的900张高分辨率图像进行训练,并在由24张图像组成的知名Kodak数据集上进行测试。将图像分割为128×128的块进行训练。在端到端训练结构中嵌入了三次分解。训练采用默认设置的Adam算法,学习率经验设定为0.0001,降低学习率并不能提升性能。训练在NVIDIA GTX1080Ti GPU上使用TensorFlow进行。

实验结果

图6 iWave与JPEG2000使用5/3滤波和9/7滤波对比

图7 iWave与其他经典算法性能对比

图8 iWave与JPEG2000计算复杂度对比

代码复现

代码在附件当中,iWave的核心代码逻辑如下:

paddings = (0,0,0,1)
        tmp = F.pad(L, paddings, "reflect")
        tmp = tmp[:,:,1::,:]
        H = H + self.lifting_coeff[0]*(L+tmp)

        paddings = (0, 0, 1, 0)
        tmp = F.pad(H, paddings, 'reflect')
        tmp = tmp[:,:,0:-1,:]
        L = L + self.lifting_coeff[1]*(H+tmp)

        paddings = (0, 0, 0, 1)
        tmp = F.pad(L, paddings, "reflect")
        tmp = tmp[:, :, 1::, :]
        H = H + self.lifting_coeff[2] * (L + tmp)

        paddings = (0, 0, 1, 0)
        tmp = F.pad(H, paddings, 'reflect')
        tmp = tmp[:, :, 0:-1, :]
        L = L + self.lifting_coeff[3] * (H + tmp)

        L = self.lifting_coeff[5] * L
        H = self.lifting_coeff[4] * H

        return L, H

这是提升机制的实现代码,分解到两个自带。

self.ll_scale = bool(wavelet_trainable) * self.ll_scale_net() + scale_init
        self.hl_scale = bool(wavelet_trainable) * self.hl_scale_net() + scale_init
        self.lh_scale = bool(wavelet_trainable) * self.lh_scale_net() + scale_init
        self.hh_scale = bool(wavelet_trainable) * self.hh_scale_net() + scale_init
        
        size = x.size()
        yuv_x = rgb2yuv(x)
        # forward transform
        LL = yuv_x
        HL_list = []
        LH_list = []
        HH_list = []
        for i in range(self.trans_steps):
            if wavelet_trainable:
                if self.wavelet_affine:
                    LL, HL, LH, HH = self.wavelet_transform[i].forward_trans(LL)
                else:
                    LL, HL, LH, HH = self.wavelet_transform.forward_trans(LL)
            else:
                LL, HL, LH, HH = self.wavelet_transform_97.forward_trans(LL)

            if train and wavelet_trainable:
                HL_list.append(self.soft_round_quant.forward(HL, self.hl_scale, alpha))
                LH_list.append(self.soft_round_quant.forward(LH, self.lh_scale, alpha))
                HH_list.append(self.soft_round_quant.forward(HH, self.hh_scale, alpha))
            else:
                HL_list.append(torch.round(HL / self.hl_scale))
                LH_list.append(torch.round(LH / self.lh_scale))
                HH_list.append(torch.round(HH / self.hh_scale))
        if train and wavelet_trainable:
            LL = self.soft_round_quant.forward(LL, self.ll_scale, alpha)
        else:
            LL = torch.round(LL / self.ll_scale)

        if not coding:
            bits = torch.cuda.FloatTensor((20,1))*0.0
        else:
            bits = self.coding_LL(LL)
        LL = LL * self.ll_scale
        context = LL

        for i in range(self.trans_steps):
            j = self.trans_steps - 1 - i

            if coding:
                bits = bits + self.coding_HL_list[j](HL_list[j],context)
            HL_list[j] = HL_list[j] * self.hl_scale

            if coding:
                bits = bits + self.coding_LH_list[j](LH_list[j], torch.cat((context, HL_list[j]),1))
            LH_list[j] = LH_list[j] * self.lh_scale

            if coding:
                bits = bits + self.coding_HH_list[j](HH_list[j], torch.cat((context, HL_list[j], LH_list[j]),1))
            HH_list[j] = HH_list[j] * self.hh_scale

            context = torch.cat((context, HL_list[j], LH_list[j], HH_list[j]), 1)
            context = F.interpolate(context, scale_factor=2, mode='bicubic')

            if wavelet_trainable:
                if self.wavelet_affine:
                    LL = self.wavelet_transform[j].inverse_trans(LL, HL_list[j], LH_list[j], HH_list[j])
                else:
                    LL = self.wavelet_transform.inverse_trans(LL, HL_list[j], LH_list[j], HH_list[j])
            else:
                LL = self.wavelet_transform_97.inverse_trans(LL, HL_list[j], LH_list[j], HH_list[j])

        batch_size = size[0]
        rgb_org = yuv2rgb(torch.cat((LL[:batch_size], LL[batch_size:2*batch_size], LL[2*batch_size:]), 1))
        rgb_post = self.post(rgb_org)

这部分是网络训练的整个前向过程,重点的思想是分解到四个自带后进行渐进式的端到端训练。

部署方式

  • 编码:
### image folder
python /${code_dir}/NIC/Encoder/encoder.py --inputPath ${data_dir} --outputPath ${bin_dir} --ckptdir ${CKPTDIR} -m ${parameter_set_id} --cfg /${code_dir}/NIC/Encoder/cfg/iwave_cfg/encode_iWave_lossy.cfg --outlog ${enc_time_log}
### single image
python /${code_dir}/NIC/Encoder/encoder.py -i ${img_filename} -o ${bin_filename} --ckptdir ${CKPTDIR} -m ${parameter_set_id} --cfg /${code_dir}NIC/Encoder/cfg/iwave_cfg/encode_iWave_lossy.cfg --outlog ${enc_time_log}

  • Cfg配置文件
### Lossy
{
	"picture_syntax": {
        "profile_id": 2,
        "model_id": 0,
		"quality_id": 3,
        "picture_size_h": 1024,
        "picture_size_w": 1024,
        "log2_slice_size_h_minus6": 5,
        "log2_slice_size_w_minus6": 5,
        "coding_tool": {
			"filtering_model_id": 0,
			"code_block_size": 64
		}
	},
	"slice_syntax": {
    }
}
### Lossless
{
	"picture_syntax": {
        "profile_id": 2,
        "model_id": 2,
        "parameter_set_id": 10,
		"quality_id": 0,
        "picture_size_h": 1024,
        "picture_size_w": 1024,
        "log2_slice_size_h_minus6": 5,
        "log2_slice_size_w_minus6": 5,

        "coding_tool": {
			"filtering_model_id": 0,
			"code_block_size": 64
		}
	},
	"slice_syntax": {
    }
}
--model_id: '0' models optimized for mse; '1' models optimized for perception; '2' lossless
--parameter_set_id: 0-4 for model_id==0; 5-9 for model_id==1; 10 for model_id==2
--quality_id: control rate. 0-7 for parameter_set_id from 0-9, default set as 3.

  • 解码:
### bin folder
python /${code_dir}/NIC/Decoder/decoder.py --binpath ${bin_dir} --recpath ${recon_dir} --ckptdir ${CKPTDIR} --outlog ${dec_time_log}
### single bin
python /${code_dir}/NIC/Decoder/decoder.py -i ${bin_filename} -o ${recon_filename} --ckptdir ${CKPTDIR} --outlog ${dec_time_log}

代码演示流程

1.首先进行编码,同时指定存放二进制文件的文件夹

2.编码得到压缩后的二进制文件

3.配置文件内容如下

4.对二进制文件进行解码,同时指定输出图像的位置和名称

复现结果展示

使用RGB彩色遥感图像进行实验,将iWave方法与JPEG2000,BPG,VVC等传统的图像压缩编码方式进行对比,计算峰值信噪比可以发现,iWave的性能强于JPEG2000,但是相较于BPG和VVC更加复杂的编码实现来说,其编码性能上还存在一定差距。

图9 iWave与其他编码方式可视化对比

​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值