1.简介
离散余弦变换(Discrete Cosine Transform),简称DCT变换,能够将空域的信号转换到频域上,在这个专题中就是将二维的像素值转换为二维的频率信号。
2.公式
2.1 二维离散余弦变换(2D DCT):
给定一个N×M(通常M等于N N表示水平长度)的输入矩阵F,其离散余弦变换结果G可通过以下公式计算得出:
其中,
为原始图像中像素点\((x,y)\)处的灰度值;
为变换后系数矩阵中的元素,表示不同频率分量的权值;
为正交归一化系数,
当
时,
,否则
。
二维离散余弦逆变换(IDCT)的公式:
这些公式描述了二维离散余弦变换和逆变换的原理,用于将输入图像从空域转换到频域,并通过调整系数来实现信号的压缩或特征提取。在实际应用中,可以使用相应的库函数或算法来进行离散余弦变换和逆变换操作。
2.2 公式解读
2.3公式使用
由于cos函数的精度问题,使用上述公式进行正变换和逆变换得不到原来的矩阵,相关转换代码会附在文末。所以采用矩阵的方法对其进行转换。相关数学原理不在说明。
以此方式在进行idct变换。
以此方式进行dct逆变换。
3.直观展示变化
初始8*8矩阵如下(表示图片的像素值):
进行dct变换 得到频域信号 再进行dct逆变换得到原始图像想信号,发现并没有多大损失。
4.频域数字意义
所有的8*8的黑白图可以看做这64个基本余弦波构成的色块进行的叠加, 每个块的上频率是确定的,对应的数字表示其影响。可以类比傅里叶变换每个频率前对应的振幅,相应的越大表示影响越大,保留低频的信号就可以保留图片的主体信息。
参考视频:【jpeg-dct】https://www.bilibili.com/video/BV17v411p7gV?vd_source=53f17186c8480e141f43fa1db7910b6c
5.代码分享
DCT变换与IDCT变换
import numpy as np
def dct(matrix):
N = matrix.shape[0]
M = matrix.shape[1]
# 构造系数矩阵
C = np.ones((N, M))
for i in range(0, N):
C[i, 0] = 1 / np.sqrt(N)
for j in range(1, M):
for i in range(0, N):
C[i, j] = np.sqrt(2 / N) * np.cos((np.pi / N) * (i + 0.5) * j)
# 计算 DCT 变换
dct_data = np.dot(np.dot(C, matrix), np.transpose(C))
return np.around(dct_data, 0)
def idct(dct_data):
N = dct_data.shape[0]
M = dct_data.shape[1]
# 构造系数矩阵
C = np.ones((N, M))
for i in range(0, N):
C[i, 0] = 1 / np.sqrt(N)
for j in range(1, M):
for i in range(0, N):
C[i, j] = np.sqrt(2 / N) * np.cos((np.pi / N) * (i + 0.5) * j)
# 计算逆变换
idct_data = np.dot(np.dot(np.transpose(C), dct_data), C)
return np.around(idct_data,0)
量化与反量化(JPEG压缩是使用,与DCT变化无关)
def quantify(dct_data):
N = dct_data.shape[0]
M = dct_data.shape[1]
quantify_data =np.zeros(dct_data.shape)
quantization_matrix = np.array([[16, 11, 10, 16, 24, 40, 51, 61],
[12, 12, 14, 19, 26, 58, 60, 55],
[14, 13, 16, 24, 40, 57, 69, 56],
[14, 17, 22, 29, 51, 87, 80, 62],
[18, 22, 37, 56, 68, 109, 103, 77],
[24, 35, 55, 64, 81, 104, 113, 92],
[49, 64, 78, 87, 103, 121, 120, 101],
[72, 92, 95, 98, 112, 100, 103, 99]])
for j in range(0, M):
for i in range(0, N):
quantify_data[i][j]=dct_data[i][j]//quantization_matrix[i][j]
return quantify_data
def i_quantify(dct_data):
N = dct_data.shape[0]
M = dct_data.shape[1]
quantify_data = np.zeros(dct_data.shape)
quantization_matrix = np.array([[16, 11, 10, 16, 24, 40, 51, 61],
[12, 12, 14, 19, 26, 58, 60, 55],
[14, 13, 16, 24, 40, 57, 69, 56],
[14, 17, 22, 29, 51, 87, 80, 62],
[18, 22, 37, 56, 68, 109, 103, 77],
[24, 35, 55, 64, 81, 104, 113, 92],
[49, 64, 78, 87, 103, 121, 120, 101],
[72, 92, 95, 98, 112, 100, 103, 99]])
for j in range(0, M):
for i in range(0, N):
quantify_data[i][j] = dct_data[i][j] * quantization_matrix[i][j]
return quantify_data
滤波函数(可以选择性的过滤到高频滤波)
def fittler(dct_data):
N = dct_data.shape[0]
M = dct_data.shape[1]
for i in range(0, N):
for j in range(M-i, M):
if abs(dct_data[i][j]) <= 1:
dct_data[i][j] = 0
return dct_data
通过python中的列表切片操作,完成分块的DCT变换与逆变换
import cv2 as cv
# img = cv.imread(r"D:\py_code\2023_10\1.jpg",cv.IMREAD_GRAYSCALE)
img = np.array([[-76, -73, -67, -62, -58, -67, -64, -55],
[-65, -69, -73, -38, -19, -43, -59, -56],
[-66, -69, -60, -15, 16, -24, -62, -55],
[-65, -70, -57, -6, 26, -22, -58, -59],
[-61, -67, -60, -24, -2, -40, -60, -58],
[-49, -63, -68, -58, -51, -60, -70, -53],
[-43, -57, -64, -69, -73, -67, -63, -45],
[-41, -49, -59, -60, -63, -52, -50, -34]])
size = 8
print(img.shape)
print(img)
dct_data = np.zeros(img.shape)
img_dct = np.zeros(img.shape)
for i in range(img.shape[0]//size):
for j in range(img.shape[1]//size):
sub_dct_data = dct(img[i*size:(i+1)*size,j*size:(j+1)*size])
sub_dct_data = fittler(sub_dct_data)
for u in range(size):
for v in range(size):
dct_data[i*size+u][j*size+v]=sub_dct_data[u][v]
print(dct_data)
for i in range(img.shape[0]//size):
for j in range(img.shape[1]//size):
sub_idct_data = idct(dct_data[i*size:(i+1)*size,j*size:(j+1)*size])
for u in range(size):
for v in range(size):
img_dct[i*size+u][j*size+v]=sub_idct_data[u][v]
print(img_dct)
总体代码 文件为黑白lina图
import numpy as np
def dct(matrix):
N = matrix.shape[0]
M = matrix.shape[1]
# 构造系数矩阵
C = np.ones((N, M))
for i in range(0, N):
C[i, 0] = 1 / np.sqrt(N)
for j in range(1, M):
for i in range(0, N):
C[i, j] = np.sqrt(2 / N) * np.cos((np.pi / N) * (i + 0.5) * j)
# 计算 DCT 变换
dct_data = np.dot(np.dot(C, matrix), np.transpose(C))
return np.around(dct_data, 0)
def idct(dct_data):
N = dct_data.shape[0]
M = dct_data.shape[1]
# 构造系数矩阵
C = np.ones((N, M))
for i in range(0, N):
C[i, 0] = 1 / np.sqrt(N)
for j in range(1, M):
for i in range(0, N):
C[i, j] = np.sqrt(2 / N) * np.cos((np.pi / N) * (i + 0.5) * j)
# 计算逆变换
idct_data = np.dot(np.dot(np.transpose(C), dct_data), C)
return np.around(idct_data,0)
def quantify(dct_data):
N = dct_data.shape[0]
M = dct_data.shape[1]
quantify_data =np.zeros(dct_data.shape)
quantization_matrix = np.array([[16, 11, 10, 16, 24, 40, 51, 61],
[12, 12, 14, 19, 26, 58, 60, 55],
[14, 13, 16, 24, 40, 57, 69, 56],
[14, 17, 22, 29, 51, 87, 80, 62],
[18, 22, 37, 56, 68, 109, 103, 77],
[24, 35, 55, 64, 81, 104, 113, 92],
[49, 64, 78, 87, 103, 121, 120, 101],
[72, 92, 95, 98, 112, 100, 103, 99]])
for j in range(0, M):
for i in range(0, N):
quantify_data[i][j]=dct_data[i][j]//quantization_matrix[i][j]
return quantify_data
def i_quantify(dct_data):
N = dct_data.shape[0]
M = dct_data.shape[1]
quantify_data = np.zeros(dct_data.shape)
quantization_matrix = np.array([[16, 11, 10, 16, 24, 40, 51, 61],
[12, 12, 14, 19, 26, 58, 60, 55],
[14, 13, 16, 24, 40, 57, 69, 56],
[14, 17, 22, 29, 51, 87, 80, 62],
[18, 22, 37, 56, 68, 109, 103, 77],
[24, 35, 55, 64, 81, 104, 113, 92],
[49, 64, 78, 87, 103, 121, 120, 101],
[72, 92, 95, 98, 112, 100, 103, 99]])
for j in range(0, M):
for i in range(0, N):
quantify_data[i][j] = dct_data[i][j] * quantization_matrix[i][j]
return quantify_data
def fittler(dct_data):
N = dct_data.shape[0]
M = dct_data.shape[1]
for i in range(0, N):
for j in range(M-i, M):
if abs(dct_data[i][j]) <= 1:
dct_data[i][j] = 0
return dct_data
import cv2 as cv
# img = cv.imread(r"D:\py_code\2023_10\1.jpg",cv.IMREAD_GRAYSCALE)
img = np.array([[-76, -73, -67, -62, -58, -67, -64, -55],
[-65, -69, -73, -38, -19, -43, -59, -56],
[-66, -69, -60, -15, 16, -24, -62, -55],
[-65, -70, -57, -6, 26, -22, -58, -59],
[-61, -67, -60, -24, -2, -40, -60, -58],
[-49, -63, -68, -58, -51, -60, -70, -53],
[-43, -57, -64, -69, -73, -67, -63, -45],
[-41, -49, -59, -60, -63, -52, -50, -34]])
size = 8
print(img.shape)
print(img)
dct_data = np.zeros(img.shape)
img_dct = np.zeros(img.shape)
for i in range(img.shape[0]//size):
for j in range(img.shape[1]//size):
sub_dct_data = dct(img[i*size:(i+1)*size,j*size:(j+1)*size])
sub_dct_data = fittler(sub_dct_data)
for u in range(size):
for v in range(size):
dct_data[i*size+u][j*size+v]=sub_dct_data[u][v]
print(dct_data)
for i in range(img.shape[0]//size):
for j in range(img.shape[1]//size):
sub_idct_data = idct(dct_data[i*size:(i+1)*size,j*size:(j+1)*size])
for u in range(size):
for v in range(size):
img_dct[i*size+u][j*size+v]=sub_idct_data[u][v]
print(img_dct)
cv.imwrite("6.jpg",img_dct)
通过滤波器过滤掉一些高频细节,完成对图片的压缩
6.基于DCT变换的信息隐藏的原理
DCT变换矩阵前后,中间过滤掉高频信号,对图片质量的影响很小,我们通过更改高频信号区的系数完成信息隐藏。