频域图像压缩与滤波

2020-11-07 11:23:58

4年多前,我写了一篇关于频域图像的简短博客文章:https://blog.demofox.org/2016/07/28/fourier-transform-and-inverse-of-images/。

现在是时候再回顾一下这个话题,并补充一些东西了。

如果你想知道傅里叶变换是如何工作的,它可以将图像或其他数据转换到频域,请阅读以下内容:https://blog.demofox.org/2016/08/11/understanding-the-discrete-fourier-transform/。

当您将图像变换到频域时,您会得到每个像素的复数(具有实部和虚部),您可以使用该复数来获取有关制作图像的频率(文字正弦波和余弦波)的信息。一条信息是该波的“相位”或起始角。您可以使用atan2(虚数,实数)来获得相位。另一条信息是该波的“振幅”,或者说该波在图像中有多大。振幅是2D向量(实数、虚数)的长度。

那么,进行图像压缩的一个快速而简单的方法是将图像转换到频率空间,找到最低的振幅频率,然后丢弃它们--字面意思是将复数清零。如果你丢弃了足够多的图像,那么描述图像的频率内容所需的数据就会比图像的像素少,这样你就可以压缩图像了。

不过,你在丢弃频率方面越积极,图像质量就会下降得越多。这是一种“有损”压缩,是jpg图像压缩方式的简化版本。有损压缩与PNG文件中的无损压缩形成对比,PNG文件使用更像.zip压缩算法来完美地编码所有源数据。

在本文附带的代码中,DoTestZeroing()函数抛出最低10%的振幅频率,然后是最低的20%,然后是30%,以此类推,直到90%。在每个阶段,它将所有复频率值写出到一个二进制文件中,然后可以使用.zip作为实现图像压缩的方法来压缩该文件。随着数据变得更多零,它变得更可压缩。

下图顶行显示了原始512×1024图像、DFT幅度信息和DFT相位信息。最下面一行显示的是相同的,但对于已经丢弃了较低90%振幅频率的图像。两者(未压缩)的DFT数据都是8MB,顶部图片压缩到7.7MB,但底部图片只压缩到847KB。利用逆DFT将修改后的底部频率数据恢复为图像。

这是另一幅512×512的图像,其DFT是4MB未压缩的。上图的DFT数据压缩到3.83MB,下图压缩到438KB。

虽然相当有效,但对于基于频率的图像压缩来说,这也是一种相当幼稚的方式!

更复杂的方法使用“离散余弦变换”或DCT而不是DFT,因为它倾向于使更多的频率幅度为零,将数据合并到较少的重要频率,这意味着在你开始丢弃频率之前,它已经很小了。DCT和DFT还假装图像永远在继续,而不是仅仅停留在边缘。DFT的作用就像是以平铺的方式重复这些图像,而DCT的作用就像它们在每次重复时都被镜像一样,这也是图像质量的一个很好的属性。

其他方法在进行基于频率的压缩之前将图像分解成块。此外,您还可以使用小波来压缩图像,或者使用主成分分析或奇异值分解。你也可以用你想要的“任何”基函数来拟合你的图像,使用L1范数正则化将你的拟合系数提升为零,使拟合数据不那么稀疏,就像DCT和DFT相比所做的那样。

你可以做的另一件事是使用压缩传感跳过几个步骤:你从图像中取几个随机但大致均匀的样本(蓝色噪声或LD将是很好的选择),然后你就可以例如求出傅立叶基系数(DFT!)。与你采集的稀疏/不规则数据样本相匹配。这就像扔掉低频,但不必对整个数据集进行DFT,然后再扔掉。它从稀疏数据开始,然后再进行匹配。

巴特·沃伦斯基(Bart Wronski)在他的博客上有几篇关于这一领域的文章,如果你感兴趣,请阅读它们:https://bartwronski.com/2020/08/30/compressing-pbr-texture-sets-with-sparsity-and-dictionary-learning/。

这是一本很棒的读物,展示了如何使用L1正则化来拟合数据,以及您可能感兴趣的所有相关信息:https://www.analyticsvidhya.com/blog/2017/06/a-comprehensive-guide-for-linear-ridge-and-lasso-regression/。

这个视频很好地概述了我提到的其他东西的随机抓包:https://www.youtube.com/watch?v=aHCyHbRIz44&;feature=youtu.be

在我上一篇关于这个主题的文章中,我展示了如何丢弃距离图像中心一定距离的频率,对图像进行低通滤波,也就是模糊图像。我还展示了,如果你扔掉比一定距离更近的频率,它会对图像进行高通滤波,也就是锐化图像。

丢弃基于距离的频率数据等同于将频率数据乘以掩码,掩码在某些地方为1.0,在其他地方为0.0。您可以将其概括为将频率乘以任何数字。在下面我将乘法限制在0到1之间,但是如果你愿意,你绝对可以选择更大的数字,甚至是负数。

下面显示了在这一部分中图像相乘的模式。顶行从左到右是一个低通滤波器,然后是一个更强的低通滤波器(去掉了更多的高频),最后是一个陷波滤波器或“带阻”滤波器。最下面的一行是补码,这样你就可以从白色(1.0)中减去图像得到底部。从左到右,最下面一行是一个高通滤波器,然后是一个较弱的高通滤波器(让更多的低频进入),然后是一个只允许特定频率通过的带通滤波器。

首先关注的是“洛基和艾伦”的照片。从顶部的图片中过滤出的频率和实际图像值出现在底部的图片中,反之亦然。在这种情况下,模糊和锐化(和边缘检测)是一枚硬币的两面。重要的是你扔掉了哪部分,保留了哪部分。

这是频率的大小看起来是什么样子。请注意,每幅图像都有经过对数函数的幅值,并且也归一化为1.0max。这就是为什么即使高通滤波器(和带通)会使中间部分变暗,但看起来并不是这样。重整化稍微掩盖了这一事实,中间是最亮的(振幅最大),这是我们在最后一部分中抛出最低振幅时看到的。

以下是应用于风景图像的相同滤镜。如果你仔细观察,右上角的图片中有一些奇怪的图案(点击图片可以在另一个选项卡中查看完整尺寸)。

在最后一节中,我们使用一个距离函数来制作“图像”,使值乘以特定的频率,从而滤除特定的频率。

在这一部分,我们将拍摄两幅图像,将它们放入频率空间,相乘,再从频率空间中取出,看看会产生什么样的结果。

有一种叫做“卷积定理”的东西告诉我们,频域中的乘法与图像之间的卷积是一样的。卷积是一种昂贵的操作,因为您必须循环遍历一幅图像的所有像素,并在每个像素处循环遍历另一幅图像的像素,然后进行一些乘法和加法运算。卷积的速度非常慢,所以把你想要卷积到频域的两幅图像相乘在一起,然后把它们从频率空间中拿出来再次成为图像,实际上可能会更快。

卷积在图形中被用于模糊、锐化或应用bokeh来获得景深,所以加速它会有很大的帮助!卷积也被用于音频中,比如混响,它使音频听起来像是在洞穴或大教堂里播放的声音。

技术说明:“内核”图片需要在像素(0,0)处居中,而不是图片的中心。另外,内核图像应该被规格化,这样它的所有像素加起来就是1.0。在进行DFT之前,您还需要将源图像和内核图像都填零(添加黑色像素边框)为x和y轴上的源+内核+1的大小,以使它们的大小相同,并避免包装问题。在完成乘法和逆DFT后,可以再次移除黑色边框。

以下是我们将用作内核图像的4个图像:一个星星、一个加号、一个圆圈和一个斑点。

您可以看到,这些图像以某种方式呈现出内核…的品质。星形的很有棱角,正的很“正像”,圆形的很圆。请注意,斑点的行为非常像一个低通滤波器!在频率空间中,它看起来确实像一个,所以这是有道理的:

如果你觉得在图像上做卷积看起来很奇怪,你应该听听音频中使用的卷积。当用于混响时,它听起来很好听,而且听起来很正确,但是如果你用它把任意的音频样本卷积在一起,你可以得到一些非常有趣和奇怪的声音!你可以在这里听到:https://blog.demofox.org/2015/03/23/diy-synth-convolution-reverb-1d-discrete-convolution-of-audio-samples/。

图像周围的黑色边框是通过在图像周围添加黑色边框以使其大小合适(零填充)而产生的瑕疵。如果你只是把卷积内核图像做得和你要卷积的图像一样大(这已经是2的幂了,因为这是FFT的要求),你会得到下面的图像,它的一部分图像从另一面“包裹”过来。

如果你使用DCT(离散余弦变换),它会镜像纹理而不是包裹它,所以你会得到更多与大多数时候应该存在的像素相似的像素,而不是包裹的DFT。不过,解决这个问题的另一种方法是,如果你在图像空间而不是频率空间进行卷积,你可以丢弃任何超出图像有效区域的样本。你需要把你实际采集的样本的重量相加,然后将最终的卷积和除以这个重量,以使其归一化。这将使边界附近的像素具有比其应有的更高的权重,但与黑色边框、包裹或镜像瑕疵相比,它可能不是那么刺耳的瑕疵。

说实话,本文中的许多操作都可以在几行Python代码中完成。不过,我发现自己实现这些东西很有价值,因为它帮助我将想法内化,以便更好地理解何时以及如何使用它们,以及如何避免当东西被用作黑匣子时出现的问题/谜团。不过,在最近研究了与奇异值分解(SVD)、主成分分析(PCA)和寻找特征向量相关的大量算法之后,我感觉潮流发生了变化。这是一些疯狂的事情,对于一个人来说太难处理了,同时仍然试图在其他话题上胜任😛