颜色查找表LUT

查找表(LUT,LookUp Table)是图像颜色转换的强大工具,在许多图形和视频编辑器中使用。

2D LUT

CLUT-from-images

2D LUT生成

def generate_identify_color_matrix(width, height, channel):
    img = np.zeros((width, height, channels), dtype=np.uint8)
    for by in range(8):
        for bx in range(8):
            for g in range(64):
                for r in range(64):
                    x = r + bx * 64
                    y = g + by * 64
                    img[y][x][0] = int(r * 255.0 / 63.0 + 0.5)
                    img[y][x][1] = int(g * 255.0 / 63.0 + 0.5)
                    img[y][x][2] = int((bx + by * 8.0) * 255.0 / 63.0 + 0.5)
    return img
 identity_lut = generate_identify_color_matrix()

在这里插入图片描述

2D LUT 用于图像转换

from typing import Tuple
from functools import lru_cache
from math import floor
import numpy as np
import cv2

def lut_apply(image, lut):
    img_list = image.tolist()
    # dst_img = image.copy()
    dst_img = np.zeros((image.shape[0], image.shape[1], image.shape[2]), dtype=np.uint8)
    for iy in range(image.shape[0]):
        for ix in range(image.shape[1]):
            b, g, r = img_list[iy][ix] #bgr mode
            x, y, bx, by = color_coordinate(r, g, b)
            lut_y = y + by * 64
            lut_x = x + bx * 64
            dst_img[iy][ix][0] = lut[lut_y][lut_x][0]
            dst_img[iy][ix][1] = lut[lut_y][lut_x][1]
            dst_img[iy][ix][2] = lut[lut_y][lut_x][2]
    return dst_img
@lru_cache(maxsize=512)
def color_coordinate(r, g, b) -> Tuple[int, int, int, int]:
    x, y, bx, by = 0, 0, 0, 0
    x = floor(r / 4.0)
    y = floor(g / 4.0)
    bx, by = blue_coordinate(floor(b / 4.0))
    return x, y, bx, by


@lru_cache(maxsize=64)
def blue_coordinate(b: int) -> Tuple[int, int]:
    assert b >= 0 and b <= 63, 'GOT {}'.format(b)
    x, y = 0, 0
    y = floor(floor(b) / 8.0)
    x = int(floor(b) - y * 8.0)
    return x, y
    
image = cv2.imread('./test.jpg')
lut = cv2.imread('./YV2.JPG')
result_img = lut_apply(image, lut)
cv2.imwrite('./test_YV2_cv.jpg', result_img)
快速方法:
class LUT_WHITEN:
    def __init__(self, lut):
        cube64rows = 8
        cube64size = 64
        cube256size = 256
        cubescale = (int)(cube256size / cube64size) #4

        reshapelut = np.zeros((cube256size, cube256size, cube256size, 3))
        for i in range(cube64size):
            tmp = math.floor(i / cube64rows)
            cx = int((i - tmp * cube64rows) * cube64size)
            cy = int(tmp * cube64size)
            cube64 = lut[cy:cy+cube64size, cx:cx+cube64size]#cube64 in lut(512*512 (512=8*64))
            _rows, _cols, _ = cube64.shape
            if _rows == 0 or _cols == 0:
                continue
            cube256 = cv2.resize(cube64, (cube256size, cube256size))
            i = i * cubescale
            for k in range(cubescale):
                reshapelut[i + k] = cube256
        self.lut = reshapelut
        # print('reshapelut shape:', reshapelut.shape)

    def imageInLut(self, src):
        arr = src.copy()
        bs = arr[:, :, 0]
        gs = arr[:, :, 1]
        rs = arr[:, :, 2]
        arr[:, :] = self.lut[bs, gs, rs]
        return arr

3D LUT

3D LUT的常见格式:

  • Hald CLUT(.png)
  • 3D LUT(.3dl)
  • Cube LUT(.cube)

3D LUT的生成(Hald CLUT)

color-filters-reconstruction

  • 创建identity image(3D LUT)

    ./bin/generate.py
    
    def generate_hald(size):
        b, g, r = numpy.mgrid[
            0 : 255 : size**2*1j,
            0 : 255 : size**2*1j,
            0 : 255 : size**2*1j
        ].astype(numpy.uint8)
    
        rgb = numpy.stack((r, g, b), axis=-1)
        return Image.fromarray(rgb.reshape(size**3, size**3, 3))
    

    为了防止在变换期间可能发生的失真、,如渐晕、划痕、渐变和JPEG伪影。生成的 25 × 25 × 25 25 \times 25 \times 25 25×25×25d的hadl image如下所示(显示了4个):
    25x25x25 look up table

  • 使用图像处理软件对hald image图像进行变换处理,得到同样尺寸的filtered hald image。
    在这里插入图片描述

  • 改进方法,用高斯模糊filtered image进行处理减少噪声。
    如果目标滤波器在局部水平上有严重的失真或图像中心有显著的梯度,则可能出现一些不期望的效果。有问题滤波图像如下所示:
    在这里插入图片描述

     ./bin/convert.py raw/15.Hudson.jpg halds/ --smooth 1.5
    
  • 将滤波后的图像转换为真实的hald image(显示的4个中裁剪了一个)。
    在这里插入图片描述

3D LUT(Hald CLUT)应用于图像(Pillow库)

pillow-lut-tools
Pillow LUT tools
Pillow LUT工具包含用于加载、操作和生成三维查找表的工具,是专为Pillow库设计的。

from PIL import Image
from pillow_lut import load_hald_image

hefe = load_hald_image('./res/test_hald.5.png')
img = Image.open('./res/test.jpg')
img.filter(hefe).save('./res/test.hald.jpg')

Pillow LUT中包含的函数:

  • load_cube_file从.cube文件格式加载三维查找表
    在这里插入图片描述

  • load_hald_image从Hald图像(通常是.png或.tiff文件)加载三维查找表。
    在这里插入图片描述

  • identity_table返回具有线性分布值的noop查找表。
    在这里插入图片描述

  • rgb_color_enhance根据基本颜色设置的给定值生成三维颜色查找表。
    在这里插入图片描述

  • sample_lut_linear使用线性插值从给定的三维查找表计算新的点值。
    在这里插入图片描述

  • sample_lut_cubic使用三次插值从给定的三维查找表计算新的点值。
    在这里插入图片描述

  • resize_lut使用插值将给定的查找表调整为新大小。
    在这里插入图片描述

  • transform_lut使用另一个表转换给定的查找表并返回结果。
    在这里插入图片描述

  • amplity_lut放大给定的查找表
    在这里插入图片描述

Pillow LUT函数的使用例子:

from PIL import Image
from pillow_lut import load_hald_image

hefe = load_hald_image('./res/hald.6.hefe.png')
im = Image.open('./res/pineapple.jpeg')
im.filter(hefe).save('./res/pineapple.hefe.jpeg')

在这里插入图片描述

from pillow_lut import rgb_color_enhance

lut = rgb_color_enhance(11, exposure=0.2, contrast=0.1, vibrance=0.5, gamma=1.3)
im = Image.open('./res/pineapple.jpeg')
im.filter(lut).save('./res/pineapple.enhance.jpeg')

在这里插入图片描述

from pillow_lut import load_hald_image, rgb_color_enhance

hefe = load_hald_image('./res/hald.6.hefe.png')
lut = rgb_color_enhance(hefe, exposure=0.2, contrast=0.1, vibrance=0.5, gamma=1.3)
im = Image.open('./res/pineapple.jpeg')
im.filter(lut).save('./res/pineapple.hefe.enhance.jpeg')

在这里插入图片描述

3D LUT(Hald CLUT )转换为2D square CLUT

import numpy, cv2

hald = cv2.imread('1.Clarendon.png')

size = int(hald.shape[0] ** (1.0/3.0) + .5)
clut = numpy.concatenate([
    numpy.concatenate(im.reshape((size, size, size**2, size**2, 3))[row], axis=1)
    for row in range(size)
])

cv2.imwrite("clut.png", clut)

2D LUT和3D LUT之间相互转换

单通道转换示意图,便于理解,3D LUT转 2D LUT容易出错的地方已标红。
在这里插入图片描述

2D LUT到3D LUT的转换

# 2D LUT(size**3, size**3, 3) ->  3D LUT(size**3, size**3, 3)
clut = cv2.imread('./identity_clut_8.png')
size = int(clut.shape[0] ** (1.0 / 3.0) + 0.5)
clut_result = np.zeros((size ** 2, size ** 2, size ** 2, 3))
for i in range(size ** 2):
    tmp1 = math.floor(i / size)
    cx = int((i - tmp1 * size) * size ** 2)
    cy = int(tmp1 * size ** 2)
    clut_result[i] = clut[cy: cy + size ** 2, cx : cx + size ** 2]

hald = clut_result.reshape((size ** 3, size ** 3, 3))

cv2.imwrite('./identity_hald_{}_test.png'.format(size), hald)

3D LUT到2D LUT的转换

#3D LUT(size**3, size**3, 3) ->  2D LUT(size**3, size**3, 3)
hald = cv2.imread('./identity_hald_8.png')

size = int(hald.shape[0] ** (1.0/3.0) + .5)
#method1
clut = np.concatenate([
    np.concatenate(hald.reshape((size, size, size**2, size**2, 3))[row], axis=1)
    for row in range(size)
])
cv2.imwrite("2d_identity.png", clut)
#method2
hald_reshape = hald.reshape((size, size, size ** 2, size ** 2, 3))
print('hald_reshape shape:', hald_reshape.shape)
img_list = []
for i in range(size):
    print('hald_reshape[i] shape:', hald_reshape[i].shape)
    tmp = np.concatenate(hald_reshape[i], axis=1)
    print('tmp shape:', tmp.shape)
    img_list.append(tmp)

result = np.concatenate(img_list)
print('result shape:', result.shape)

cv2.imwrite("identity_clut_8_test.png", result)

参考资料

color-filters-reconstruction
pillow-lut-tools
Pillow LUT tools
Create your own LUT
CLUT-from-images

猜你喜欢

转载自blog.csdn.net/studyeboy/article/details/112554067