LUT คืออะไร ทำไมเราต้องใช้มัน

สำหรับคนที่ทำงาน Production น่าจะเคยได้ยินคำว่า LUT มาก่อน โดยเฉพาะคนที่ทำงานในฝั่ง Post-Production มันเหมือนเวทย์มนต์ทำให้ภาพที่เราเห็นกลายเป็นแบบที่เราต้องการ มีแสงและสีแบบที่เราต้องการได้รวดเร็วอย่างไม่น่าเชื่อ วันนี้เรามาทำความเข้าใจไส้ในของ LUT กันว่ามันคืออะไร มันทำงานอย่างไร

Quick Basic Digital Image & Video

ในระบบคอมพิวเตอร์ เวลาเราเก็บรูปภาพ เราจะเริ่มจาก ความกว้าง และ ยาว ของรูปภาพ เราจะใช้หน่วยเป็น Pixel หรือนับเป็นช่อง ๆ เวลาเราซื้อกล้อง เราอาจจะเคยได้ยินว่า กล้องตัวนี้ให้ความละเอียดภาพ 24 MP หรือก็คือในภาพนี้มีทั้งหมด 24 ล้านช่องด้วยกัน แต่มันไม่ได้บอกนะว่า ภาพนี้มีขนาดกว้าง และ ยาวเท่าไหร่ มันไม่สนใจ มันสนแค่ว่า ภาพนี้มีทั้งหมด 24 ล้านช่องเท่านั้น

ดังนั้น สูตรเวลาเราหาความละเอียดของรูปภาพ มันน่าจะเป็น ความกว้างสักอย่าง คูณกับความยาว แต่แน่นอนว่า ถ้าเรารู้สักด้าน เราน่าจะหาอีกด้านได้ไม่ยากผ่านการแก้สมการใช่มะ สุดท้ายแล้ว ถ้าเรารู้ด้านใดด้านหนึ่ง เราก็แค่เอาขนาดด้านที่เรารู้ไปหารความละเอียด ก็จบแล้ว

นอกจากด้านกว้างและยาวแล้ว สิ่งที่เราเห็นคือ สี แบบที่ง่ายที่สุดคือ สีดำและ สีขาว เราอาจจะแทนเป็น 0 และ 1 ตามลำดับได้ แต่เมื่อเราอยากได้ความละเอียดมากขึ้น เราเลยต้องเพิ่มตัวเลขความเข้มเข้าไปอีก จากเดิม 0 และ 1 เราใช้ 1 Bit ในการเก็บ เราอาจจะใช้ 8 Bit ไปเลย ทำให้เรามีตัวเลขตั้งแต่ 0-255

เรื่องมากเข้าไปอีก เห้ย เราไม่อยากได้ขาวดำแล้ว เราอยากได้สีเลย ซึ่งระบบสีในคอมพิวเตอร์มีหลายระบบมาก ๆ แต่ระบบที่เรานิยมใช้กันคือ ระบบสีแบบ RGB ที่เราคุ้นเคยกัน ซึ่งมันเกิดจากความเข้ม ของสีแดง, สีเขียว และ สีน้ำเงินเอามาผสมกัน จนกลายเป็นสีที่เราเห็น ดังนั้นในแต่ละ Pixel หากเราใช้ระบบสีแบบ RGB จะมีตัวเลขทั้งหมด 3 ตัวด้วยกัน

ส่วนวีดีโอ ในเชิงคอมพิวเตอร์เอาจริง ๆ เราทำทุกอย่างกับมันได้เหมือนกับที่เราทำกับรูปภาพทุกประการ เพราะวีดีโอก็คือ รูปภาพหลาย ๆ ภาพจำนวนมาก ๆ ต่อกัน แล้วเพิ่มพวก Metadata อื่น ๆ เข้าไปเช่น Framerate เพื่อบอกโปรแกรมเล่นว่าให้เล่นเร็วขนาดไหนแค่นั้นเอง

LUT คืออะไร ?

LUT (Look-up Table) ในงานตัดต่อ เป็นเหมือนสื่อกลางที่ทำให้เราสามารถแปลงข้อมูลสีของไฟล์ ไปเป็นแบบที่เราต้องการได้ หลักการมันง่ายมาก ๆ คือ เราจะทำตารางออกมาหนึ่งตัว เพื่อ Map ออกมาเลยว่า สีนี้ เมื่อผ่าน LUT จะเป็นอีกสีนึงหรือสีเดิมอะไรก็ว่ากันไป

ถามว่า แล้วเราจะเอาของพวกนี้มาใช้ทำไมกันละ เริ่มต้นง่าย ๆ ก่อน เวลาเราอยากจะได้สีแบบที่เราต้องการ เช่น เราอยากได้สีของรูปหรือวีดีโอของเราเหมือน Mad Max จังเลย แต่ถ้าจะให้เรามานั่งปรับอะไรเองทั้งหมด เพื่อให้เหมือน มันก็เป็นเรื่องยากใช่มะ เราก็สามารถไปหา LUT ที่ทำให้ Look & Feel เหมือน Mad Max มาแปะ ก็เรียบร้อยแล้ว มันจะ Map สีของไฟล์เดิม เทียบกับ LUT ออกมา มันก็จะเหมือนกับ Mad Max ที่เราต้องการได้เลย LUT พวกนี้ เราจะเรียกว่า Creative LUT หรือก็คือ LUT ที่ทำหน้าที่ในการปรุงแต่งแสงสีให้ออกมาใน Look & Feel ที่ต้องการนั่นเอง

หรือ เราย้อนกลับไปหน้างาน ก่อน Post เลย บางครั้ง เพื่อให้เก็บ Dynamic Range ที่มากกว่าเดิม เราจะเลือกถ่ายมาเป็น LOG ในการที่จะแปลงให้อยู่ใน Colour Space ที่เราใช้ทำงานเป็นหลัก เช่น เวลาเราทำงานบางครั้ง เราจะถ่ายมาเป็น S-Log3 และเราทำงานบน Rec.709 เราก็จะมี LUT สำหรับแปลงนั่นเอง นอกจากนั้น มันยังทำให้เราได้ประโยชน์เมื่อเราทำงานกับกล้องหลาย ๆ ประเภทเช่น กล้องตัวนึงเป็น Sony เราจะถ่ายด้วย S-Log3 และกล้องอีกตัวเป็น Arri เลย กดมาเป็น LogC4 เราก็สามารถทำงานด้วยกันง่ายขึ้นด้วยการแปลงทั้งสองให้กลายเป็น Format ที่เราต้องการทำงานก่อน เช่น Rec.709 เท่านี้ เราก็สามารถทำงานร่วมกันได้ง่ายกว่าเดิมแล้ว โดย LUT พวกนี้ เราเลยจะเรียกว่า Speed LUT

อีกประเภทที่เราใช้งานบ่อย เป็นตัวจบการทำงาน เช่น เราบอกว่าจอ หรือ Media ที่เราต้องการทำงาน มันจะต้องแสดงผลในอีก Colour Space หนึ่ง เช่นใน Post เราทำมาเป็น Rec.709 แต่เราบอกว่า เราต้องเอาไปฉายผ่าน Cinema Projecter ที่ใช้ DCI เราจะต้องแปลงงานที่เราทำเสร็จแล้วให้อยู่ใน Colour Space ที่ถูกต้องก่อน โดยเราจะเรียก LUT ที่ทำหน้าที่พวกนี้ว่า Technical LUT

เอาจริง ๆ ถ้าเราลองไปหาอ่าน เราว่าเขาน่าจะแบ่งประเภทตามการใช้งานที่มากกว่านี้อีก แต่ 3 ตัวนี้ เป็นตัวที่เราใช้งานเป็นประจำเลยยกตัวอย่างขึ้นมาให้อ่านกัน แต่ไม่ว่าจะเป็น LUT ประเภทไหน หลักการการทำงานเหมือนกันเป๊ะ ๆ คือ มันเป็นตารางสำหรับเทียบแสง และสีให้เป็นในรูปแบบที่เราต้องการ

LUT Demo with OpenCV

import cv2
import numpy as np
import matplotlib.pyplot as plt

เพื่อให้เข้าใจกันลึกขึ้น เรามาลองเล่น LUT แบบ ลึก ๆ เขียนโปรแกรมกันเลยดีกว่า โดย Dependencies ที่เราจะใช้ในวันนี้มี OpenCV ที่เป็น Image Processing Library, Numpy สำหรับการจัดการ Array และ Matplotlib สำหรับการ Plot Graph

img = cv2.imread('penguin.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

plt.imshow(img)
plt.title('Original')
plt.show()

เริ่มจากการอ่านไฟล์รูปภาพเข้ามาก่อน ตัว OpenCV เขาอำนวยความสะดวกให้เราแล้ว โดยการให้คำสั่งชื่อว่า imread มา โดยมันจะอ่านไฟล์รูปภาพเข้ามาเป็น Numpy Array แต่เวลา OpenCV มันอ่าน มันไปอ่านเป็น BGR ทำให้ เราต้องแปลงมันกลับไปเป็น RGB เหมือนเดิมก่อน ทำให้เราเลยต้องใช้คำสั่ง cvtColor เพื่อขอแปลงกลับ

จากนั้นเราทำการขอให้มันแสดงผลรูปออกมาดู เพื่อให้มั่นใจว่า เราโหลดรูปถูก Channel หรือไม่

> img.shape
(1365, 2048, 3)

อย่างที่เราบอกว่า รูปจริง ๆ มันไม่มีอะไรเลย นอกจาก ตัวเลขความเข้มของแต่ละ Channel เท่านั้น ทำให้เวลาเราสั่งโหลดรูปภาพผ่าน OpenCV มันจะเก็บเป็น Numpy Array โดยถ้าเราขอดูรูปร่างของมัน เราจะเห็นว่า มันจะเป็นขนาดด้านยาว คูณด้านกว้าง แล้วค่อยคูณ 3 โดยที่ 3 นี่แหละ คือเลขแต่ละ Channel

RLUT = [i for i in range(255, -1, -1)]
GLUT = [i for i in range(255, -1, -1)]
BLUT = [i for i in range(255, -1, -1)]

LUT = np.array([RLUT, GLUT, BLUT])

จากนั้นเรามาเตรียม LUT กันดีกว่า เพื่อความง่าย และรวดเร็วในการ Demo เราขอให้ Simple LUT เลยละกัน เราจะแปลงรูปให้แสดงกลับด้านกัน ส่วนที่สว่างให้มืด และ ส่วนที่มือให้สว่าง เลยทำ LUT ที่แปลงกลับด้านกัน เช่น 0 -> 255 เพื่อให้เห็นภาพ เราจะทำ LUT ของแต่ละ Channel แยกกัน ออกเป็น RLUT สำหรับ Red Channel, GLUT สำหรับ Green Channel และ BLUT สำหรับ Blue Channel สุดท้าย เพื่อความง่ายอีก เราจะ Merge มันเข้าไปเป็น Array ชุดเดียวกันเดี๋ยวเวลาเราจะ Access จะได้ง่ายหน่อย

> LUT.shape
(3,256)

ถ้าเราขอรูปร่างของ LUT ออกมาดู มันจะกลายเป็น 3,256 โดย 3 แรกมาจาก 3 Channel RGB และ 256 มาจากค่าตาราง 0-255 เพราะรูปเราใช้ 8 Bit Colour Space

appliedImg = np.zeros(img.shape)

for y in range(img.shape[0]) :
    for x in range(img.shape[1]) :
        for channel in range(img.shape[2]) :
            appliedImg[y,x,channel] = LUT[channel,img[y,x, channel]]

ถ้าใครที่อ่าน Numpy มาลึกหน่อย เราสามารถ Boardcast Numpy Array แล้วทำ Parallel Operation ได้เลย ไม่ต้องมานั่ง For-Loop ให้เสียเวลาเด้อ แต่ทำแบบนี้เพื่อให้เข้าใจง่ายสำหรับมือใหม่

มาถึงขั้นตอนที่สำคัญ คือ การ Apply LUT เข้าไปในภาพจริง ๆ เราเริ่มจากการสร้าง Numpy Array ที่ประกอบด้วย 0 ที่มีมิติเท่ากับรูปภาพต้นฉบับของเราเป๊ะ ๆ เพื่อเก็บรูปหลังจากที่เรา Apply LUT เสร็จแล้ว

ที่เหลือง่ายมาก ๆ คือ เราทำการ For-Loop ไล่ลงไปในแต่ละมิติเลย ใช้ทั้งหมด 3 มิติคือยาว, กว้าง และ Channel อย่างที่เราบอกว่า LUT มันคือ Look-up Table การแปลงแต่ละ Pixel ง่ายมาก ๆ เราแค่เอาค่าของแต่ละ Pixel และ Channel ไปเช็คกับตารางที่เราทำไว้ ได้เท่าไหร่ก็แปะลงไปในรูปใหม่เท่านั้นเอง

สุดท้าย ถ้าเราเอาภาพออกมาดู ภาพของเราก็กลายเป็นภาพ Invert เรียบร้อยแล้ว เอาจริง ๆ คือพวก LUT จริง ๆ เบื้องหลังการทำงานแบบที่เรา Demo ให้ดู แค่ว่าตัว LUT ไม่เหมือนกัน เขามีการทำออกมาพิเศษ

จริง ๆ เราว่า บางคนอาจจะคุ้น ๆ ว่าเอ๊ะ ทำไมมันเหมือน Invert ใน Photoshop เลย ใช่แล้วฮะ เบื้องหลังของมัน ก็คือการกลับด้าน เอา 255 ไปลบนั่นเอง

1D vs 3D LUT

ถ้าเราลองไปนั่งหาอ่านเพิ่มเติมดู เราจะเจอกับอีกคำคือ 3D LUT มันคืออะไรกัน ก่อนหน้านี้ เราบอกว่า LUT ทำหน้าที่เป็นเหมือนตารางเทียบสี แต่แน่นอนว่า สีที่เราใช้กันประกอบด้วย RGB สามสีรวมกัน ทำให้ ถ้าเราจะปรับสีจริง ๆ เราสามารถเลือกปรับแต่ละ Channel ได้

ในตัว 1D LUT นั้นจะประกอบด้วยค่าเพียงค่าเดียวเท่านั้น เช่น แปลงจาก 245 -> 240 แค่นั้นเลย โดยเราอาจจะใส่ LUT นี้เข้าไปในทั้งสาม Channel เลยก็ได้ หรือจริง ๆ เราจะเอา 1D LUT มา 3 ตัวของแต่ละ Channel มาทำงานก็ได้เหมือนกัน แต่มันน่าจะลำบากน่าดู

เลยทำให้เรามี 3D LUT ขึ้นมา เปรียบเสมือนกับเราเอา 1D LUT 3 อันมาวางรวม ๆ กันเป็นไฟล์เดียวนั่นเอง โดยพวกนี้ไฟล์มันจะอยู่ในนามสกุลที่ชื่อว่า Cube ถ้าเราลองเปิดดู เราจะเห็นว่ามันมีส่วนประกอบอยู่ 2 ส่วนคือ Header สำหรับบอกข้อมูลที่จำเป็นต่าง ๆ เช่นขนาด หรือค่าสูงสุดต่ำสุดเป็นต้น และอีกส่วนคือตัวตารางเอง

TITLE "Generated by Resolve"
LUT_3D_SIZE 33

0.00802625 0.016556 0.0184024
0.0100862 0.0191501 0.0210269
0.0124819 0.0221103 0.024033
0.0135042 0.02327 0.0252384
0.0156252 0.0248112 0.0270237
0.0213626 0.0282444 0.0313268
0.0279545 0.0317082 0.0356451
0.0358282 0.0351873 0.0406043

ดูจากไฟล์แล้วอาจจะเอ๊ะว่า ทำไมไฟล์ตรงตัวตารางมันมีเลขแค่ 3 ตัวเองละ ถ้าเราจะเทียบจากสี 3 Channel เป็น 3 Channel มันน่าจะต้องมี 6 ค่าสิ อะ ก็จริง แต่ 3 ค่าแรกจริง ๆ แล้วเราคำนวณเองได้ เราเลยไม่ต้องเก็บ จาก Header บอกว่า มันมีขนาด 33 แปลว่า ถ้าเราเอามารวมกัน มันจะได้เท่ากับ 33 ยกกำลัง 3 จุด 35,937 จุดด้วยกัน โดย LUT บางตัวเขาจะกำหนดค่า ต่ำสุด สูงสุดด้วย แต่ถ้าไม่ได้กำหนดมันจะใช้ค่าเริ่มต้น คือ 0,1 แปลว่า จุดแรก จะเป็น 0,0,0 มันก็จะไปเทียบกับแถวแรกตรง ๆ ได้เลยนั่นเอง แล้วถามว่า อ้าวแล้วถ้าค่ามันวิ่งระหว่าง 0,1 แต่สีเรามันเป็น 0-255 แล้วเราจะทำยังไงละ ง่ายมาก เราก็หารมันสิ

ถามว่า เราจะทำแบบนั้นทำไมอะ นั่นเป็นเพราะ ถ้าเราเก็บ RGB ตรง ๆ เลยถามว่า ถ้าเราเอาไปใส่กับไฟล์ที่เป็นสี 8-bit กับ 10-bit เราจะต้องแยกไฟล์กันเหรอ มันก็ไม่น่า ยังไม่นับกล้องในอนาคตที่อาจจะเก็บสีได้ละเอียดกว่านี้อีก เขาเลยเลือกที่จะ Normalise มาให้ เราก็เลยต้อง Normalise ค่าสีตามสเปกของไฟล์ที่ใส่เข้ามาก่อน จิ้มจากตาราง แล้วค่อยแปลงกลับโดยการคูณค่าสีกลับเข้าไปแค่นั้นเลยง่าย ๆ

LUT มันโง่ ดังนั้นคนต้องฉลาด

สิ่งสำคัญของ LUT อย่างที่เราเห็นคือ ไม่ว่าเราจะ Apply LUT ตัวเดิมกับไฟล์ที่มาในลักษณะแบบไหน มันก็จะทำเหมือนกันในทุก ๆ ครั้งคือ การอ่านเทียบตารางทั้งหมด ปัญหาคือ ไฟล์ภาพที่เราได้มาแต่ละรอบ มันให้แสง และ สีที่แตกต่างกัน เช่น เรามี Footage ที่เรากดตอนเที่ยงมา และ ถ่ายตอนเย็นมา เมื่อเราอัด LUT เข้าไป สิ่งที่เราจะได้มันจะแตกต่างกันเลย เพราะ สีต้นทางมันแตกต่างกัน น่าจะเป็นตัวอย่างที่ Extreme มากเลยทีเดียวโดยเฉพาะ Creative LUT เนี่ยแหละตัวดีเลย

วิธีการทำงานกับ LUT ที่เราคิดว่าง่ายที่สุดคือ ให้เรา Calibrate ภาพหรือ Footage ของเราให้ตรงกับ Reference ให้มากที่สุดเท่าที่จะเป็นไปได้ แล้วค่อยใส่ LUT เข้าไป สำหรับเราเอง เราจะใช้ Technical LUT แปลงให้อยู่ใน Rec.709 ก่อน แล้วพยายาม Calibrate ให้แสงมันไม่ Over และ Under เกินไปจัดการพวกรายละเอียดให้ออกมาในรูปแบบที่เราต้องการก่อน (ส่วนนี้สำคัญมาก ๆ) จากนั้น เราถึงจะใส่ Creative LUT ให้ได้ออกมาในรูปแบบที่เราต้องการ

ตัวอย่างนี้ทำใน Final Cut Pro X

ตัวอย่างเช่น เราถ่ายมาเป็น S-Log3 เราจะใช้ LUT เพื่อแปลงเป็น Rec.709 ก่อน จากนั้น ใช้ Color Wheels เพื่อปรับแสงและสีให้อยู่ในโทนปกติ ไม่มีส่วนไหน Under หรือ Over จากนั้น ถ้าเป็นหน้าคน ผิวคน เราจะใช้ Skin LUT โดยเลือกเฉพาะผิวหนัง เมื่อต้นฉบับอยู่ในจุดที่โอเคแล้ว เราก็แค่ใส่ Creative LUT ในที่นี้ เราเลือกเป็น Film Tone อาจจะปรับ Intensity ลงไปหน่อยเพื่อให้มันเข้ากับ Footage ของเรา

สรุป

Look-up Table (LUT) เป็นเครื่องมือในงาน Production ที่ช่วยให้เราสามารถทำงานได้อย่างรวดเร็วมากขึ้นในงาน Post ตั้งแต่การแปลง Colour Space, Gamma จนไปถึงการทำให้ Look & Feel เป็นไปในแบบที่เราต้องการ หลักการเบื้องหลังของมันง่ายมากคือ การทำตารางสีขึ้นมา โดยเอาสีต้นฉบับไปเทียบกับตาราง เราจะได้สีใหม่ออกมานั่นเอง โดย LUT ถ้าแบ่งตามลักษณะการเก็บข้อมูล เราจะแบ่งได้เป็น 1D และ 3D LUT ด้วยกัน โดย 3D LUT จะเลือกเก็บทั้ง 3 Channel RGB เลย เทียบกับ 1D LUT จะเก็บเพียง 1 Channel เท่านั้น เราสามารถดาวน์โหลด LUT File มาใช้งานกับโปรแกรมตัดต่อของเราได้เลย เขาจะมีไฟล์ที่เป็นมาตรฐานไว้แล้วเช่น Cube File เป็นต้น ลองไปโหลดมาเล่นกันได้