提示:内容整理自:https://github.com/gzr2017/ImageProcessing100Wen
CV小白从0开始学数字图像处理
40 JPEG 压缩——第四步:YCbCr+离散余弦变换+量化
将图像转为 YCbCr 色彩空间之后,进行 离散余弦变换再对 Y 用 Q1 量化矩阵量化,Cb 和 Cr 用 Q2 量化矩阵量化。最后通过离散余弦逆变换对图像复原。还需比较图像的容量。
这是实际生活中使用的减少 JPEG 数据量的方法,Q1 和 Q2 根据 JPEG 规范由以下等式定义:
Q1 = 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)), dtype=np.float32)
Q2 = np.array(((17, 18, 24, 47, 99, 99, 99, 99),
(18, 21, 26, 66, 99, 99, 99, 99),
(24, 26, 56, 99, 99, 99, 99, 99),
(47, 66, 99, 99, 99, 99, 99, 99),
(99, 99, 99, 99, 99, 99, 99, 99),
(99, 99, 99, 99, 99, 99, 99, 99),
(99, 99, 99, 99, 99, 99, 99, 99),
(99, 99, 99, 99, 99, 99, 99, 99)), dtype=np.float32)
代码如下:
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.RGB > YCbCr
Y = 0.2990 * img[..., 2] + 0.5870 * img[..., 1] + 0.1140 * img[..., 0]
Cb = -0.1687 * img[..., 2] - 0.3313 * img[..., 1] + 0.5 * img[..., 0] + 128.
Cr = 0.5 * img[..., 2] - 0.4187 * img[..., 1] - 0.0813 * img[..., 0] + 128.
YCC = np.zeros_like(img, dtype=np.float32)
YCC[..., 0] = Y
YCC[..., 1] = Cb
YCC[..., 2] = Cr
4.DCT
T = 8
K = 8
X = np.zeros((H, W, C), dtype=np.float64)
Q1 = 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)), dtype=np.float32)
Q2 = np.array(((17, 18, 24, 47, 99, 99, 99, 99),
(18, 21, 26, 66, 99, 99, 99, 99),
(24, 26, 56, 99, 99, 99, 99, 99),
(47, 66, 99, 99, 99, 99, 99, 99),
(99, 99, 99, 99, 99, 99, 99, 99),
(99, 99, 99, 99, 99, 99, 99, 99),
(99, 99, 99, 99, 99, 99, 99, 99),
(99, 99, 99, 99, 99, 99, 99, 99)), dtype=np.float32)
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):
for c in range(C):
X[v+yi, u+xi, c] += YCC[y+yi, x+xi, c] * w(x,y,u,v)
X[yi:yi+T, xi:xi+T, 0] = np.round(X[yi:yi+T, xi:xi+T, 0] / Q1) * Q1
X[yi:yi+T, xi:xi+T, 1] = np.round(X[yi:yi+T, xi:xi+T, 1] / Q2) * Q2
X[yi:yi+T, xi:xi+T, 2] = np.round(X[yi:yi+T, xi:xi+T, 2] / Q2) * Q2
5.IDCT
IYCC = np.zeros((H, W, 3), dtype=np.float64)
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):
IYCC[y+yi, x+xi] += X[v+yi, u+xi] * w(x,y,u,v)
6.IDCT
IYCC = np.zeros((H, W, 3), dtype=np.float64)
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):
IYCC[y+yi, x+xi] += X[v+yi, u+xi] * w(x,y,u,v)
7.YCbCr > RGB
out = np.zeros_like(img, dtype=np.float32)
out[..., 2] = IYCC[..., 0] + (IYCC[..., 2] - 128.) * 1.4020
out[..., 1] = IYCC[..., 0] - (IYCC[..., 1] - 128.) * 0.3441 - (IYCC[..., 2] - 128.) * 0.7139
out[..., 0] = IYCC[..., 0] + (IYCC[..., 1] - 128.) * 1.7718
out[out>255] = 255
out = out.astype(np.uint8)
8.MSE
v_max = 255.
mse = np.sum(np.power(np.abs(img.astype(np.float32) - out.astype(np.float32)), 2)) / (H * W * C)
psnr = 10 * np.log10(v_max ** 2 / mse)
print("PSNR >>", psnr)
bitrate = 1. * T * K ** 2 / (T ** 2)
print("bitrate >>", bitrate)
9.保存结果
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)