From 8dc4d3509e05a71205462d373803f43d1ab18845 Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 00:58:34 -0700 Subject: [PATCH 01/13] Add colorspaces: YUV, YIQ, YPbPr, YCbCr --- skimage/color/colorconv.py | 224 ++++++++++++++++++++++++++++++++++++- 1 file changed, 222 insertions(+), 2 deletions(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index 8f2b82c0..55b011ac 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -124,9 +124,9 @@ 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 +322,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 ]]).T + +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]]).T + +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]]).T + +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]]).T + +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]) @@ -1456,3 +1480,199 @@ 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 + ``(.., ..,[ ..,] 3)``. + + Returns + ------- + out : ndarray + The image in YUV format, in a 3- or 4-D array of shape + ``(.., ..,[ ..,] 3)``. + + Raises + ------ + ValueError + If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 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 + ``(.., ..,[ ..,] 3)``. + + Returns + ------- + out : ndarray + The image in YIQ format, in a 3- or 4-D array of shape + ``(.., ..,[ ..,] 3)``. + + Raises + ------ + ValueError + If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 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 + ``(.., ..,[ ..,] 3)``. + + Returns + ------- + out : ndarray + The image in YIQ format, in a 3- or 4-D array of shape + ``(.., ..,[ ..,] 3)``. + + Raises + ------ + ValueError + If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 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 + ``(.., ..,[ ..,] 3)``. + + Returns + ------- + out : ndarray + The image in YCbCr format, in a 3- or 4-D array of shape + ``(.., ..,[ ..,] 3)``. + + Raises + ------ + ValueError + If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + + Notes + ----- + The destination color space is sometimes also 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 + ``(.., ..,[ ..,] 3)``. + + Returns + ------- + out : ndarray + The image in YIQ format, in a 3- or 4-D array of shape + ``(.., ..,[ ..,] 3)``. + + Raises + ------ + ValueError + If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 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 + ``(.., ..,[ ..,] 3)``. + + Returns + ------- + out : ndarray + The image in RGB format, in a 3- or 4-D array of shape + ``(.., ..,[ ..,] 3)``. + + Raises + ------ + ValueError + If `yiq` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 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 + ``(.., ..,[ ..,] 3)``. + + Returns + ------- + out : ndarray + The image in RGB format, in a 3- or 4-D array of shape + ``(.., ..,[ ..,] 3)``. + + Raises + ------ + ValueError + If `ypbpr` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 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 + ``(.., ..,[ ..,] 3)``. + + Returns + ------- + out : ndarray + The image in RGB format, in a 3- or 4-D array of shape + ``(.., ..,[ ..,] 3)``. + + Raises + ------ + ValueError + If `ycbcr` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + + Notes + ----- + The source color space is sometimes also called "YUV" + """ + arr = ycbcr.copy() + arr[..., 0] -= 16 + arr[..., 1] -= 128 + arr[..., 2] -= 128 + return _convert(rgb_from_ycbcr, arr) From 84c9254180d60caecfa904a5cbf07b82f07c97eb Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 02:43:44 -0700 Subject: [PATCH 02/13] Add to contributors --- CONTRIBUTORS.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index f2a75b33..3bbfe5d0 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -224,3 +224,6 @@ - Evgeni Burovski Adaptation of ImageJ 3D skeletonization algorithm. + +- Alex Izvorski + Color spaces From 1a6cff4f727d25957e16796da6d3cc991d86ec75 Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 02:44:02 -0700 Subject: [PATCH 03/13] Minor changes to docs and formatting --- skimage/color/colorconv.py | 56 ++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index 55b011ac..583c2136 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -1481,6 +1481,7 @@ def _prepare_lab_array(arr): 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. @@ -1488,18 +1489,18 @@ def rgb2yuv(rgb): ---------- rgb : array_like The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Returns ------- out : ndarray The image in YUV format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Raises ------ ValueError - If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + If `rgb` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``. Notes ----- @@ -1507,6 +1508,7 @@ def rgb2yuv(rgb): """ return _convert(yuv_from_rgb, rgb) + def rgb2yiq(rgb): """RGB to YIQ color space conversion. @@ -1514,21 +1516,22 @@ def rgb2yiq(rgb): ---------- rgb : array_like The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Returns ------- out : ndarray The image in YIQ format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Raises ------ ValueError - If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + 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. @@ -1536,21 +1539,22 @@ def rgb2ypbpr(rgb): ---------- rgb : array_like The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Returns ------- out : ndarray The image in YIQ format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Raises ------ ValueError - If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + 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. @@ -1558,18 +1562,18 @@ def rgb2ycbcr(rgb): ---------- rgb : array_like The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Returns ------- out : ndarray The image in YCbCr format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Raises ------ ValueError - If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + If `rgb` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``. Notes ----- @@ -1581,6 +1585,7 @@ def rgb2ycbcr(rgb): arr[..., 2] += 128 return arr + def yuv2rgb(yuv): """RGB to YIQ color space conversion. @@ -1588,21 +1593,22 @@ def yuv2rgb(yuv): ---------- rgb : array_like The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Returns ------- out : ndarray The image in YIQ format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Raises ------ ValueError - If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + 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. @@ -1610,21 +1616,22 @@ def yiq2rgb(yiq): ---------- yiq : array_like The image in YIQ format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Returns ------- out : ndarray The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Raises ------ ValueError - If `yiq` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + 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. @@ -1632,21 +1639,22 @@ def ypbpr2rgb(ypbpr): ---------- ypbpr : array_like The image in YPbPr format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Returns ------- out : ndarray The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Raises ------ ValueError - If `ypbpr` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + 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. @@ -1654,18 +1662,18 @@ def ycbcr2rgb(ycbcr): ---------- ycbcr : array_like The image in YCbCr format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Returns ------- out : ndarray The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. + ``(M, N, [P,] 3)``. Raises ------ ValueError - If `ycbcr` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. + If `ycbcr` is not a 3- or 4-D array of shape ``(M, N, [P,] 3)``. Notes ----- From 1c0d0efdd1f22a1a62796644360f2c47bc48a9aa Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 02:44:20 -0700 Subject: [PATCH 04/13] YUV colorspace unit tests --- skimage/color/tests/test_colorconv.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/skimage/color/tests/test_colorconv.py b/skimage/color/tests/test_colorconv.py index 96057e3b..4072cd9e 100644 --- a/skimage/color/tests/test_colorconv.py +++ b/skimage/color/tests/test_colorconv.py @@ -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,20 @@ 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([[[0.9998, -0.0193, -0.0122]]]), decimal=4) + assert_array_almost_equal(rgb2yiq(rgb), np.array([[[0.9998, 0.0003, -0.0228]]]), decimal=4) + assert_array_almost_equal(rgb2ypbpr(rgb), np.array([[[0.9998, -0.0221, -0.0099]]]), decimal=4) + assert_array_almost_equal(rgb2ycbcr(rgb), np.array([[[234.9561, 123.0547, 125.7861]]]), decimal=4) + + def test_yuv_roundtrip(self): + img_rgb = img_as_float(self.img_rgb) + 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_gray2rgb(): x = np.array([0, 0.5, 1]) From dc552f03aabae8096b99b1d388a76c3cab5919b3 Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 02:51:17 -0700 Subject: [PATCH 05/13] Change notes in the docs --- skimage/color/colorconv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index 583c2136..a9429f66 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -1577,7 +1577,7 @@ def rgb2ycbcr(rgb): Notes ----- - The destination color space is sometimes also called "YUV" + 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 @@ -1677,7 +1677,7 @@ def ycbcr2rgb(ycbcr): Notes ----- - The source color space is sometimes also called "YUV" + 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 From 53bbfe64ade13b1392082201eaf9de3b226f51a6 Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 03:18:47 -0700 Subject: [PATCH 06/13] Add imports --- skimage/color/__init__.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/skimage/color/__init__.py b/skimage/color/__init__.py index d68332f4..80d8a03a 100644 --- a/skimage/color/__init__.py +++ b/skimage/color/__init__.py @@ -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', From aad78f7ad31e129b28cf267bfd09739f7cfaaa0b Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 03:19:28 -0700 Subject: [PATCH 07/13] Fix conversion matrixes shouldn't be transposed --- skimage/color/colorconv.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index a9429f66..d8a67565 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -324,25 +324,25 @@ gray_from_rgb = np.array([[0.2125, 0.7154, 0.0721], yuv_from_rgb = np.array([[ 0.299 , 0.587 , 0.114 ], [-0.14714119, -0.28886916, 0.43601035 ], - [ 0.61497538, -0.51496512, -0.10001026 ]]).T + [ 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]]).T + [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]]).T + [ 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]]).T + [ 112.0 , -93.786, -18.214]]) rgb_from_ycbcr = linalg.inv(ycbcr_from_rgb) From 0bc241dbb894437aa49b214fb50d29f55552c492 Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 03:19:46 -0700 Subject: [PATCH 08/13] Fix tests, more tests --- skimage/color/tests/test_colorconv.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/skimage/color/tests/test_colorconv.py b/skimage/color/tests/test_colorconv.py index 4072cd9e..f9947501 100644 --- a/skimage/color/tests/test_colorconv.py +++ b/skimage/color/tests/test_colorconv.py @@ -444,18 +444,26 @@ class TestColorconv(TestCase): def test_yuv(self): rgb = np.array([[[1.0, 1.0, 1.0]]]) - assert_array_almost_equal(rgb2yuv(rgb), np.array([[[0.9998, -0.0193, -0.0122]]]), decimal=4) - assert_array_almost_equal(rgb2yiq(rgb), np.array([[[0.9998, 0.0003, -0.0228]]]), decimal=4) - assert_array_almost_equal(rgb2ypbpr(rgb), np.array([[[0.9998, -0.0221, -0.0099]]]), decimal=4) - assert_array_almost_equal(rgb2ycbcr(rgb), np.array([[[234.9561, 123.0547, 125.7861]]]), decimal=4) + 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]]])) def test_yuv_roundtrip(self): - img_rgb = img_as_float(self.img_rgb) + 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]) From 1da3d4d23a6a221b592feb38d34262bff2dc4322 Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 23:30:58 -0700 Subject: [PATCH 09/13] Add one more set of unit tests for rgb 0,1,0 --- skimage/color/tests/test_colorconv.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/skimage/color/tests/test_colorconv.py b/skimage/color/tests/test_colorconv.py index f9947501..106eabee 100644 --- a/skimage/color/tests/test_colorconv.py +++ b/skimage/color/tests/test_colorconv.py @@ -448,6 +448,11 @@ class TestColorconv(TestCase): 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] From 1c6cc3c478963e58c723f3b147149f3e15bc1db3 Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 23:31:22 -0700 Subject: [PATCH 10/13] More specific description --- CONTRIBUTORS.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 3bbfe5d0..7318049a 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -226,4 +226,4 @@ Adaptation of ImageJ 3D skeletonization algorithm. - Alex Izvorski - Color spaces + Color spaces for YUV and related spaces From d0bf9d614fd92cc4e3abbcd87b6ffad1dc714d5a Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 23:35:15 -0700 Subject: [PATCH 11/13] Add to authors in file --- skimage/color/colorconv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index d8a67565..989fa356 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -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 @@ -330,7 +331,7 @@ 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]]) + [0.21153661, -0.52273617, 0.31119955]]).T rgb_from_yiq = linalg.inv(yiq_from_rgb) From 8abe35797241cd8e496c7c0fb0dbc4964a51845a Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sat, 30 Apr 2016 23:50:18 -0700 Subject: [PATCH 12/13] Fix one more transpose --- skimage/color/colorconv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index 989fa356..4eb83743 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -331,7 +331,7 @@ 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]]).T + [0.21153661, -0.52273617, 0.31119955]]) rgb_from_yiq = linalg.inv(yiq_from_rgb) From 88bd0c4864cc1f42b43abb5084a894a98d3c2609 Mon Sep 17 00:00:00 2001 From: Alex Izvorski Date: Sun, 1 May 2016 14:37:17 -0700 Subject: [PATCH 13/13] Wrap long lines --- skimage/color/colorconv.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index 4eb83743..a16b5584 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -125,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, 'YUV': yuv2rgb, 'YIQ': yiq2rgb, 'YPbPr': ypbpr2rgb, 'YCbCr': ycbcr2rgb } + 'XYZ': xyz2rgb, 'YUV': yuv2rgb, 'YIQ': yiq2rgb, + 'YPbPr': ypbpr2rgb, 'YCbCr': ycbcr2rgb } todict = {'RGB': lambda im: im, 'HSV': rgb2hsv, 'RGB CIE': rgb2rgbcie, - 'XYZ': rgb2xyz, 'YUV': rgb2yuv, 'YIQ': rgb2yiq, 'YPbPr': rgb2ypbpr, 'YCbCr': rgb2ycbcr } + 'XYZ': rgb2xyz, 'YUV': rgb2yuv, 'YIQ': rgb2yiq, + 'YPbPr': rgb2ypbpr, 'YCbCr': rgb2ycbcr } fromspace = fromspace.upper() tospace = tospace.upper() @@ -1505,7 +1507,8 @@ def rgb2yuv(rgb): 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) + 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) @@ -1578,7 +1581,8 @@ def rgb2ycbcr(rgb): 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" + 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 @@ -1678,7 +1682,8 @@ def ycbcr2rgb(ycbcr): 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" + 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