引 言 网络上图像在传输过程中为节省内存空间主要采用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] -> [(h/8)*(w/8),8,8]
h,w = 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]):
output[i,:,:] = dct(input[i,:,:])
return output
if __name__ == "__main__":
np.random.seed(20)
image = np.random.randn(16,8)*255
dct_result2 = dct_transform_2(image)
print(dct_result2)
print('*' * 50)
- 方法三
import itertools
def dct_transform_3(img):
h,w = img.shape
input = img.reshape(h//8,8,w//8,8).transpose(0,2,1,3).reshape(-1,8,8)
tensor = np.zeros((8, 8, 8, 8), dtype=np.float32)
for x, y, u, v in itertools.product(range(8), repeat=4):
tensor[x, y, u, v] = np.cos((2 * x + 1) * u * np.pi / 16) * np.cos(
(2 * y + 1) * v * np.pi / 16)
alpha = np.array([1. / np.sqrt(2)] + [1] * 7)
scale = np.outer(alpha, alpha) * 0.25
output = scale * np.tensordot(input, tensor, axes=2)
return output
if __name__ == "__main__":
np.random.seed(20)
image = np.random.randn(16,8)*255
dct_result3 = dct_transform_3(image)
print(dct_result3)
print('*' * 50)
调用以下两句发现三个程序的运行结果相同。
print(np.round(dct_result,decimals=3) == np.round(dct_result2,decimals=3))
print(np.round(dct_result,decimals=3) == np.round(dct_result3,decimals=3))
- 方法四
此外,可以调用cv2.dct()函数进行系数的dct变换。
三、图像同频率系数抽取
图像经过DCT处理后,想要获得每个频率段的系数值。就需要使用上文在DCT变换过程中用到的图像变形转置操作。
为更合理的验证提取系数代码的准确性,我们构建一张16x16的图片,其中像素值相同数据间隔8个数,用于表示同频率。构建图像过程
import torch
a = torch.arange(64).view(8,8)
b = torch.cat((a,a),dim=1)
data = torch.cat((b,b),dim=0)
print(data)
图像数据显示
tensor([[ 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22, 23, 16, 17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30, 31, 24, 25, 26, 27, 28, 29, 30, 31],
[32, 33, 34, 35, 36, 37, 38, 39, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 40, 41, 42, 43, 44, 45, 46, 47],
[48, 49, 50, 51, 52, 53, 54, 55, 48, 49, 50, 51, 52, 53, 54, 55],
[56, 57, 58, 59, 60, 61, 62, 63, 56, 57, 58, 59, 60, 61, 62, 63],
[ 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22, 23, 16, 17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30, 31, 24, 25, 26, 27, 28, 29, 30, 31],
[32, 33, 34, 35, 36, 37, 38, 39, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 40, 41, 42, 43, 44, 45, 46, 47],
[48, 49, 50, 51, 52, 53, 54, 55, 48, 49, 50, 51, 52, 53, 54, 55],
[56, 57, 58, 59, 60, 61, 62, 63, 56, 57, 58, 59, 60, 61, 62, 63]])
- 获取同频率频率数据方法一
out = data.view(2,8,2,8).permute(1,3,0,2).contiguous().view(64,4)
print(out)
- 获取同频率频率数据方法二
out = torch.stack(torch.stack(torch.split(data,8,dim=0),dim=0).split(8,dim=-1),dim=2)
out = out.permute(1,3,0,2).reshape(64,4)
torch.split()函数中的参数split_size指的是每块大小,而不是切分成多少块,正好与torch.chunk()函数相反。
实验结果:
tensor([[ 0, 0, 0, 0],
[ 1, 1, 1, 1],
[ 2, 2, 2, 2],
[ 3, 3, 3, 3],
[ 4, 4, 4, 4],
[ 5, 5, 5, 5],
[ 6, 6, 6, 6],
[ 7, 7, 7, 7],
[ 8, 8, 8, 8],
[ 9, 9, 9, 9],
[10, 10, 10, 10],
[11, 11, 11, 11],
[12, 12, 12, 12],
[13, 13, 13, 13],
[14, 14, 14, 14],
[15, 15, 15, 15],
[16, 16, 16, 16],
[17, 17, 17, 17],
[18, 18, 18, 18],
[19, 19, 19, 19],
[20, 20, 20, 20],
[21, 21, 21, 21],
[22, 22, 22, 22],
[23, 23, 23, 23],
[24, 24, 24, 24],
[25, 25, 25, 25],
[26, 26, 26, 26],
[27, 27, 27, 27],
[28, 28, 28, 28],
[29, 29, 29, 29],
[30, 30, 30, 30],
[31, 31, 31, 31],
[32, 32, 32, 32],
[33, 33, 33, 33],
[34, 34, 34, 34],
[35, 35, 35, 35],
[36, 36, 36, 36],
[37, 37, 37, 37],
[38, 38, 38, 38],
[39, 39, 39, 39],
[40, 40, 40, 40],
[41, 41, 41, 41],
[42, 42, 42, 42],
[43, 43, 43, 43],
[44, 44, 44, 44],
[45, 45, 45, 45],
[46, 46, 46, 46],
[47, 47, 47, 47],
[48, 48, 48, 48],
[49, 49, 49, 49],
[50, 50, 50, 50],
[51, 51, 51, 51],
[52, 52, 52, 52],
[53, 53, 53, 53],
[54, 54, 54, 54],
[55, 55, 55, 55],
[56, 56, 56, 56],
[57, 57, 57, 57],
[58, 58, 58, 58],
[59, 59, 59, 59],
[60, 60, 60, 60],
[61, 61, 61, 61],
[62, 62, 62, 62],
[63, 63, 63, 63]])
四、总结
本文只是描述了将YCbCr图像变成DCT系数矩阵的过程,对于传统RGB图变成YCbCr图像过程的代码没有介绍。请浏览者自己查阅资料。如果本代码对于你有所帮助请记得点赞收藏呦😊
3561

被折叠的 条评论
为什么被折叠?



