mirror of
https://github.com/wassname/scikit-image.git
synced 2026-06-27 19:48:43 +08:00
Add colorspaces: YUV, YIQ, YPbPr, YCbCr (#2060)
Add YUV, YIQ, YPbPr, YCbCr colorspaces
This commit is contained in:
@@ -224,3 +224,6 @@
|
||||
|
||||
- Evgeni Burovski
|
||||
Adaptation of ImageJ 3D skeletonization algorithm.
|
||||
|
||||
- Alex Izvorski
|
||||
Color spaces for YUV and related spaces
|
||||
|
||||
@@ -22,6 +22,14 @@ from .colorconv import (convert_colorspace,
|
||||
hed2rgb,
|
||||
lab2lch,
|
||||
lch2lab,
|
||||
rgb2yuv,
|
||||
yuv2rgb,
|
||||
rgb2yiq,
|
||||
yiq2rgb,
|
||||
rgb2ypbpr,
|
||||
ypbpr2rgb,
|
||||
rgb2ycbcr,
|
||||
ycbcr2rgb,
|
||||
separate_stains,
|
||||
combine_stains,
|
||||
rgb_from_hed,
|
||||
@@ -75,6 +83,14 @@ __all__ = ['convert_colorspace',
|
||||
'hed2rgb',
|
||||
'lab2lch',
|
||||
'lch2lab',
|
||||
'rgb2yuv',
|
||||
'yuv2rgb',
|
||||
'rgb2yiq',
|
||||
'yiq2rgb',
|
||||
'rgb2ypbpr',
|
||||
'ypbpr2rgb',
|
||||
'rgb2ycbcr',
|
||||
'ycbcr2rgb',
|
||||
'separate_stains',
|
||||
'combine_stains',
|
||||
'rgb_from_hed',
|
||||
|
||||
+236
-2
@@ -40,6 +40,7 @@ Supported color spaces
|
||||
:author: Ralf Gommers (hsv2rgb)
|
||||
:author: Travis Oliphant (XYZ and RGB CIE functions)
|
||||
:author: Matt Terry (lab2lch)
|
||||
:author: Alex Izvorski (yuv2rgb, rgb2yuv and related)
|
||||
|
||||
:license: modified BSD
|
||||
|
||||
@@ -124,9 +125,11 @@ def convert_colorspace(arr, fromspace, tospace):
|
||||
>>> img_hsv = convert_colorspace(img, 'RGB', 'HSV')
|
||||
"""
|
||||
fromdict = {'RGB': lambda im: im, 'HSV': hsv2rgb, 'RGB CIE': rgbcie2rgb,
|
||||
'XYZ': xyz2rgb}
|
||||
'XYZ': xyz2rgb, 'YUV': yuv2rgb, 'YIQ': yiq2rgb,
|
||||
'YPbPr': ypbpr2rgb, 'YCbCr': ycbcr2rgb }
|
||||
todict = {'RGB': lambda im: im, 'HSV': rgb2hsv, 'RGB CIE': rgb2rgbcie,
|
||||
'XYZ': rgb2xyz}
|
||||
'XYZ': rgb2xyz, 'YUV': rgb2yuv, 'YIQ': rgb2yiq,
|
||||
'YPbPr': rgb2ypbpr, 'YCbCr': rgb2ycbcr }
|
||||
|
||||
fromspace = fromspace.upper()
|
||||
tospace = tospace.upper()
|
||||
@@ -322,6 +325,30 @@ gray_from_rgb = np.array([[0.2125, 0.7154, 0.0721],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]])
|
||||
|
||||
yuv_from_rgb = np.array([[ 0.299 , 0.587 , 0.114 ],
|
||||
[-0.14714119, -0.28886916, 0.43601035 ],
|
||||
[ 0.61497538, -0.51496512, -0.10001026 ]])
|
||||
|
||||
rgb_from_yuv = linalg.inv(yuv_from_rgb)
|
||||
|
||||
yiq_from_rgb = np.array([[0.299 , 0.587 , 0.114 ],
|
||||
[0.59590059, -0.27455667, -0.32134392],
|
||||
[0.21153661, -0.52273617, 0.31119955]])
|
||||
|
||||
rgb_from_yiq = linalg.inv(yiq_from_rgb)
|
||||
|
||||
ypbpr_from_rgb = np.array([[ 0.299 , 0.587 , 0.114 ],
|
||||
[-0.168736,-0.331264, 0.5 ],
|
||||
[ 0.5 ,-0.418688,-0.081312]])
|
||||
|
||||
rgb_from_ypbpr = linalg.inv(ypbpr_from_rgb)
|
||||
|
||||
ycbcr_from_rgb = np.array([[ 65.481, 128.553, 24.966],
|
||||
[ -37.797, -74.203, 112.0 ],
|
||||
[ 112.0 , -93.786, -18.214]])
|
||||
|
||||
rgb_from_ycbcr = linalg.inv(ycbcr_from_rgb)
|
||||
|
||||
# CIE LAB constants for Observer=2A, Illuminant=D65
|
||||
# NOTE: this is actually the XYZ values for the illuminant above.
|
||||
lab_ref_white = np.array([0.95047, 1., 1.08883])
|
||||
@@ -1450,3 +1477,210 @@ def _prepare_lab_array(arr):
|
||||
if shape[-1] < 3:
|
||||
raise ValueError('Input array has less than 3 color channels')
|
||||
return dtype.img_as_float(arr, force_copy=True)
|
||||
|
||||
|
||||
def rgb2yuv(rgb):
|
||||
"""RGB to YUV color space conversion.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rgb : array_like
|
||||
The image in RGB format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The image in YUV format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `rgb` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Y is between 0 and 1. Use YCbCr instead of YUV for the color space which
|
||||
is commonly used by video codecs (where Y ranges from 16 to 235)
|
||||
"""
|
||||
return _convert(yuv_from_rgb, rgb)
|
||||
|
||||
|
||||
def rgb2yiq(rgb):
|
||||
"""RGB to YIQ color space conversion.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rgb : array_like
|
||||
The image in RGB format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The image in YIQ format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `rgb` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``.
|
||||
"""
|
||||
return _convert(yiq_from_rgb, rgb)
|
||||
|
||||
|
||||
def rgb2ypbpr(rgb):
|
||||
"""RGB to YIQ color space conversion.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rgb : array_like
|
||||
The image in RGB format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The image in YIQ format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `rgb` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``.
|
||||
"""
|
||||
return _convert(ypbpr_from_rgb, rgb)
|
||||
|
||||
|
||||
def rgb2ycbcr(rgb):
|
||||
"""RGB to YCbCr color space conversion.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rgb : array_like
|
||||
The image in RGB format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The image in YCbCr format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `rgb` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Y is between 16 and 235. This is the color space which is commonly used
|
||||
by video codecs, it is sometimes incorrectly called "YUV"
|
||||
"""
|
||||
arr = _convert(ycbcr_from_rgb, rgb)
|
||||
arr[..., 0] += 16
|
||||
arr[..., 1] += 128
|
||||
arr[..., 2] += 128
|
||||
return arr
|
||||
|
||||
|
||||
def yuv2rgb(yuv):
|
||||
"""RGB to YIQ color space conversion.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rgb : array_like
|
||||
The image in RGB format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The image in YIQ format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `rgb` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``.
|
||||
"""
|
||||
return _convert(rgb_from_yuv, yuv)
|
||||
|
||||
|
||||
def yiq2rgb(yiq):
|
||||
"""YIQ to RGB color space conversion.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
yiq : array_like
|
||||
The image in YIQ format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The image in RGB format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `yiq` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``.
|
||||
"""
|
||||
return _convert(rgb_from_yiq, yiq)
|
||||
|
||||
|
||||
def ypbpr2rgb(ypbpr):
|
||||
"""YPbPr to RGB color space conversion.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ypbpr : array_like
|
||||
The image in YPbPr format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The image in RGB format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `ypbpr` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``.
|
||||
"""
|
||||
return _convert(rgb_from_ypbpr, ypbpr)
|
||||
|
||||
|
||||
def ycbcr2rgb(ycbcr):
|
||||
"""YCbCr to RGB color space conversion.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ycbcr : array_like
|
||||
The image in YCbCr format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
The image in RGB format, in a 3- or 4-D array of shape
|
||||
``(M, N, [P,] 3)``.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `ycbcr` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Y is between 16 and 235. This is the color space which is commonly used
|
||||
by video codecs, it is sometimes incorrectly called "YUV"
|
||||
"""
|
||||
arr = ycbcr.copy()
|
||||
arr[..., 0] -= 16
|
||||
arr[..., 1] -= 128
|
||||
arr[..., 2] -= 128
|
||||
return _convert(rgb_from_ycbcr, arr)
|
||||
|
||||
@@ -37,6 +37,10 @@ from skimage.color import (rgb2hsv, hsv2rgb,
|
||||
xyz2luv, luv2xyz,
|
||||
luv2rgb, rgb2luv,
|
||||
lab2lch, lch2lab,
|
||||
rgb2yuv, yuv2rgb,
|
||||
rgb2yiq, yiq2rgb,
|
||||
rgb2ypbpr, ypbpr2rgb,
|
||||
rgb2ycbcr, ycbcr2rgb,
|
||||
guess_spatial_dimensions
|
||||
)
|
||||
|
||||
@@ -438,6 +442,33 @@ class TestColorconv(TestCase):
|
||||
rgb = img_as_float(self.img_rgb[:1, :1, :])
|
||||
return rgb2lab(rgb)[0, 0, :]
|
||||
|
||||
def test_yuv(self):
|
||||
rgb = np.array([[[1.0, 1.0, 1.0]]])
|
||||
assert_array_almost_equal(rgb2yuv(rgb), np.array([[[1, 0, 0]]]))
|
||||
assert_array_almost_equal(rgb2yiq(rgb), np.array([[[1, 0, 0]]]))
|
||||
assert_array_almost_equal(rgb2ypbpr(rgb), np.array([[[1, 0, 0]]]))
|
||||
assert_array_almost_equal(rgb2ycbcr(rgb), np.array([[[235, 128, 128]]]))
|
||||
rgb = np.array([[[0.0, 1.0, 0.0]]])
|
||||
assert_array_almost_equal(rgb2yuv(rgb), np.array([[[0.587, -0.28886916, -0.51496512]]]))
|
||||
assert_array_almost_equal(rgb2yiq(rgb), np.array([[[0.587, -0.27455667, -0.52273617]]]))
|
||||
assert_array_almost_equal(rgb2ypbpr(rgb), np.array([[[0.587, -0.331264, -0.418688]]]))
|
||||
assert_array_almost_equal(rgb2ycbcr(rgb), np.array([[[144.553, 53.797, 34.214]]]))
|
||||
|
||||
def test_yuv_roundtrip(self):
|
||||
img_rgb = img_as_float(self.img_rgb)[::16, ::16]
|
||||
assert_array_almost_equal(yuv2rgb(rgb2yuv(img_rgb)), img_rgb)
|
||||
assert_array_almost_equal(yiq2rgb(rgb2yiq(img_rgb)), img_rgb)
|
||||
assert_array_almost_equal(ypbpr2rgb(rgb2ypbpr(img_rgb)), img_rgb)
|
||||
assert_array_almost_equal(ycbcr2rgb(rgb2ycbcr(img_rgb)), img_rgb)
|
||||
|
||||
def test_rgb2yiq_conversion(self):
|
||||
rgb = img_as_float(self.img_rgb)[::16, ::16]
|
||||
yiq = rgb2yiq(rgb).reshape(-1, 3)
|
||||
gt = np.array([colorsys.rgb_to_yiq(pt[0], pt[1], pt[2])
|
||||
for pt in rgb.reshape(-1, 3)]
|
||||
)
|
||||
assert_almost_equal(yiq, gt, decimal=2)
|
||||
|
||||
|
||||
def test_gray2rgb():
|
||||
x = np.array([0, 0.5, 1])
|
||||
|
||||
Reference in New Issue
Block a user