利用离散余弦变换 (DCT) 执行图像压缩

408 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第27天,点击查看活动详情

前言

离散余弦变换 (Discrete Cosine Transform, DCT) 以不同频率振幅的余弦函数组合表示图像,而离散傅里叶变换 (Discrete Fourier Transform, DFT) 则以复杂指数的形式使用正弦和余弦函数。以下方程式显示了如何计算 N×NN×N 图像 f(x,y)f(x,y)DCT 的第 (i,j)(i,j) 项(系数):

D(i,j)=12NC(i)C(j)x=0N1y=0N1f(x,y)cos[(2x+1)iπ2N]cos[(2y+1)iπ2N]D(i,j)=\frac 1 {\sqrt{2N}}C(i)C(j)\sum ^{N-1} _{x=0}\sum ^{N-1} _{y=0}f(x,y)cos[\frac {(2x+1)i\pi}{2N}]cos[\frac {(2y+1)i\pi}{2N}]

其中 C(u)={12u=01u>0C(u)=\left\{ \begin{array}{rcl} \frac 1 {\sqrt 2} & & {u=0}\\ 1 & & {u>0} \end{array} \right.,对于块大小为 8×88\times8DCTN=8N=8

利用离散余弦变换 (DCT) 执行图像压缩

DCT 算法用途广泛,通常用于实现图像 JPEG 压缩,在本节中,我们将学习如何使用 Python 执行图像重建操作。

(1) 首先,导入所需库,关键在于从 scipy.fftpack 模块导入所需的函数 dct()idct()

import scipy.fftpack as fp
from skimage.io import imread
from skimage.color import rgb2gray, gray2rgb
from skimage.draw import rectangle_perimeter
import numpy as np
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D  # noqa: F401 unused import
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.ticker import LinearLocator, FormatStrFormatter
from scipy.fftpack import dct, idct

(2) 使用 scipy.fftpackdct()idct() 函数分别定义函数 dct2()idct2() 以实现 2D-DCTIDCT。其中,函数 dct() 的调用方式如下,而 idct() 函数的调用方式类似:

scipy.fftpack.dct(x, type=2, n=None, axis=-1, norm=None, overwrite_x=False)

该返回任意类型序列x的离散余弦变换。

根据在前言中介绍的 DCT 方程,并使用通过使用参数 norm ='ortho' 应用归一化:

def dct2(a):
    return dct(dct(a, axis=0, norm='ortho'), axis=1, norm='ortho')

def idct2(a):
    return idct(idct(a, axis=0, norm='ortho'), axis=1, norm='ortho')  

(3) 读取输入 RGB 图像并将其转换为灰度。计算图像的 2D-DCT,然后利用 IDCT 使用前面定义的函数重建图像:

im = rgb2gray(imread('1.png'))
imF = dct2(im)
im1 = idct2(imF)

(4) 检查重建的图像,观察其与原始图像之间的差别,查看其是否与原始图像相同,在这里使用函数 np.callclose() 评估图像间的差距:

print(np.allclose(im, im1))

(5) 使用 matplotlib.pyplot 绘制原始图像和重建图像,得到结果如下所示:

plt.figure(figsize=(10,5))
plt.gray()
plt.subplot(121), plt.imshow(im), plt.axis('off'), plt.title('original image', size=10)
plt.subplot(122), plt.imshow(im1), plt.axis('off'), plt.title('reconstructed image (DCT+IDCT)', size=10)
plt.tight_layout()
plt.show()

Figure_4.png

在以上结果图像中可以看到,重建后的图像与原始图像在视觉效果上类似,证明了可以使用 DCT 进行图像压缩,使用 IDCT 对压缩后的图像进行重建。