|
|
|
@ -10,6 +10,7 @@ PIL_CONVERT_COLOR = {
|
|
|
|
|
'full_YCbCr': lambda pil_image: pil_image.convert("YCbCr") if pil_image.mode != 'YCbCr' else pil_image,
|
|
|
|
|
'full_Y': lambda pil_image: pil_image.convert("YCbCr").getchannel(0) if pil_image.mode != 'YCbCr' else pil_image.getchannel(0),
|
|
|
|
|
'sdtv_Y': lambda pil_image: _rgb2ycbcr(np.array(pil_image))[:,:,0] if pil_image.mode == 'RGB' else NotImplementedError(f"{pil_image.mode} to Y"),
|
|
|
|
|
'sdtv2_Y': lambda pil_image: rgb2y(np.array(pil_image)) if pil_image.mode == 'RGB' else NotImplementedError(f"{pil_image.mode} to Y"),
|
|
|
|
|
'L': lambda pil_image: pil_image.convert("L") if pil_image.mode != 'L' else pil_image,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -32,3 +33,87 @@ def _rgb2ycbcr(img, maxVal=255):
|
|
|
|
|
ycbcr = np.reshape(t, [img.shape[0], img.shape[1], img.shape[2]])
|
|
|
|
|
|
|
|
|
|
return ycbcr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rgb2y(im):
|
|
|
|
|
"""
|
|
|
|
|
this impl:
|
|
|
|
|
0.301, 0.586, 0.113 = 77/256, 150/256, 29/256
|
|
|
|
|
-0.172, -0.340, 0.512 = -44/256, -87/256, 131/256
|
|
|
|
|
0.512, -0.430, -0.082 = 131/256, -110/256, -21/256
|
|
|
|
|
|
|
|
|
|
ycbcr 601 sdtv spec[1]:
|
|
|
|
|
0.299, 0.587, 0.114
|
|
|
|
|
-0.172, -0.339, 0.511
|
|
|
|
|
0.511, -0.428, -0.083
|
|
|
|
|
|
|
|
|
|
ycbcr 601 sdtv spec[2]:
|
|
|
|
|
0.299, 0.587, 0.114
|
|
|
|
|
-0.169, -0.331, 0.5
|
|
|
|
|
0.5, -0.419, -0.081
|
|
|
|
|
|
|
|
|
|
[1] Video Demystified A Handbook for the Digital Engineer 4th ed - keith Jack, Chapter 3
|
|
|
|
|
[2] Color Space Conversions Adrian Ford, Alan Roberts
|
|
|
|
|
"""
|
|
|
|
|
im = im.astype(np.float32)
|
|
|
|
|
R, G, B = im[:,:,0], im[:,:,1], im[:,:,2]
|
|
|
|
|
Y = 77/256*R + 150/256*G + 29/256*B
|
|
|
|
|
# [1] Note that 8-bit YCbCr and R'G'B' data should be saturated a
|
|
|
|
|
return Y.clip(0,255).astype(np.uint8)
|
|
|
|
|
|
|
|
|
|
def rgb2yuv(im):
|
|
|
|
|
"""
|
|
|
|
|
this impl:
|
|
|
|
|
0.301, 0.586, 0.113 = 77/256, 150/256, 29/256
|
|
|
|
|
-0.172, -0.340, 0.512 = -44/256, -87/256, 131/256
|
|
|
|
|
0.512, -0.430, -0.082 = 131/256, -110/256, -21/256
|
|
|
|
|
|
|
|
|
|
ycbcr 601 sdtv spec[1]:
|
|
|
|
|
0.299, 0.587, 0.114
|
|
|
|
|
-0.172, -0.339, 0.511
|
|
|
|
|
0.511, -0.428, -0.083
|
|
|
|
|
|
|
|
|
|
ycbcr 601 sdtv spec[2]:
|
|
|
|
|
0.299, 0.587, 0.114
|
|
|
|
|
-0.169, -0.331, 0.5
|
|
|
|
|
0.5, -0.419, -0.081
|
|
|
|
|
|
|
|
|
|
[1] Video Demystified A Handbook for the Digital Engineer 4th ed - keith Jack, Chapter 3
|
|
|
|
|
[2] Color Space Conversions Adrian Ford, Alan Roberts
|
|
|
|
|
"""
|
|
|
|
|
im = im.astype(np.float32)
|
|
|
|
|
R, G, B = im[:,:,0], im[:,:,1], im[:,:,2]
|
|
|
|
|
Y = 77/256*R + 150/256*G + 29/256*B
|
|
|
|
|
U = -44/256*R - 87/256*G + 131/256*B
|
|
|
|
|
V = 131/256*R - 110/256*G - 21/256*B
|
|
|
|
|
Y, U, V = Y, U + 128, V + 128
|
|
|
|
|
# [1] Note that 8-bit YCbCr and R'G'B' data should be saturated at the 0 and 255 levels to avoid underflow and overflow
|
|
|
|
|
return np.stack([Y,U,V], axis=-1).clip(0,255).astype(np.uint8)
|
|
|
|
|
|
|
|
|
|
def yuv2rgb(im):
|
|
|
|
|
"""
|
|
|
|
|
this impl:
|
|
|
|
|
1, 0, 1.406 = 1, 0, 360/256
|
|
|
|
|
1, -0.344, -0.719 = 1, -88/256, -184/256
|
|
|
|
|
1, 1.777, 0 = 1, 455/256, 0
|
|
|
|
|
|
|
|
|
|
ycbcr 601 sdtv spec[1]:
|
|
|
|
|
1, 0, 1.371
|
|
|
|
|
1, -0.336, -0.698
|
|
|
|
|
1, 1.732, 0
|
|
|
|
|
|
|
|
|
|
ycbcr 601 sdtv spec[2]:
|
|
|
|
|
1, 0, 1.403
|
|
|
|
|
1, -0.344, -0.714
|
|
|
|
|
1, 1.773, 0
|
|
|
|
|
|
|
|
|
|
[1] Video Demystified A Handbook for the Digital Engineer 4th ed - keith Jack, Chapter 3
|
|
|
|
|
[2] Color Space Conversions Adrian Ford, Alan Roberts
|
|
|
|
|
"""
|
|
|
|
|
im = im.astype(np.float32)
|
|
|
|
|
Y, Ud, Vd = im[:,:,0], im[:,:,1]-128, im[:,:,2]-128
|
|
|
|
|
R = Y + 360/256*Vd
|
|
|
|
|
G = Y - 88/256*Ud - 184/256*Vd
|
|
|
|
|
B = Y + 455/256*Ud
|
|
|
|
|
# [1] Note that 8-bit YCbCr and R'G'B' data should be saturated at the 0 and 255 levels to avoid underflow and overflow
|
|
|
|
|
return np.stack([R, G, B], axis=-1).clip(0,255).astype(np.uint8)
|