From 5108d8c346abb72b459bb25f20a37493875c6d38 Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Thu, 29 Nov 2012 12:06:01 -0800 Subject: [PATCH 1/4] Fixed RGB<->XYZ conversion. Now correctly follows the algorithm from EasyRGB. Also fixed a XYZ<->Lab conversion issue by adding a .copy(). --- skimage/color/colorconv.py | 20 ++++++++++++++++---- skimage/color/tests/test_colorconv.py | 6 +++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index 38eab9955e1..123e547c81c 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -379,8 +379,14 @@ def xyz2rgb(xyz): >>> lena_xyz = rgb2xyz(lena) >>> lena_rgb = xyz2rgb(lena_xyz) """ - return _convert(rgb_from_xyz, xyz) - + # Follow the algorithm from http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + # except we don't multiply/divide by 100 in the conversion + arr = _prepare_colorarray(xyz) + arr = _convert(rgb_from_xyz, arr) + mask = arr>0.0031308 + arr[mask] = 1.055 * np.power(arr[mask], 1/2.4) - 0.055 + arr[~mask] *= 12.92 + return arr def rgb2xyz(rgb): """RGB to XYZ color space conversion. @@ -415,7 +421,13 @@ def rgb2xyz(rgb): >>> lena = data.lena() >>> lena_xyz = rgb2xyz(lena) """ - return _convert(xyz_from_rgb, rgb) + # Follow the algorithm from http://www.easyrgb.com/index.php?X=MATH&H=02#text2 + # except we don't multiply/divide by 100 in the conversion + arr = _prepare_colorarray(rgb).copy() + mask = arr>0.04045 + arr[mask] = np.power((arr[mask]+0.055)/1.055, 2.4) + arr[~mask] /= 12.92 + return _convert(xyz_from_rgb, arr) def rgb2rgbcie(rgb): @@ -594,7 +606,7 @@ def xyz2lab(xyz): >>> lena_xyz = rgb2xyz(lena) >>> lena_lab = xyz2lab(lena_xyz) """ - arr = _prepare_colorarray(xyz) + arr = _prepare_colorarray(xyz).copy() # scale by CIE XYZ tristimulus values of the reference white point arr = arr / lab_ref_white diff --git a/skimage/color/tests/test_colorconv.py b/skimage/color/tests/test_colorconv.py index c09c9d22a8b..d1edf47fc55 100644 --- a/skimage/color/tests/test_colorconv.py +++ b/skimage/color/tests/test_colorconv.py @@ -113,10 +113,14 @@ def test_rgb2xyz_error_one_element(self): # XYZ to RGB def test_xyz2rgb_conversion(self): - # only roundtrip test, we checked rgb2xyz above already assert_almost_equal(xyz2rgb(rgb2xyz(self.colbars_array)), self.colbars_array) + # RGB<->XYZ roundtrip on another image + def test_xyz_rgb_roundtrip(self): + img_rgb = img_as_float(self.img_rgb) + assert_array_almost_equal(xyz2rgb(rgb2xyz(img_rgb)), img_rgb) + # RGB to RGB CIE def test_rgb2rgbcie_conversion(self): gt = np.array([[[ 0.1488856 , 0.18288098, 0.19277574], From 43eb33d26b2e775f75058c40ea950a369e709e34 Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Fri, 30 Nov 2012 01:30:59 -0800 Subject: [PATCH 2/4] flake8 on colorconv.py and removed unneeded .copy() --- skimage/color/colorconv.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/skimage/color/colorconv.py b/skimage/color/colorconv.py index 123e547c81c..4186682dae5 100644 --- a/skimage/color/colorconv.py +++ b/skimage/color/colorconv.py @@ -79,7 +79,6 @@ def is_gray(image): return image.ndim == 2 - def convert_colorspace(arr, fromspace, tospace): """Convert an image array to a new color space. @@ -288,8 +287,8 @@ def hsv2rgb(hsv): # From sRGB specification xyz_from_rgb = np.array([[0.412453, 0.357580, 0.180423], - [0.212671, 0.715160, 0.072169], - [0.019334, 0.119193, 0.950227]]) + [0.212671, 0.715160, 0.072169], + [0.019334, 0.119193, 0.950227]]) rgb_from_xyz = linalg.inv(xyz_from_rgb) @@ -379,15 +378,15 @@ def xyz2rgb(xyz): >>> lena_xyz = rgb2xyz(lena) >>> lena_rgb = xyz2rgb(lena_xyz) """ - # Follow the algorithm from http://www.easyrgb.com/index.php?X=MATH&H=01#text1 + # Follow the algorithm from http://www.easyrgb.com/index.php # except we don't multiply/divide by 100 in the conversion - arr = _prepare_colorarray(xyz) - arr = _convert(rgb_from_xyz, arr) - mask = arr>0.0031308 - arr[mask] = 1.055 * np.power(arr[mask], 1/2.4) - 0.055 + arr = _convert(rgb_from_xyz, xyz) + mask = arr > 0.0031308 + arr[mask] = 1.055 * np.power(arr[mask], 1 / 2.4) - 0.055 arr[~mask] *= 12.92 return arr + def rgb2xyz(rgb): """RGB to XYZ color space conversion. @@ -421,11 +420,11 @@ def rgb2xyz(rgb): >>> lena = data.lena() >>> lena_xyz = rgb2xyz(lena) """ - # Follow the algorithm from http://www.easyrgb.com/index.php?X=MATH&H=02#text2 + # Follow the algorithm from http://www.easyrgb.com/index.php # except we don't multiply/divide by 100 in the conversion arr = _prepare_colorarray(rgb).copy() - mask = arr>0.04045 - arr[mask] = np.power((arr[mask]+0.055)/1.055, 2.4) + mask = arr > 0.04045 + arr[mask] = np.power((arr[mask] + 0.055) / 1.055, 2.4) arr[~mask] /= 12.92 return _convert(xyz_from_rgb, arr) @@ -606,7 +605,7 @@ def xyz2lab(xyz): >>> lena_xyz = rgb2xyz(lena) >>> lena_lab = xyz2lab(lena_xyz) """ - arr = _prepare_colorarray(xyz).copy() + arr = _prepare_colorarray(xyz) # scale by CIE XYZ tristimulus values of the reference white point arr = arr / lab_ref_white From b5d1e9f209d143169195514f80b74e1350799b03 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Fri, 30 Nov 2012 15:36:01 +0100 Subject: [PATCH 3/4] FIX quickshift nosetest with different xyz color conversion --- skimage/segmentation/tests/test_quickshift.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/skimage/segmentation/tests/test_quickshift.py b/skimage/segmentation/tests/test_quickshift.py index d43d7559626..a940f859733 100644 --- a/skimage/segmentation/tests/test_quickshift.py +++ b/skimage/segmentation/tests/test_quickshift.py @@ -34,10 +34,10 @@ def test_color(): seg = quickshift(img, random_seed=0, max_dist=30, kernel_size=10, sigma=0) # we expect 4 segments: assert_equal(len(np.unique(seg)), 4) - assert_array_equal(seg[:10, :10], 0) - assert_array_equal(seg[10:, :10], 3) - assert_array_equal(seg[:10, 10:], 1) - assert_array_equal(seg[10:, 10:], 2) + assert_array_equal(seg[:10, :10], 1) + assert_array_equal(seg[10:, :10], 2) + assert_array_equal(seg[:10, 10:], 0) + assert_array_equal(seg[10:, 10:], 3) seg2 = quickshift(img, kernel_size=1, max_dist=2, random_seed=0, convert2lab=False, sigma=0) From 6953785eabc57079650329e7add662edf8c13de8 Mon Sep 17 00:00:00 2001 From: Sergey Karayev Date: Sun, 2 Dec 2012 22:51:16 -0800 Subject: [PATCH 4/4] added rgb2lab test --- skimage/color/tests/test_colorconv.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/skimage/color/tests/test_colorconv.py b/skimage/color/tests/test_colorconv.py index d1edf47fc55..962fa9fc1e4 100644 --- a/skimage/color/tests/test_colorconv.py +++ b/skimage/color/tests/test_colorconv.py @@ -179,11 +179,29 @@ def test_lab2xyz(self): assert_array_almost_equal(lab2xyz(self.lab_array), self.xyz_array, decimal=3) + def test_rgb2lab_brucelindbloom(self): + """ + Test the RGB->Lab conversion by comparing to the calculator on the + authoritative Bruce Lindbloom + [website](http://brucelindbloom.com/index.html?ColorCalculator.html). + """ + # Obtained with D65 white point, sRGB model and gamma + gt_for_colbars = np.array([ + [100,0,0], + [97.1393, -21.5537, 94.4780], + [91.1132, -48.0875, -14.1312], + [87.7347, -86.1827, 83.1793], + [60.3242, 98.2343, -60.8249], + [53.2408, 80.0925, 67.2032], + [32.2970, 79.1875, -107.8602], + [0,0,0]]).T + gt_array = np.swapaxes(gt_for_colbars.reshape(3, 4, 2), 0, 2) + assert_array_almost_equal(rgb2lab(self.colbars_array), gt_array, decimal=2) + def test_lab_rgb_roundtrip(self): img_rgb = img_as_float(self.img_rgb) assert_array_almost_equal(lab2rgb(rgb2lab(img_rgb)), img_rgb) - def test_gray2rgb(): x = np.array([0, 0.5, 1]) assert_raises(ValueError, gray2rgb, x)