图像处理-笔记

Lab-color-space、JPEG和zigzag

Posted by LT on April 26, 2020

Lab颜色空间

  1. 命名
    • Lab色彩空间在1931年国际照明委员会(CIE)制定的颜色度量国际标准的基础上建立起来的。
    • 1976年,经修改后被正式命名为CIELab。
    • 注意,还有一个颜色模型叫做Hunter1948 L,a,b,是由HunterLab公司制作的。虽然和CIE的Lab模型有些关联,但实现不一样。
    • 一般情况说Lab颜色模型,都是指CIE-Lab模型。
  2. 取值范围
    • Lab颜色空间中的L分量用于表示像素的亮度,取值范围是[0,100],表示从纯黑到纯白;
    • a表示从红色到绿色的范围,取值范围是[127,-128];
    • b表示从黄色到蓝色的范围,取值范围是[127,-128]。
  3. 敏感度
    • 人眼对于亮度L敏感,对于色度ab不敏感。

JPEG编码与Zig-Zag扫描

  1. 动机:由于人眼对低频敏感,高频不敏感,所以JPEG压缩,就是适当以损失高频分量为代价,从而减小图像大小。
  2. 这里,频域分量采取的是DCT变换。规律如下。
    • 在DCT之前,先分块,一般是8*8的。
    • 对于一幅图像DCT系数,从左上角到右下角,绝对值由大👉小低频👉高频
  3. 两类JPEG编码信息:DC(直流系数)、AC(交流系数)
    • DC(直流系数):每个8*8子块中的[0,0]元素,代表子块的平均值。JPEG中对F[0,0]单独编码,由于两个相邻的8×8子块的DC系数相差很小,采用差分编码DPCM,可以提高压缩比,也就是说对相邻的子块DC系数的差值进行编码。
    • AC(交流系数):8×8块的其它63个系数。为了保证低频分量先出现,高频分量后出现,63个元素采用了Zig-Zag扫描,并采用游程编码。如下图所示。Z

代码示例:Zig-Zag

  1. 两个函数
     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)
    
  2. 使用
     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)