Lab颜色空间
- 命名
- Lab色彩空间在1931年国际照明委员会(CIE)制定的颜色度量国际标准的基础上建立起来的。
- 1976年,经修改后被正式命名为CIELab。
- 注意,还有一个颜色模型叫做Hunter1948 L,a,b,是由HunterLab公司制作的。虽然和CIE的Lab模型有些关联,但实现不一样。
- 一般情况说Lab颜色模型,都是指CIE-Lab模型。
- 取值范围
- Lab颜色空间中的L分量用于表示像素的亮度,取值范围是[0,100],表示从纯黑到纯白;
- a表示从红色到绿色的范围,取值范围是[127,-128];
- b表示从黄色到蓝色的范围,取值范围是[127,-128]。
- 敏感度
- 人眼对于亮度L敏感,对于色度ab不敏感。
JPEG编码与Zig-Zag扫描
- 动机:由于人眼对低频敏感,高频不敏感,所以JPEG压缩,就是适当以损失高频分量为代价,从而减小图像大小。
- 这里,频域分量采取的是DCT变换。规律如下。
- 在DCT之前,先分块,一般是8*8的。
- 对于一幅图像DCT系数,从左上角到右下角,绝对值由
大👉小
,低频👉高频
。
- 两类JPEG编码信息:DC(直流系数)、AC(交流系数)
- DC(直流系数):每个8*8子块中的[0,0]元素,代表子块的平均值。JPEG中对F[0,0]单独编码,由于两个相邻的8×8子块的DC系数相差很小,采用差分编码DPCM,可以提高压缩比,也就是说对相邻的子块DC系数的差值进行编码。
- AC(交流系数):8×8块的其它63个系数。为了保证低频分量先出现,高频分量后出现,63个元素采用了Zig-Zag扫描,并采用游程编码。如下图所示。
代码示例:Zig-Zag
- 两个函数
def zigzag(dct_coef, one_dim_dct, action): n = dct_coef.shape[0] k = 0 for i in range(1,n+1): for j in range(1,i+1): if i % 2 == 0: if action=='init': one_dim_dct[k] = dct_coef[j -1][i+1-j -1] if action=='modify': dct_coef[j -1][i+1-j -1] = one_dim_dct[k] else: if action=='init': one_dim_dct[k] = dct_coef[i+1-j -1][j -1] if action=='modify': dct_coef[i+1-j -1][j -1] = one_dim_dct[k] k = k + 1 for i in range(1, n): for j in range(1, n - i+1): if i % 2 == 0: if action=='init': one_dim_dct[k] = dct_coef[n-j+1 -1][i + j -1] if action=='modify': dct_coef[n-j+1 -1][i + j -1] = one_dim_dct[k] else: if action=='init': one_dim_dct[k] = dct_coef[i + j -1][n-j+1 -1] if action=='modify': dct_coef[i + j -1][n-j+1 -1] = one_dim_dct[k] k = k + 1 return dct_coef, one_dim_dct def blk_triangle_replace_HighDCT(gray_img, x_64_8_sample): height, width, size_y, size_x, channels = 8,8, 8,8,1 recon_img_complete = np.zeros((height * size_y, width * size_x)) for i in range(gray_img.shape[0]//8): for j in range(gray_img.shape[0] // 8): blk_img = gray_img[i*8: (i+1)*8, j*8: (j+1)*8] blk_dct = cv2.dct(blk_img) init_one_dim_dct = np.random.randint(0, 1, size=(8*8)).astype(np.float32) _, one_dim_dct = zigzag(blk_dct, init_one_dim_dct, 'init') # 修改了右下角(三角形,面积占1/8)之后的DCT矩阵 one_dim_dct[np.prod(blk_dct.shape) // 8 * 7:] = x_64_8_sample[8*i+j] blk_dct, _ = zigzag(blk_dct, one_dim_dct, 'modify') recon_img = cv2.idct(blk_dct) recon_img_complete[i * height:(i + 1) * height, j*height:(j + 1) * height] = recon_img return recon_img_complete.astype(np.uint8)
- 使用
def plot_images(args, x_sample, dir, file_name, size_x=10, size_y=10): folder = '../{}/train_64x64/images0/'.format(args.img_folder) val_namelist = os.listdir(folder) val_namelist = val_namelist[len(val_namelist) //5*4: ] random.shuffle(val_namelist) print(x_sample.shape) batch, channels, height, width = x_sample.shape[0], x_sample.shape[1], x_sample.shape[2], 8*x_sample.shape[3] mosaic = np.zeros((height * size_y, width * size_x, channels)) # 用生成的高频DCT(下三角)替换原图(从val中随机选择)的DCT,再iDCT for j in range(size_y): for i in range(size_x): idx = j * size_x + i gray_img = cv2.imread(folder+val_namelist[idx]).transpose(2, 0, 1).astype(np.float32)[0] image = blk_triangle_replace_HighDCT(gray_img, x_sample[idx].squeeze()) mosaic[j*height:(j+1)*height, i*height:(i+1)*height] = torch.tensor(image).unsqueeze(dim=2).numpy() # Remove channel for BW images mosaic = mosaic.squeeze() cv2.imwrite(dir + file_name + '.png', mosaic)