LUT用來調(diào)色挺好玩的。本質(zhì)就是通過一個(gè)表,把一個(gè)顏色映射為另一個(gè)顏色。
原理說明
某天看見GPUImage庫里面有下面這樣的一張圖,很好奇有什么用,結(jié)果發(fā)現(xiàn)就是傳說中的LUT(圖片是其中一種表達(dá)方式,還可以是文本或其他),對此圖進(jìn)行調(diào)色之后,再套用到目標(biāo)圖片中,就可以獲得一模一樣的調(diào)色結(jié)果。

那么這個(gè)圖怎么看?
首先看一共有8x8=64個(gè)方塊,從左上角的第0個(gè)開始一行行數(shù)過去,數(shù)到右下角的第63,代表了藍(lán)色B的取值范圍是[0, 63]。于是問題來了,平時(shí)見到的取值范圍都是[0, 255]的,而這個(gè)圖里只有[0, 63],精度變低了。猜測是為了減少占用空間,64x64x64x3比256x256x256x3小得太多了。那么先不管,那就假設(shè)藍(lán)色B的取值范圍從[0, 255]降低到[0, 63]。

OK,如果我有一個(gè)顏色C1(B:30,G:31,R:32),那么根據(jù)B的值,我找到了第30個(gè)小方塊,如下圖。這個(gè)小方塊的以左上角為原點(diǎn),R值為橫軸,G值為縱軸,取值范圍也是[0, 63]。這時(shí),我們再根據(jù)顏色C1的G和R值作為坐標(biāo)點(diǎn),找到一個(gè)點(diǎn),這個(gè)點(diǎn)的顏色C2就是我們得到的映射結(jié)果。
特別注意!僅坐標(biāo)的取值范圍是[0, 63],輸出的顏色還是[0, 255] !!

簡單的說,就是將輸入顏色作為一個(gè)三維坐標(biāo)系的一個(gè)點(diǎn),然后得到這個(gè)點(diǎn)的新顏色作為輸出。
那么下面就用代碼實(shí)現(xiàn)這個(gè)過程(python+opencv)
聲明一個(gè)類MYLUT。為了能直接使用[0, 255]的取值范圍,特意將64放大到256(實(shí)際上還是不精確的)。最終生成一個(gè)shape為(256,256,256,3)的數(shù)組作為LUT。
class MYLUT:
def __init__(self, lutpath='lut/lookup_my.png'):
lut = cv2.imread(lutpath)
cube64rows = 8
cube64size = 64
# cube256rows = 16
cube256size = 256
cubescale = cube256size / cube64size # 4
reshapelut = np.zeros((cube256size, cube256size, cube256size, 3))
for i in range(cube64size):
cx = (i % cube64rows) * cube64size
cy = (i / cube64rows) * cube64size
cube64 = lut[cy:cy + cube64size, cx:cx + cube64size]
_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
def imageInLut(self, src):
arr = src.copy()
bs = arr[:, :, 0]
gs = arr[:, :, 1]
rs = arr[:, :, 2]
arr[:, :] = self.lut[bs, gs, rs] # numpy寫的越騷,運(yùn)行速度越快
return arr
# 下面的樸素的遍歷方式就很慢。
# img = src.reshape(-1, 3)
# for iy in range(img.shape[0]):
# b,g,r = img[iy]
# img[iy] = self.lut[b, g, r]
# return img.reshape(src.shape)
上述代碼中的查找顏色替換arr[:, :] = self.lut[bs, gs, rs]是提速的關(guān)鍵!在python中用for循環(huán)遍歷就是慢。
注意測試的時(shí)候使用原始LUT圖,得到一樣的結(jié)果圖片,則是正確的。
if __name__ == "__main__":
img = cv2.imread('test.jpg')
print('init', time.time())
lut = MYLUT()
print('start', time.time())
img = lut.imageInLut(img)
print('finish', time.time())
# cv2.imwrite(output, vhs)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
print("done")
以上代碼僅作示范,請讀者舉一反三。
然后用PhotoShop(不是PS喔?。┬薷脑嫉腖UT圖(注意只能改顏色!不能弄模糊、噪點(diǎn)之類的操作!請用無損壓縮的圖片格式,例如PNG),再代入得到結(jié)果。



顏色調(diào)的有點(diǎn)丑,請忽略。