提示:内容整理自:https://github.com/gzr2017/ImageProcessing100Wen
CV小白从0开始学数字图像处理
36 JPEG 压缩——第一步:离散余弦变换(Discrete Cosine Transformation)
imori.jpg
灰度化之后,先进行离散余弦变换,再进行离散余弦逆变
离散余弦变换(Discrete Cosine Transformation)是一种使用下面式子计算的频率变换:
T = 8
F(u,v) = 1 / T * C(u)C(v) * Sum_{y=0:T-1} Sum_{x=0:T-1} f(x,y) cos((2x+1)u*pi/2T) cos((2y+1)v*pi/2T)
离散余弦逆变换(Inverse Discrete Cosine Transformation)是离散余弦变换的逆变换,使用下式定义:
f(x,y) = 1 / T * C(x)C(y) * Sum_{u=0:T-1} Sum_{v=0:T-1} F(u,v) cos((2x+1)u*pi/2T) cos((2y+1)v*pi/2T)
在这里我们先将图像分割成8x 8的小块,在各个小块中使用离散余弦变换编码,使用离散余弦逆变换解码,这就是 JPEG 的互逆过程。现在我们也同样地,把图像分割成8x 8的小块,然后进行离散余弦变换和离散余弦逆变换。
代码如下:
1.引入库
CV2计算机视觉库
import cv2
import numpy as np
import matplotlib.pyplot as plt
2.读入数据
img = cv2.imread("imori.jpg").astype(np.float32)
H, W, C = img.shape
3.灰度化
gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
4.DCT
T = 8
K = 8
X = np.zeros((H, W), dtype=np.float32)
#indx = np.tile(np.arange(T), (T, 1))
#indy = np.arange(T).repeat(T).reshape(T, -1)
#dct = np.ones_like(indx, dtype=np.float32)
#dct[:, 0] /= np.sqrt(2)
#dct[0] /= np.sqrt(2)
def w(x, y, u, v):
cu = 1.
cv = 1.
if u == 0:
cu /= np.sqrt(2)
if v == 0:
cv /= np.sqrt(2)
theta = np.pi / (2 * T)
return (( 2 * cu * cv / T) * np.cos((2*x+1)*u*theta) * np.cos((2*y+1)*v*theta))
for yi in range(0, H, T):
for xi in range(0, W, T):
for v in range(T):
for u in range(T):
for y in range(T):
for x in range(T):
X[v+yi, u+xi] += gray[y+yi, x+xi] * w(x,y,u,v)
"""
_x = indx + xi * T
_y = indy + yi * T
_u = u + xi * T
_v = v + yi * T
X[_v, _u] = np.sum(C * gray[_y, _x] * np.cos((2*indx+1)*u*np.pi/(2*T)) * np.cos((2*indy+1)*v*np.pi/(2*T)))
"""
5.IDCT
out = np.zeros((H, W), dtype=np.float32)
for yi in range(0, H, T):
for xi in range(0, W, T):
for y in range(T):
for x in range(T):
for v in range(K):
for u in range(K):
out[y+yi, x+xi] += X[v+yi, u+xi] * w(x,y,u,v)
"""
_u = indx + xi * T
_v = indy + yi * T
_x = x + yi * T
_y = y + xi * T
out[_y, _x] = np.sum(C * X[_v, _u] * np.cos((2*x+1)*indx*np.pi/(2*T)) * np.cos((2*y+1)*indy*np.pi/(2*T))) * 4. / (T ** 2)
"""
out[out>255] = 255
out = np.round(out).astype(np.uint8)
6.保存结果
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)