引 言 网络上图像在传输过程中为节省内存空间主要采用jpeg格式。jpeg图属于有损压缩图像的一种。在图像篡改检测过程中,可以利用jpeg图像的单双压缩伪影的不同而判别图像为伪造图并可以定位伪造区域。RGB图像变成jpeg图像过程中涉及从RGB图变成YCbCr图像,DCT变换,DCT系数量化过程,和DCT系数反量化,IDCT逆变换过程。本文讲述DCT变化的公式和几种常用代码。
一、DCT变换公式
DCT最常用的变化是 8x8的块变换,变换后的图像与原始图像大小一致。其中每个像素经过变换后变成一个频率值,切割后的一张8x8的图相当于有64个频率值。
二、DCT变换编程
原始图像尺寸的长度和宽度并不一定都是8的倍数,所以图像在进行DCT变换之前,需要对图像进行crop/resize操作,使图像满足长宽都为8的整数倍。将修改后的图像进行DCT变换就会获得相应的DCT系数。
- 方法一
import numpy as np
"""comes from unofficial implementation [F3-Net : Frequency in Face Forgery Network](https://github.com/yyk-wew/F3Net)"""
def DCT_mat(size):
m = [[ (np.sqrt(1./size) if i == 0 else np.sqrt(2./size)) * np.cos((j + 0.5) * np.pi * i / size)
for j in range(size)] for i in range(size)]
return m
def get_dct(block):
coef = np.zeros((block,block)).astype(np.float32)
coef[0:] = np.sqrt(1.0/block)
for i in range(1,block):
for j in range(block):
coef[i,j] = np.sqrt(2.0 /block) * np.cos((2 * j + 1) * np.pi * i / (2.0 * block))
return coef
def dct_transform_1(img):
block = 8
coef = get_dct(block)
# split image to block 8*8
#[h,w] -> [(h/8)*(w/8),8,8]
h,w = img.shape
print('img.shape',img.shape)
input = img.reshape(h//8,8,w//8,8).transpose(0,2,1,3).reshape(-1,8,8)
# output = np.zeros_like(input)
# for i in range(input.shape[0]):
# dct_inter = np.matmul(coef,input[i,:,:])
# output[i,:,:] = np.matmul(dct_inter,coef.transpose(1,0))
dct_inter = np.matmul(coef,input)
output = np.matmul(dct_inter,coef.transpose(1,0))
return output
if __name__ == "__main__":
np.random.seed(20)
image = np.random.randn(16,8)*255
dct_result = dct_transform_1(image)
print(dct_result)
print('*' * 50)
- 方法二
def dct(input):
block = 8
output = np.zeros_like(input)
for u in range(block):
for v in range(block):
if u==0:
alpha = np.sqrt(1.0/block)
else:
alpha = np.sqrt(2.0/block)
if v==0:
beta = np.sqrt(1.0/block)
else:
beta = np.sqrt(2.0/block)
temp = 0.0
for i in range(block):
for j in range(block):
temp += input[i,j]*np.cos((2*i+1)*np.pi*u/(2*block))*np.cos((2*j+1)*np.pi*v/(2*block))
output[u,v] =alpha*beta*temp
return output
def dct_transform_2(img):
block = 8
# split image to block 8*8
#[h,w] ->