LUT(look up table)調(diào)色的原理與代碼實(shí)現(xiàn)

LUT用來調(diào)色挺好玩的。本質(zhì)就是通過一個(gè)表,把一個(gè)顏色映射為另一個(gè)顏色。

原理說明

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

原始的LUT圖

那么這個(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]。

根據(jù)藍(lán)色值找出對應(yīng)小方塊

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] !!
根據(jù)紅綠值找出對應(yīng)的新顏色

簡單的說,就是將輸入顏色作為一個(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é)果。

修改后的LUT
測試圖1
結(jié)果1

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容