数字水印 | 离散余弦变换 DCT 基本原理及 Python 代码实现



1 基本原理

参考博客:https://www.cnblogs.com/zxporz/p/16072580.html

D C T \mathsf{DCT} DCT 全称为 D i s c r e t e   C o s i n e   T r a n s f o r m \mathsf{Discrete\ Cosine\ Transform} Discrete Cosine Transform,即离散余弦变换。 D C T \mathsf{DCT} DCT 变换属于傅里叶变换的一种,常用于对信号和图像(包括图片和视频)进行数据压缩。 D C T \mathsf{DCT} DCT 是视频压缩史上最重要的发明之一,对于 H . 26 X \mathsf{H.26X} H.26X J P E G \mathsf{JPEG} JPEG 等压缩标准的制定至关重要。

虽然 D C T \mathsf{DCT} DCT 具有比较复杂的数学公式,但是我们这里仅做简单理解。

对一幅图像执行离散余弦变换 ( D C T ) \mathsf{(DCT)} (DCT) 相当于将图像的能量集中在变换系数的左上角,这部分系数被称为直流 ( D C ) \mathsf{(DC)} (DC) 系数。直流系数是 D C T \mathsf{DCT} DCT 最重要的输出之一,因为它携带了原始图像的大部分信息。其余的系数,分布在左上角之外的区域,被称为交流 ( A C ) \mathsf{(AC)} (AC) 系数。这些系数包含了图像的细节信息,反映了图像的纹理和边缘。

只要对这些 D C T \mathsf{DCT} DCT 系数做逆离散余弦变换 ( I D C T ) \mathsf{(IDCT)} (IDCT),理论上就可以重建出原始图像的像素矩阵。需要注意的是, D C T \mathsf{DCT} DCT 本身并不直接压缩数据。它起到的是一个准备作用,为后续的量化、编码等压缩步骤提供了有力的数学基础。量化过程会根据需要压缩的强度,减少 A C \mathsf{AC} AC 系数中的某些值,从而实现数据压缩。

假设一张图片由 3 × 3 3\times3 3×3 个像素块构成,如下图所示:

原文说的是,取一个图像中的一部分,且这个部分只包含 3 × 3 3\times3 3×3 个像素。

如上图所示,相当于是把其余格的部分信息(特征)都抽取到了第一个格。第一个格的像素值就是这个图像的低频信息,其余格的就是这个图像的高频信息。低频信息主要表示的是一张图的总体样貌,一般低频系数的值也比较大。而高频信息主要表示的是图像中人物或物体的细节,一般高频系数的数量较多。做完 D C T \mathsf{DCT} DCT 变换后,低频信息和高频信息就分离开来了。



2 代码实现

参考博客:https://blog.csdn.net/qq_41821067/article/details/114113677

import cv2
import numpy as np
from matplotlib import pyplot as plt


# 处理原始图像
img = cv2.imread('logo.jpg', 0)  # 读取图像为灰度图像
print("img.shape:", img.shape)
img1 = img.astype('float32')  # 将unit8类型转换为float类型

# 进行离散余弦变换
img_dct = cv2.dct(img1)
print("img_dct:", img_dct)
print("img_dct.shape:", img_dct.shape)

# 进行对数处理
img_dct_log = np.log(abs(img_dct))
print("img_dct_log:", img_dct_log)

# 进行逆离散余弦变换
img_recor = cv2.idct(img_dct)
print("img_recor:", img_recor)
print("img_recor.shape:", img_recor.shape)

# 判断是否相同
print("img:", img)
print("img_recor:", img_recor)
print(abs(img - img_recor) < 1)

# 画图
plt.subplot(1, 4, 1)
plt.title("Original Image", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(img, cmap="gray")

plt.subplot(1, 4, 2)
plt.title("Coefficients", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(img_dct, cmap="gray")

plt.subplot(1, 4, 3)
plt.title("Log", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(img_dct_log, cmap="gray")

plt.subplot(1, 4, 4)
plt.title("Recovered Image", fontsize=12, loc="center")
plt.axis('off')
plt.imshow(img_recor, cmap="gray")

plt.savefig('test.jpg', dpi=400, bbox_inches='tight')
plt.show()

代码说明:

  • 根据 img.shapeimg_dct.shape 的结果可知 D C T \mathsf{DCT} DCT 并不会改变图像的大小。
  • 根据 img_dct 可知 D C T \mathsf{DCT} DCT 系数非常小,以至于在视觉上难以区分。为了更好地可视化这些系数,我们对其进行对数变换,以拉伸坐标轴的刻度,使得小的系数在图像中也能显示出来。
  • 根据 imgimg_recor 可知原始图像和还原后的图像并不完全相等,但是根据 print(abs(img - img_recor) < 1) 可知二者之间的像素差值不会超过 1 1 1

效果如下:

在这里插入图片描述



3 图像压缩

import cv2
from matplotlib import pyplot as plt


# 处理原始图像
img = cv2.imread('logo.jpg', 0)  # 读取图像为灰度图像
img1 = img.astype('float32')  # 将unit8类型转换为float类型

# 进行离散余弦变换
img_dct = cv2.dct(img1)

# 压缩图像
zip_len = [10, 20, 50, 100, 200, 300, 500, 800]  # 压缩后的图像大小

for i in range(len(zip_len)):
    # 进行逆离散余弦变换:仅保留左上角的部分数据
    img_recor = cv2.idct(img_dct[0:zip_len[i], 0:zip_len[i]])
    print("img_recor.shape:", img_recor.shape)

    # 画图
    plt.subplot(2, int(len(zip_len) / 2), i + 1)
    plt.title("zip_len={zip_len}".format(zip_len=zip_len[i]), fontsize=12, loc="center")
    plt.axis('off')
    plt.imshow(img_recor, cmap="gray")

plt.savefig('compress.jpg', dpi=400, bbox_inches='tight')
plt.show()

核心代码:

cv2.idct(img_dct[0:zip_len[i], 0:zip_len[i]])

使用 D C T \mathsf{DCT} DCT 进行图片压缩的本质,就是仅保留部分左上角的 D C T \mathsf{DCT} DCT 系数,通过逆变换构建被压缩了的图像。

效果如下:

在这里插入图片描述



  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DCT离散余弦变换)是一种常用的信号分析技术,可以将时信号转换到频,常用于图像压缩。下面是 Python 代码实现 DCT 变换和逆变换,并对图像进行压缩和解压缩的示例: ```python import cv2 import numpy as np def dct(img): # 获取图像大小 h, w = img.shape[:2] # 初始化 DCT 系数矩阵 dct_coef = np.zeros((h, w), dtype=np.float32) # 对图像进行 DCT 变换 for i in range(0, h, 8): for j in range(0, w, 8): dct_coef[i:i+8, j:j+8] = cv2.dct(img[i:i+8, j:j+8]) return dct_coef def idct(dct_coef, compress_rate=1.0): # 获取图像大小 h, w = dct_coef.shape[:2] # 计算保留 DCT 系数的数量 num_remain_coef = int(h * w * compress_rate) # 初始化 DCT 系数矩阵 dct_coef_new = np.zeros((h, w), dtype=np.float32) # 选取保留的 DCT 系数 dct_coef_flat = dct_coef.flatten() idx = np.argsort(-np.abs(dct_coef_flat)) dct_coef_flat = dct_coef_flat[idx] dct_coef_flat[num_remain_coef:] = 0 dct_coef_flat = dct_coef_flat[idx.argsort()] dct_coef_new = dct_coef_flat.reshape((h, w)) # 对 DCT 系数进行 IDCT 逆变换 img = np.zeros((h, w), dtype=np.float32) for i in range(0, h, 8): for j in range(0, w, 8): img[i:i+8, j:j+8] = cv2.idct(dct_coef_new[i:i+8, j:j+8]) # 将图像像素范围从 [0, 255] 转换为 [0, 1] img /= 255 return img # 加载图像 img = cv2.imread('lena.png', 0).astype(np.float32) # 进行 DCT 变换 dct_coef = dct(img) # 对 DCT 系数进行压缩,并进行 IDCT 逆变换 compress_rate = 0.1 img_compress = idct(dct_coef, compress_rate) # 显示压缩后的图像 cv2.imshow('compressed image', img_compress) # 等待按下任意按键退出程序 cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上述代码中,`dct` 函数实现DCT 变换,`idct` 函数实现了对 DCT 系数进行压缩和解压缩。在 `idct` 函数中,我们通过计算保留 DCT 系数的数量,将 DCT 系数进行了压缩,并进行 IDCT 逆变换得到压缩后的图像。`compress_rate` 变量控制了压缩比例,压缩比例越高,保留的 DCT 系数数量越少,压缩后的图像质量越低。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值