![]() |
![]() |
เป็นไปได้ที่ภาพที่มีโครงสร้างที่ต้องการแต่กลับไม่มีสีที่ต้องการ ในขณะที่สีที่ต้องการกลับไปอยู่ในภาพอื่น จึงเกิดเทคนิคการย้ายสีระหว่าภาพขึ้น
Algorithm การย้ายสีจากภาพหนึ่งไปยังอีกภาพหนึ่งถูกนำเสนอโดย Reinhard et al. [1] ในปัจจุบันได้ถูกนำมาปรับปรุง และนำรวมกับเทคนิคด้วย Machine Learning สร้างเป็นระบบช่วยลงสีแบบ automatic colorization อีกด้วย
ขั้นตอนการทำงาน
มี 2 กระบวนการ
1. การเปลี่ยน Color space
2. การทำ Statistical aligment
การเปลี่ยน Color Space
การเปลี่ยน Color space ก็เพื่อให้เกิดอิสระต่อกันระหว่าง channel ของสี ภาพที่เป็น Digital format ส่วนใหญ่จะใช้ RGB color space [2] ซึ่งจะมี correlation กันระหว่าง channel ของสีคือ red, green และ blue ต้องทำการลด correlation ลง โดย Reinhard et al. ใช้วิธีการเปลี่ยนจาก RGB color space ไปเป็น LMS colorspace [3] ก่อน แล้วจึงเปลี่ยนไปใช้ lαβ color space [4] โดยอาศัยสมการ
[LMS]=[0.38110.57830.04020.19670.72440.07820.02410.12880.8444]⋅[RGB]⇢(1)
L=log10(L)M=log10(M)S=log10(S)⇢(2)
[lαβ]=[1√30001√60001√2]⋅[11111−21−10]⋅[LMS]⇢(3)
นี่คือสมการที่ใช้ในการเปลี่ยนจาก RGB color space ไป lαβ color space เพื่อใช้ในการประมวลข้อมูล เมื่อเสร็จแล้วต้องทำการเปลี่ยนจาก lαβ color space กลับมาสู่ RGB color space เพื่อให้สามารถนำไปใช้กับ Image editor อื่นได้ต่อไป
การย้อนกลับมาเป็น RGB ใช้สมการดังนี้
[LMS]=[11111−11−20]⋅[√33000√66000√22]⋅[lαβ]⇢(4)
L=10LM=10MS=10S⇢(5)
[RGB]=[4.4679−3.58730.1193−1.21862.3809−0.16240.0497−0.24391.2045]⋅[LMS]⇢(6)
การทำ Statistical aligment
Reinhard et al. ใช้การหาค่า Arithmetic Mean และ Standard deviation ของแต่ละ channel ใน lαβ color space โดย
μl แทนค่า mean ของ channel l
μa แทนค่า mean ของ channel α
μb แทนค่า mean ของ channel β
σl แทนค่า standard deviation ของ channel l
σa แทนค่า standard deviation ของ channel α
σb แทนค่า standard deviation ของ channel β
ขั้นตอนที่ 1 หาผลต่างระหว่างค่าสีของแต่ละ channel กับ ค่า mean
l∗=l−μl
α∗=α−μa
β∗=β−μb
ขั้นตอนที่สอง ทำการ scale ค่าที่ได้จากขั้นตอนที่ 1 ด้วย σtσs , σt คือ standard deviation จาก target image และ σs คือ standard deviation จาก source image
l′=σtlσsll∗
α′=σtaσsaα∗
β′=σtbσsbβ∗
ขั้นตอนที่สาม บวกด้วย μ ของ แต่ละ Channel ของภาพ target
l′=l′+μtl
α′=α′+μta
β′=β′+μtb
ในการทำงานต้องใช้รูป 2 รูปทำหน้าที่เป็น source (s) และ target (t) โดยที่ source จะเป็นภาพที่ต้องการนำเสนอ และ target คือภาพที่สีจะถูก transfer ออกไปยัง source
เมื่อเสร็จแล้วก็ทำการแปลงกับไปใช้ RGB color space ต่อไป
![]() |
รูปที่ 1 Color transfer เริ่มต้นด้วยการเปลี่ยน Color space จาก RGB ไปเป็น LAB แล้วทำ Statistical alignment |
![]() |
รูปที่ 2 หลังจากได้ค่าของ Pixel ใหม่แล้ว ก็ทำการเปลี่ยน Color Space จาก LAB ไปสู่ RGB ซึ่งจะได้รูปภาพใหม่ออก |
Python code
ความต้องการ
1. Numpy
2. Matplotlib
3. Skimage (option) หรือ PIL
import matplotlib.pyplot as plt
import numpy as np
import skimage.io
def replaceZeroes(data):
'''
Reference :
https://stackoverflow.com/questions/21610198/runtimewarning-divide-by-zero-encountered-in-log
'''
min_nonzero = np.min(data[np.nonzero(data)])
data[data == 0] = min_nonzero
return data
s_img_1 = skimage.io.imread('pexels-photo-248771.jpeg')
t_img_1 = skimage.io.imread('pexels-photo-440731.jpeg')
ro = s_img_1.shape[0]
co = s_img_1.shape[1]
# normalize
s_img = s_img_1/255
t_img = t_img_1/255
# split RBG channels
sR,sG,sB = np.rollaxis(s_img,-1)
tR,tG,tB = np.rollaxis(t_img,-1)
r1 = sR.reshape((sR.shape[0]*sR.shape[1],1))
g1 = sG.reshape((sG.shape[0]*sG.shape[1],1))
b1 = sB.reshape((sB.shape[0]*sB.shape[1],1))
r2 = tR.reshape((tR.shape[0]*tR.shape[1],1))
g2 = tG.reshape((tG.shape[0]*tG.shape[1],1))
b2 = tB.reshape((tB.shape[0]*tB.shape[1],1))
s_img = np.hstack((r1,g1,b1))
t_img = np.hstack((r2,g2,b2))
a = np.array([[0.3811, 0.5783, 0.0402],[0.1967, 0.7244, 0.0782],[0.0241, 0.1288 ,0.8444]])
b = np.array([[1/np.sqrt(3), 0 ,0],[0, 1/np.sqrt(6), 0],[0, 0, 1/np.sqrt(2)]])
c = np.array([[1, 1, 1],[1, 1, -2],[1, -1, 0]])
b2 = np.array([[np.sqrt(3)/3, 0, 0],[0, np.sqrt(6)/6, 0],[0, 0, np.sqrt(2)/2]])
c2 = np.array([[1, 1, 1],[1, 1, -1],[1, -2, 0]])
# to LMS space
s_lms = np.dot(a,s_img.T)
t_lms = np.dot(a,t_img.T)
# log 10
s_lms = replaceZeroes(s_lms)
s_log10_lms = np.where(s_lms > 0.0000000001, np.log10(s_lms), -10)
t_lms = replaceZeroes(t_lms)
t_log10_lms = np.where(t_lms > 0.0000000001, np.log10(t_lms), -10)
# to LAB space
p1 = np.dot(b , c)
s_lab = np.dot(p1, s_log10_lms)
t_lab = np.dot(p1, t_log10_lms)
# to statistics
s_mean = np.mean(s_lab,axis=1)
s_std = np.std(s_lab,axis=1)
t_mean = np.mean(t_lab,axis=1)
t_std = np.std(t_lab,axis=1)
sf = t_std/s_std
#apply the statistical alignment
res_lab = np.zeros(s_lab.shape)
for ch in range(0,3):
res_lab[ch,:] = (s_lab[ch,:] - s_mean[ch])*sf[ch] + t_mean[ch]
# convert back to LMS
LMS_res=np.dot(np.dot(c2,b2),res_lab)
for ch in range(0,3) :
LMS_res[ch,:] = np.power(10,LMS_res[ch,:])
# convert back to RGB
d = np.array([[4.4679, -3.5873, 0.1193],[-1.2186, 2.3809, -0.1624],[0.0497, -0.2439, 1.2045]])
est_im = np.dot(d,LMS_res).T
result = est_im.reshape((ro,co,3)); # reshape the image
fig=plt.figure(figsize=(30,10))
fig.add_subplot(1,3,1)
plt.imshow(s_img_1)
plt.title('Source')
plt.axis('off')
fig.add_subplot(1,3,2)
plt.imshow(t_img_1)
plt.title('Target')
plt.axis('off')
fig.add_subplot(1,3,3)
plt.imshow(result)
plt.title('Result')
plt.axis('off')
plt.show()
[download code ]ทดสอบ
ภาพเหล่านี้มาจากเว็บไซต์ https://www.pexels.com/search/nature/ ภายใต้ลิขสิทธ์ Creative Common Image (https://www.pexels.com/creative-commons-images/)
จากซ้ายไปขวา คือ source image (receiver ) ,target image (donator ), result image
ข้อบกพร่อง
ยังพบข้อผิดพลาดเกิดขึ้นได้ในบางภาพ (ไม่ทราบสาเหตุ) การเปลี่ยนไปใช้ภาษาอย่างเช่น Matlab หรือ Octave ให้ผลลัพธ์ที่แน่นอนและมี performace ดีกว่า
เอกสารอ้างอิง
[1] Erik Reinhard, Michael Ashikhmin, Bruce Gooch and Peter Shirley,
'Color Transfer between Images', IEEE CG&A special issue on Applied
Perception, Vol 21, No 5, pp 34-41, September - October 2001
[2] https://en.wikipedia.org/wiki/RGB_color_space
[3] https://en.wikipedia.org/wiki/LMS_color_space
[4] https://en.wikipedia.org/wiki/CIELAB_color_space
Sign up here with your email
ConversionConversion EmoticonEmoticon