From 032d0cd785a979da59e90c1064a868cd252618e4 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Oct 2009 10:38:44 +0200 Subject: [PATCH 01/16] Change import to form used everywhere else. --- scikits/image/color/tests/test_colorconv.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scikits/image/color/tests/test_colorconv.py b/scikits/image/color/tests/test_colorconv.py index 1d8ecc17..3dbc027d 100644 --- a/scikits/image/color/tests/test_colorconv.py +++ b/scikits/image/color/tests/test_colorconv.py @@ -6,7 +6,7 @@ :license: modified BSD """ -from os import path +import os.path import numpy as np from numpy.testing import * @@ -22,8 +22,8 @@ import colorsys class TestColorconv(TestCase): - img_rgb = imread(path.join(data_dir, 'color.png')) - img_grayscale = imread(path.join(data_dir, 'camera.png')) + img_rgb = imread(os.path.join(data_dir, 'color.png')) + img_grayscale = imread(os.path.join(data_dir, 'camera.png')) def test_rgb2hsv_conversion(self): rgb = self.img_rgb.astype("float32")[::16, ::16] @@ -34,7 +34,7 @@ class TestColorconv(TestCase): ) assert_almost_equal(hsv, gt) - def test_rgb2hsv_error_grayscale(self): + def test_rgb2hsv_error_grayscale(self): self.assertRaises(ValueError, rgb2hsv, self.img_grayscale) def test_rgb2hsv_error_one_element(self): From 6c80fa6a5514f71999f80b768ebffbdf604d617a Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Oct 2009 10:48:09 +0200 Subject: [PATCH 02/16] Add documentation for rgb2hsv. --- scikits/image/color/colorconv.py | 36 +++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index cd3c3b63..c12791cf 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -14,9 +14,31 @@ __docformat__ = "restructuredtext en" import numpy as np def rgb2hsv(rgb): + """RGB to HSV color space conversion. - """ - RGB to HSV color space conversion + Parameters + ---------- + rgb : ndarray + The image in RGB format, in a 3-D array of shape (.., .., 3). + + Returns + ------- + out : ndarray + The image in HSV format, in a 3-D array of shape (.., .., 3). + + Raises + ------ + ValueError + If `rgb` is not a 3-D array of shape (.., .., 3). + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_hsv = color.rgb2hsv(lena) """ if type(rgb) != np.ndarray: @@ -25,10 +47,10 @@ def rgb2hsv(rgb): if rgb.ndim != 3 or rgb.shape[2] != 3: msg = "the input array 'rgb' must be have a shape == (.,.,3))" raise ValueError, msg - + arr = rgb.astype("float32") out = np.empty_like(arr) - + # -- V channel out_v = arr.max(-1) @@ -39,15 +61,15 @@ def rgb2hsv(rgb): # -- H channel # red is max - idx = (arr[:,:,0] == out_v) + idx = (arr[:,:,0] == out_v) out[idx, 0] = (arr[idx, 1] - arr[idx, 2]) / delta[idx] # green is max - idx = (arr[:,:,1] == out_v) + idx = (arr[:,:,1] == out_v) out[idx, 0] = 2. + (arr[idx, 2] - arr[idx, 0] ) / delta[idx] # blue is max - idx = (arr[:,:,2] == out_v) + idx = (arr[:,:,2] == out_v) out[idx, 0] = 4. + (arr[idx, 0] - arr[idx, 1] ) / delta[idx] out_h = (out[:,:,0] / 6.) % 1. From 1657a4d1b83bd61af4093357c224da07f8f5549f Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Oct 2009 14:34:00 +0200 Subject: [PATCH 03/16] Implement hsv2rgb. --- scikits/image/color/colorconv.py | 60 ++++++++++++++++++++- scikits/image/color/tests/test_colorconv.py | 24 +++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index c12791cf..9130738a 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -8,7 +8,7 @@ from __future__ import division -__all__ = ["rgb2hsv"] +__all__ = ['rgb2hsv', 'hsv2rgb'] __docformat__ = "restructuredtext en" import numpy as np @@ -83,3 +83,61 @@ def rgb2hsv(rgb): return out + +def hsv2rgb(hsv): + """HSV to RGB color space conversion. + + Parameters + ---------- + hsv : ndarray + The image in HSV format, in a 3-D array of shape (.., .., 3). + + Returns + ------- + out : ndarray + The image in RGB format, in a 3-D array of shape (.., .., 3). + + Raises + ------ + ValueError + If `hsv` is not a 3-D array of shape (.., .., 3). + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_hsv = rgb2hsv(lena) + >>> lena_rgb = hsv2rgb(lena_hsv) + """ + + if type(hsv) != np.ndarray: + raise TypeError, "the input array 'hsv' must be a numpy.ndarray" + + if hsv.ndim != 3 or hsv.shape[2] != 3: + msg = "the input array 'hsv' must be have a shape == (.,.,3))" + raise ValueError, msg + + arr = hsv.astype("float32") + + hi = np.floor(arr[:,:,0] * 6) + f = arr[:,:,0] * 6 - hi + p = arr[:,:,2] * (1 - arr[:,:,1]) + q = arr[:,:,2] * (1 - f * arr[:,:,1]) + t = arr[:,:,2] * (1 - (1 - f) * arr[:,:,1]) + v = arr[:,:,2] + + hi = np.dstack([hi, hi, hi]).astype("uint8") % 6 + out = np.choose(hi, [np.dstack((v, t, p)), + np.dstack((q, v, p)), + np.dstack((p, v, t)), + np.dstack((p, q, v)), + np.dstack((t, p, v)), + np.dstack((v, p, q))]) + + # remove NaN + out[np.isnan(out)] = 0 + + return out diff --git a/scikits/image/color/tests/test_colorconv.py b/scikits/image/color/tests/test_colorconv.py index 3dbc027d..f40dcec5 100644 --- a/scikits/image/color/tests/test_colorconv.py +++ b/scikits/image/color/tests/test_colorconv.py @@ -14,17 +14,20 @@ from numpy.testing import * from scikits.image.io import imread from scikits.image.color import ( rgb2hsv, + hsv2rgb, ) from scikits.image import data_dir import colorsys + class TestColorconv(TestCase): img_rgb = imread(os.path.join(data_dir, 'color.png')) img_grayscale = imread(os.path.join(data_dir, 'camera.png')) + # RGB to HSV def test_rgb2hsv_conversion(self): rgb = self.img_rgb.astype("float32")[::16, ::16] hsv = rgb2hsv(rgb).reshape(-1, 3) @@ -43,6 +46,27 @@ class TestColorconv(TestCase): def test_rgb2hsv_error_list(self): self.assertRaises(TypeError, rgb2hsv, [self.img_rgb[0,0]]) + + # HSV to RGB + def test_hsv2rgb_conversion(self): + rgb = self.img_rgb.astype("float32")[::16, ::16] + # create HSV image with colorsys + hsv = np.array([colorsys.rgb_to_hsv(pt[0], pt[1], pt[2]) + for pt in rgb.reshape(-1, 3)]).reshape(rgb.shape) + # convert back to RGB and compare with original. + # float32 -> relative precision about 1e-6 + assert_almost_equal(rgb, hsv2rgb(hsv), decimal=4) + + def test_hsv2rgb_error_grayscale(self): + self.assertRaises(ValueError, hsv2rgb, self.img_grayscale) + + def test_hsv2rgb_error_one_element(self): + self.assertRaises(ValueError, hsv2rgb, self.img_rgb[0,0]) + + def test_hsv2rgb_error_list(self): + self.assertRaises(TypeError, hsv2rgb, [self.img_rgb[0,0]]) + + if __name__ == "__main__": run_module_suite() From 6097565337daf0efbb5fee23608a79b932c23f0d Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Oct 2009 14:45:33 +0200 Subject: [PATCH 04/16] Add note on loss of precision. --- scikits/image/color/colorconv.py | 18 ++++++++++++++++++ scikits/image/color/tests/test_colorconv.py | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index 9130738a..065f1d31 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -31,6 +31,15 @@ def rgb2hsv(rgb): ValueError If `rgb` is not a 3-D array of shape (.., .., 3). + Notes + ----- + Conversion between RGB and HSV color spaces results in some loss of + precision, due to integer arithmetic and rounding [1]_. + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/HSL_and_HSV + Examples -------- >>> import os @@ -102,6 +111,15 @@ def hsv2rgb(hsv): ValueError If `hsv` is not a 3-D array of shape (.., .., 3). + Notes + ----- + Conversion between RGB and HSV color spaces results in some loss of + precision, due to integer arithmetic and rounding [1]_. + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/HSL_and_HSV + Examples -------- >>> import os diff --git a/scikits/image/color/tests/test_colorconv.py b/scikits/image/color/tests/test_colorconv.py index f40dcec5..67f641bb 100644 --- a/scikits/image/color/tests/test_colorconv.py +++ b/scikits/image/color/tests/test_colorconv.py @@ -54,7 +54,7 @@ class TestColorconv(TestCase): hsv = np.array([colorsys.rgb_to_hsv(pt[0], pt[1], pt[2]) for pt in rgb.reshape(-1, 3)]).reshape(rgb.shape) # convert back to RGB and compare with original. - # float32 -> relative precision about 1e-6 + # relative precision for RGB -> HSV roundtrip is about 1e-6 assert_almost_equal(rgb, hsv2rgb(hsv), decimal=4) def test_hsv2rgb_error_grayscale(self): From 844f14bca0dd07aeb7cbdb140142f891dc22cbab Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Oct 2009 15:14:21 +0200 Subject: [PATCH 05/16] Extract the type and shape checks into a common function. --- scikits/image/color/colorconv.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index 065f1d31..4016c65b 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -13,6 +13,18 @@ __docformat__ = "restructuredtext en" import numpy as np + +def _prepare_colorarray(arr, dtype="float32"): + """Check the shape of the array, and give it the requested type""" + if type(arr) != np.ndarray: + raise TypeError, "the input array must be a numpy.ndarray" + + if arr.ndim != 3 or arr.shape[2] != 3: + msg = "the input array must be have a shape == (.,.,3))" + raise ValueError, msg + + return arr.astype(dtype) + def rgb2hsv(rgb): """RGB to HSV color space conversion. @@ -49,15 +61,7 @@ def rgb2hsv(rgb): >>> lena = imread(os.path.join(data_dir, 'lena.png')) >>> lena_hsv = color.rgb2hsv(lena) """ - - if type(rgb) != np.ndarray: - raise TypeError, "the input array 'rgb' must be a numpy.ndarray" - - if rgb.ndim != 3 or rgb.shape[2] != 3: - msg = "the input array 'rgb' must be have a shape == (.,.,3))" - raise ValueError, msg - - arr = rgb.astype("float32") + arr = _prepare_colorarray(rgb) out = np.empty_like(arr) # -- V channel @@ -130,15 +134,7 @@ def hsv2rgb(hsv): >>> lena_hsv = rgb2hsv(lena) >>> lena_rgb = hsv2rgb(lena_hsv) """ - - if type(hsv) != np.ndarray: - raise TypeError, "the input array 'hsv' must be a numpy.ndarray" - - if hsv.ndim != 3 or hsv.shape[2] != 3: - msg = "the input array 'hsv' must be have a shape == (.,.,3))" - raise ValueError, msg - - arr = hsv.astype("float32") + arr = _prepare_colorarray(hsv) hi = np.floor(arr[:,:,0] * 6) f = arr[:,:,0] * 6 - hi From 1a4ae96024aed2826e13cbf712397f3b32233bf5 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Oct 2009 18:57:31 +0200 Subject: [PATCH 06/16] Add RGB to XYZ bidi conversion. --- scikits/image/color/colorconv.py | 76 ++++++++++++++++++++- scikits/image/color/tests/test_colorconv.py | 50 +++++++++++++- 2 files changed, 121 insertions(+), 5 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index 4016c65b..28444898 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -1,17 +1,31 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -""" -:author: Nicolas Pinto, 2009 +"""Functions for converting between color spaces. + +Supported color spaces +---------------------- +- RGB +- HSV +- XYZ + +Authors +------- +- rgb2hsv was written by Nicolas Pinto +- hsv2rgb was written by Ralf Gommers +- other functions were originally written by Travis Oliphant and adapted by + Ralf Gommers + :license: modified BSD """ from __future__ import division -__all__ = ['rgb2hsv', 'hsv2rgb'] +__all__ = ['rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb'] __docformat__ = "restructuredtext en" import numpy as np +from scipy import linalg def _prepare_colorarray(arr, dtype="float32"): @@ -155,3 +169,59 @@ def hsv2rgb(hsv): out[np.isnan(out)] = 0 return out + + +#--------------------------------------------------------------- +# Primaries for the coordinate systems +#--------------------------------------------------------------- +cie_primaries = [700, 546.1, 435.8] +sb_primaries = [1./155 * 1e5, 1./190 * 1e5, 1./225 * 1e5] + +#--------------------------------------------------------------- +# Matrices that define conversion between different color spaces +#--------------------------------------------------------------- + +# From sRGB specification +xyz_from_rgb = [[0.412453, 0.357580, 0.180423], + [0.212671, 0.715160, 0.072169], + [0.019334, 0.119193, 0.950227]] + +rgb_from_xyz = linalg.inv(xyz_from_rgb) + +#------------------------------------------------------------- +# The conversion functions that make use of the matrices above +#------------------------------------------------------------- + +def _convert(matrix, arr): + """Do the color space conversion. + + Parameters + ---------- + matrix : array_like + The 3x3 matrix to use. + arr : ndarray + The input array. + + Returns + ------- + out : ndarray + The converted array. + """ + arr = _prepare_colorarray(arr) + arr = np.swapaxes(arr, 0, 2) + oldshape = arr.shape + arr = np.reshape(arr, (3, -1)) + out = np.dot(matrix, arr) + out.shape = oldshape + out = np.swapaxes(out, 2, 0) + + return out + + +def xyz2rgb(xyz): + return _convert(rgb_from_xyz, xyz) + +def rgb2xyz(rgb): + return _convert(xyz_from_rgb, rgb) + + diff --git a/scikits/image/color/tests/test_colorconv.py b/scikits/image/color/tests/test_colorconv.py index 67f641bb..ff36f2f0 100644 --- a/scikits/image/color/tests/test_colorconv.py +++ b/scikits/image/color/tests/test_colorconv.py @@ -1,8 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -""" -:author: Nicolas Pinto, 2009 +"""Tests for color conversion functions. + +Authors +------- +- the rgb2hsv test was written by Nicolas Pinto, 2009 +- other tests written by Ralf Gommers, 2009 + :license: modified BSD """ @@ -15,6 +20,8 @@ from scikits.image.io import imread from scikits.image.color import ( rgb2hsv, hsv2rgb, + rgb2xyz, + xyz2rgb ) from scikits.image import data_dir @@ -27,6 +34,13 @@ class TestColorconv(TestCase): img_rgb = imread(os.path.join(data_dir, 'color.png')) img_grayscale = imread(os.path.join(data_dir, 'camera.png')) + colbars = np.array([[1, 1, 0, 0, 1, 1, 0, 0], + [1, 1, 1, 1, 0, 0, 0, 0], + [1, 0, 1, 0, 1, 0, 1, 0]]) + colbars_array = np.swapaxes(colbars.reshape(3, 4, 2), 0, 2) + colbars_point75 = colbars * 0.75 + colbars_point75_array = np.swapaxes(colbars_point75.reshape(3, 4, 2), 0, 2) + # RGB to HSV def test_rgb2hsv_conversion(self): rgb = self.img_rgb.astype("float32")[::16, ::16] @@ -67,6 +81,38 @@ class TestColorconv(TestCase): self.assertRaises(TypeError, hsv2rgb, [self.img_rgb[0,0]]) + # RGB to XYZ + def test_rgb2xyz_conversion(self): + gt = np.array([[[ 0.950456, 1. , 1.088754], + [ 0.538003, 0.787329, 1.06942 ], + [ 0.592876, 0.28484 , 0.969561], + [ 0.180423, 0.072169, 0.950227]], + [[ 0.770033, 0.927831, 0.138527], + [ 0.35758 , 0.71516 , 0.119193], + [ 0.412453, 0.212671, 0.019334], + [ 0. , 0. , 0. ]]]) + + assert_almost_equal(rgb2xyz(self.colbars_array), gt) + + # stop repeating the "raises" checks for all other functions that are + # implemented with color._convert() + def test_rgb2xyz_error_grayscale(self): + self.assertRaises(ValueError, rgb2xyz, self.img_grayscale) + + def test_rgb2xyz_error_one_element(self): + self.assertRaises(ValueError, rgb2xyz, self.img_rgb[0,0]) + + def test_rgb2xyz_error_list(self): + self.assertRaises(TypeError, rgb2xyz, [self.img_rgb[0,0]]) + + + # 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) + + if __name__ == "__main__": run_module_suite() From 5de50145897a49fc36edd377ea1cfab34b4cc6a7 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Oct 2009 19:39:00 +0200 Subject: [PATCH 07/16] Add docstrings for rgb2xyz and xyz2rgb. --- scikits/image/color/colorconv.py | 71 ++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index 28444898..f6f485b3 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -219,9 +219,80 @@ def _convert(matrix, arr): def xyz2rgb(xyz): + """XYZ to RGB color space conversion. + + Parameters + ---------- + xyz : ndarray + The image in XYZ format, in a 3-D array of shape (.., .., 3). + + Returns + ------- + out : ndarray + The image in RGB format, in a 3-D array of shape (.., .., 3). + + Raises + ------ + ValueError + If `xyz` is not a 3-D array of shape (.., .., 3). + + Notes + ----- + The CIE XYZ color space is derived from the CIE RGB color space. Note + however that this function converts to sRGB. + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/CIE_1931_color_space + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_xyz = rgb2xyz(lena) + >>> lena_rgb = xyz2rgb(lena_hsv) + """ return _convert(rgb_from_xyz, xyz) def rgb2xyz(rgb): + """RGB to XYZ color space conversion. + + Parameters + ---------- + rgb : ndarray + The image in RGB format, in a 3-D array of shape (.., .., 3). + + Returns + ------- + out : ndarray + The image in XYZ format, in a 3-D array of shape (.., .., 3). + + Raises + ------ + ValueError + If `rgb` is not a 3-D array of shape (.., .., 3). + + Notes + ----- + The CIE XYZ color space is derived from the CIE RGB color space. Note + however that this function converts from sRGB. + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/CIE_1931_color_space + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_xyz = rgb2xyz(lena) + """ return _convert(xyz_from_rgb, rgb) From 94f5eeac25c8c96380d56e25b44c0b283d9589d9 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 20 Oct 2009 12:10:33 +0200 Subject: [PATCH 08/16] Add description of the API to the module docstring. This is not all implemented yet, mostly a description of what I want it to look like in the end. This required figuring out the right matrices based on some of the random ones in Travis' code. Should not be too difficult. --- scikits/image/color/colorconv.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index f6f485b3..39337b12 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -3,6 +3,15 @@ """Functions for converting between color spaces. +The "central" color space in this module is RGB, more specifically the linear +sRGB color space using D65 as a white-point (IEC 61966-2-1). This represents a +standard monitor (w/o gamma correction). + +The API consists of functions to convert to and from RGB as defined above, as +well as a generic function to convert to and from any supported color space +(which is done through RGB in most cases). + + Supported color spaces ---------------------- - RGB @@ -188,6 +197,14 @@ xyz_from_rgb = [[0.412453, 0.357580, 0.180423], rgb_from_xyz = linalg.inv(xyz_from_rgb) +# Matrices from Jain. TODO: find complete reference. +xyz_from_rgbcie = [[0.490, 0.310, 0.200], + [0.177, 0.813, 0.011], + [0.000, 0.010, 0.990]] + +rgbcie_from_xyz = linalg.inv(xyz_from_rgbcie) + + #------------------------------------------------------------- # The conversion functions that make use of the matrices above #------------------------------------------------------------- From cf379160224e155dd1ddc0ae23a1c862df8a4e32 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 20 Oct 2009 13:12:18 +0200 Subject: [PATCH 09/16] Convert matrix lists to arrays, add RGB CIE color space. --- scikits/image/color/colorconv.py | 89 ++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index 39337b12..4b3ed5f4 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -16,6 +16,7 @@ Supported color spaces ---------------------- - RGB - HSV +- RGB CIE - XYZ Authors @@ -183,27 +184,31 @@ def hsv2rgb(hsv): #--------------------------------------------------------------- # Primaries for the coordinate systems #--------------------------------------------------------------- -cie_primaries = [700, 546.1, 435.8] -sb_primaries = [1./155 * 1e5, 1./190 * 1e5, 1./225 * 1e5] +cie_primaries = np.array([700, 546.1, 435.8]) +sb_primaries = np.array([1./155, 1./190, 1./225]) * 1e5 #--------------------------------------------------------------- # Matrices that define conversion between different color spaces #--------------------------------------------------------------- # From sRGB specification -xyz_from_rgb = [[0.412453, 0.357580, 0.180423], - [0.212671, 0.715160, 0.072169], - [0.019334, 0.119193, 0.950227]] +xyz_from_rgb = np.array([[0.412453, 0.357580, 0.180423], + [0.212671, 0.715160, 0.072169], + [0.019334, 0.119193, 0.950227]]) rgb_from_xyz = linalg.inv(xyz_from_rgb) -# Matrices from Jain. TODO: find complete reference. -xyz_from_rgbcie = [[0.490, 0.310, 0.200], - [0.177, 0.813, 0.011], - [0.000, 0.010, 0.990]] +# From http://en.wikipedia.org/wiki/CIE_1931_color_space +# Note: Travis' code did not have the divide by 0.17697 +xyz_from_rgbcie = np.array([[0.49, 0.31, 0.20], + [0.17697, 0.81240, 0.01063], + [0.00, 0.01, 0.99]]) / 0.17697 rgbcie_from_xyz = linalg.inv(xyz_from_rgbcie) +# construct matrices to and from rgb: +rgbcie_from_rgb = np.dot(rgbcie_from_xyz, xyz_from_rgb) +rgb_from_rgbcie = np.dot(rgb_from_xyz, xyz_from_rgb) #------------------------------------------------------------- # The conversion functions that make use of the matrices above @@ -312,4 +317,70 @@ def rgb2xyz(rgb): """ return _convert(xyz_from_rgb, rgb) +def rgb2rgbcie(rgb): + """RGB to RGB CIE color space conversion. + + Parameters + ---------- + rgb : ndarray + The image in RGB format, in a 3-D array of shape (.., .., 3). + + Returns + ------- + out : ndarray + The image in RGB CIE format, in a 3-D array of shape (.., .., 3). + + Raises + ------ + ValueError + If `rgb` is not a 3-D array of shape (.., .., 3). + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/CIE_1931_color_space + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_rgbcie = rgb2rgbcie(lena) + """ + return _convert(rgbcie_from_rgb, rgb) + +def rgbcie2rgb(rgbcie): + """RGB CIE to RGB color space conversion. + + Parameters + ---------- + rgbcie : ndarray + The image in RGB CIE format, in a 3-D array of shape (.., .., 3). + + Returns + ------- + out : ndarray + The image in RGB format, in a 3-D array of shape (.., .., 3). + + Raises + ------ + ValueError + If `rgbcie` is not a 3-D array of shape (.., .., 3). + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/CIE_1931_color_space + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_rgbcie = rgb2rgbcie(lena) + >>> lena_rgb = rgbcie2rgb(lena_hsv) + """ + return _convert(rgb_from_rgbcie, rgbcie) From 57b73a5f5346115e116f810144188472d97aff58 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 21 Oct 2009 18:10:31 +0200 Subject: [PATCH 10/16] Add NTSC color space. Also a typo in rgbcie fixed. --- scikits/image/color/colorconv.py | 85 ++++++++++++++++++++- scikits/image/color/tests/test_colorconv.py | 51 +++++++++++-- 2 files changed, 129 insertions(+), 7 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index 4b3ed5f4..e431e083 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -18,6 +18,7 @@ Supported color spaces - HSV - RGB CIE - XYZ +- NTSC Authors ------- @@ -31,7 +32,8 @@ Authors from __future__ import division -__all__ = ['rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb'] +__all__ = ['rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb', 'rgb2rgbcie', 'rgbcie2rgb', + 'rgb2ntsc', 'ntsc2rgb'] __docformat__ = "restructuredtext en" import numpy as np @@ -208,7 +210,19 @@ rgbcie_from_xyz = linalg.inv(xyz_from_rgbcie) # construct matrices to and from rgb: rgbcie_from_rgb = np.dot(rgbcie_from_xyz, xyz_from_rgb) -rgb_from_rgbcie = np.dot(rgb_from_xyz, xyz_from_rgb) +rgb_from_rgbcie = np.dot(rgb_from_xyz, xyz_from_rgbcie) + +# from Travis' code. "Matrices from Jain". TODO: find reference. +ntsc_from_xyz = np.array([[1.910, -0.533, -0.288], + [-0.985, 2.000, -0.028], + [0.058, -0.118, 0.896]]) + +xyz_from_ntsc = linalg.inv(ntsc_from_xyz) + +# construct matrices to and from rgb: +ntsc_from_rgb = np.dot(ntsc_from_xyz, xyz_from_rgb) +rgb_from_ntsc = np.dot(rgb_from_xyz, xyz_from_ntsc) + #------------------------------------------------------------- # The conversion functions that make use of the matrices above @@ -384,3 +398,70 @@ def rgbcie2rgb(rgbcie): """ return _convert(rgb_from_rgbcie, rgbcie) +def rgb2ntsc(rgb): + """RGB to NTSC color space conversion. + + Parameters + ---------- + rgb : ndarray + The image in RGB format, in a 3-D array of shape (.., .., 3). + + Returns + ------- + out : ndarray + The image in NTSC format, in a 3-D array of shape (.., .., 3). + + Raises + ------ + ValueError + If `rgb` is not a 3-D array of shape (.., .., 3). + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/NTSC + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_ntsc = rgb2ntsc(lena) + """ + return _convert(ntsc_from_rgb, rgb) + +def ntsc2rgb(ntsc): + """NTSC to RGB color space conversion. + + Parameters + ---------- + ntsc : ndarray + The image in NTSC format, in a 3-D array of shape (.., .., 3). + + Returns + ------- + out : ndarray + The image in RGB format, in a 3-D array of shape (.., .., 3). + + Raises + ------ + ValueError + If `ntsc` is not a 3-D array of shape (.., .., 3). + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/NTSC + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_ntsc = rgb2ntsc(lena) + >>> lena_rgb = ntsc2rgb(lena_hsv) + """ + return _convert(rgb_from_ntsc, ntsc) + diff --git a/scikits/image/color/tests/test_colorconv.py b/scikits/image/color/tests/test_colorconv.py index ff36f2f0..842e1acc 100644 --- a/scikits/image/color/tests/test_colorconv.py +++ b/scikits/image/color/tests/test_colorconv.py @@ -18,10 +18,10 @@ from numpy.testing import * from scikits.image.io import imread from scikits.image.color import ( - rgb2hsv, - hsv2rgb, - rgb2xyz, - xyz2rgb + rgb2hsv, hsv2rgb, + rgb2xyz, xyz2rgb, + rgb2rgbcie, rgbcie2rgb, + rgb2ntsc, ntsc2rgb ) from scikits.image import data_dir @@ -91,7 +91,6 @@ class TestColorconv(TestCase): [ 0.35758 , 0.71516 , 0.119193], [ 0.412453, 0.212671, 0.019334], [ 0. , 0. , 0. ]]]) - assert_almost_equal(rgb2xyz(self.colbars_array), gt) # stop repeating the "raises" checks for all other functions that are @@ -113,6 +112,48 @@ class TestColorconv(TestCase): self.colbars_array) + # RGB to RGB CIE + def test_rgb2rgbcie_conversion(self): + gt = np.array([[[ 0.1488856 , 0.18288098, 0.19277574], + [ 0.01163224, 0.16649536, 0.18948516], + [ 0.12259182, 0.03308008, 0.17298223], + [-0.01466154, 0.01669446, 0.16969164]], + [[ 0.16354714, 0.16618652, 0.0230841 ], + [ 0.02629378, 0.1498009 , 0.01979351], + [ 0.13725336, 0.01638562, 0.00329059], + [ 0. , 0. , 0. ]]]) + assert_almost_equal(rgb2rgbcie(self.colbars_array), gt) + + + # RGB CIE to RGB + def test_rgbcie2rgb_conversion(self): + # only roundtrip test, we checked rgb2rgbcie above already + assert_almost_equal(rgbcie2rgb(rgb2rgbcie(self.colbars_array)), + self.colbars_array) + + + # RGB to NTSC + def test_rgb2ntsc_conversion(self): + gt = np.array([[[ 0.96880981, 1.03331573, 0.91265003], + [ 0.29994641, 1.01478128, 0.89649967], + [ 0.70133987, -0.04145057, 0.86950234], + [ 0.03247648, -0.05998501, 0.85335198]], + [[ 0.93633333, 1.09330074, 0.05929805], + [ 0.26746994, 1.0747663 , 0.04314769], + [ 0.66886339, 0.01853444, 0.01615036], + [ 0. , 0. , 0. ]]]) + assert_almost_equal(rgb2ntsc(self.colbars_array), gt) + + + # NTSC to RGB + def test_ntsc2rgb_conversion(self): + # only roundtrip test, we checked rgb2ntsc above already + assert_almost_equal(ntsc2rgb(rgb2ntsc(self.colbars_array)), + self.colbars_array) + + + + if __name__ == "__main__": run_module_suite() From 64f65e01607c3e26011843b3713945759a9a9812 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 22 Oct 2009 01:14:02 +0200 Subject: [PATCH 11/16] Clean up the colorconv module docstring. --- scikits/image/color/colorconv.py | 38 +++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index e431e083..aa757ddd 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -4,8 +4,9 @@ """Functions for converting between color spaces. The "central" color space in this module is RGB, more specifically the linear -sRGB color space using D65 as a white-point (IEC 61966-2-1). This represents a -standard monitor (w/o gamma correction). +sRGB color space using D65 as a white-point [1]_. This represents a +standard monitor (w/o gamma correction). For a good FAQ on color spaces see +[2]_. The API consists of functions to convert to and from RGB as defined above, as well as a generic function to convert to and from any supported color space @@ -14,20 +15,31 @@ well as a generic function to convert to and from any supported color space Supported color spaces ---------------------- -- RGB -- HSV -- RGB CIE -- XYZ -- NTSC +* RGB : Red Green Blue. + Here the sRGB standard [1]_. +* HSV : Hue, Saturation, Value. + Uniquely defined when related to sRGB [3]_. +* RGB CIE : Red Green Blue. + The original RGB CIE standard from 1931 [4]_. Primary colors are 700 nm + (red), 546.1 nm (blue) and 435.8 nm (green). +* XYZ CIE : XYZ + Derived from the RGB CIE color space. Chosen such that + ``x == y == z == 1/3`` at the whitepoint, and all color matching + functions are greater than zero everywhere. +* NTSC -Authors -------- -- rgb2hsv was written by Nicolas Pinto -- hsv2rgb was written by Ralf Gommers -- other functions were originally written by Travis Oliphant and adapted by - Ralf Gommers +:author: Nicolas Pinto (rgb2hsv) +:author: Ralf Gommers (hsv2rgb) +:author: Travis Oliphant (XYZ and RGB CIE functions) :license: modified BSD + +References +---------- +.. [1] Official specification of sRGB, IEC 61966-2-1:1999. +.. [2] http://www.poynton.com/ColorFAQ.html +.. [3] http://en.wikipedia.org/wiki/HSL_and_HSV +.. [4] http://en.wikipedia.org/wiki/CIE_1931_color_space """ from __future__ import division From d7b49ef950065c22c5d07c78e07da670a4d65525 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 22 Oct 2009 01:18:02 +0200 Subject: [PATCH 12/16] Remove NTSC color space. Reason: it was not clear exactly what this was and what it was for. The color space used for NTSC video is YIQ, not RGB NTSC. --- scikits/image/color/colorconv.py | 85 +-------------------- scikits/image/color/tests/test_colorconv.py | 25 +----- 2 files changed, 4 insertions(+), 106 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index aa757ddd..effb7dc6 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -26,7 +26,6 @@ Supported color spaces Derived from the RGB CIE color space. Chosen such that ``x == y == z == 1/3`` at the whitepoint, and all color matching functions are greater than zero everywhere. -* NTSC :author: Nicolas Pinto (rgb2hsv) :author: Ralf Gommers (hsv2rgb) @@ -44,8 +43,9 @@ References from __future__ import division -__all__ = ['rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb', 'rgb2rgbcie', 'rgbcie2rgb', - 'rgb2ntsc', 'ntsc2rgb'] +__all__ = ['rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb', 'rgb2rgbcie', + 'rgbcie2rgb'] + __docformat__ = "restructuredtext en" import numpy as np @@ -224,17 +224,6 @@ rgbcie_from_xyz = linalg.inv(xyz_from_rgbcie) rgbcie_from_rgb = np.dot(rgbcie_from_xyz, xyz_from_rgb) rgb_from_rgbcie = np.dot(rgb_from_xyz, xyz_from_rgbcie) -# from Travis' code. "Matrices from Jain". TODO: find reference. -ntsc_from_xyz = np.array([[1.910, -0.533, -0.288], - [-0.985, 2.000, -0.028], - [0.058, -0.118, 0.896]]) - -xyz_from_ntsc = linalg.inv(ntsc_from_xyz) - -# construct matrices to and from rgb: -ntsc_from_rgb = np.dot(ntsc_from_xyz, xyz_from_rgb) -rgb_from_ntsc = np.dot(rgb_from_xyz, xyz_from_ntsc) - #------------------------------------------------------------- # The conversion functions that make use of the matrices above @@ -409,71 +398,3 @@ def rgbcie2rgb(rgbcie): >>> lena_rgb = rgbcie2rgb(lena_hsv) """ return _convert(rgb_from_rgbcie, rgbcie) - -def rgb2ntsc(rgb): - """RGB to NTSC color space conversion. - - Parameters - ---------- - rgb : ndarray - The image in RGB format, in a 3-D array of shape (.., .., 3). - - Returns - ------- - out : ndarray - The image in NTSC format, in a 3-D array of shape (.., .., 3). - - Raises - ------ - ValueError - If `rgb` is not a 3-D array of shape (.., .., 3). - - References - ---------- - .. [1] http://en.wikipedia.org/wiki/NTSC - - Examples - -------- - >>> import os - >>> from scikits.image import data_dir - >>> from scikits.image.io import imread - - >>> lena = imread(os.path.join(data_dir, 'lena.png')) - >>> lena_ntsc = rgb2ntsc(lena) - """ - return _convert(ntsc_from_rgb, rgb) - -def ntsc2rgb(ntsc): - """NTSC to RGB color space conversion. - - Parameters - ---------- - ntsc : ndarray - The image in NTSC format, in a 3-D array of shape (.., .., 3). - - Returns - ------- - out : ndarray - The image in RGB format, in a 3-D array of shape (.., .., 3). - - Raises - ------ - ValueError - If `ntsc` is not a 3-D array of shape (.., .., 3). - - References - ---------- - .. [1] http://en.wikipedia.org/wiki/NTSC - - Examples - -------- - >>> import os - >>> from scikits.image import data_dir - >>> from scikits.image.io import imread - - >>> lena = imread(os.path.join(data_dir, 'lena.png')) - >>> lena_ntsc = rgb2ntsc(lena) - >>> lena_rgb = ntsc2rgb(lena_hsv) - """ - return _convert(rgb_from_ntsc, ntsc) - diff --git a/scikits/image/color/tests/test_colorconv.py b/scikits/image/color/tests/test_colorconv.py index 842e1acc..5fcfe053 100644 --- a/scikits/image/color/tests/test_colorconv.py +++ b/scikits/image/color/tests/test_colorconv.py @@ -20,8 +20,7 @@ from scikits.image.io import imread from scikits.image.color import ( rgb2hsv, hsv2rgb, rgb2xyz, xyz2rgb, - rgb2rgbcie, rgbcie2rgb, - rgb2ntsc, ntsc2rgb + rgb2rgbcie, rgbcie2rgb ) from scikits.image import data_dir @@ -132,28 +131,6 @@ class TestColorconv(TestCase): self.colbars_array) - # RGB to NTSC - def test_rgb2ntsc_conversion(self): - gt = np.array([[[ 0.96880981, 1.03331573, 0.91265003], - [ 0.29994641, 1.01478128, 0.89649967], - [ 0.70133987, -0.04145057, 0.86950234], - [ 0.03247648, -0.05998501, 0.85335198]], - [[ 0.93633333, 1.09330074, 0.05929805], - [ 0.26746994, 1.0747663 , 0.04314769], - [ 0.66886339, 0.01853444, 0.01615036], - [ 0. , 0. , 0. ]]]) - assert_almost_equal(rgb2ntsc(self.colbars_array), gt) - - - # NTSC to RGB - def test_ntsc2rgb_conversion(self): - # only roundtrip test, we checked rgb2ntsc above already - assert_almost_equal(ntsc2rgb(rgb2ntsc(self.colbars_array)), - self.colbars_array) - - - - if __name__ == "__main__": run_module_suite() From caede7762b9a7a23ac80d051dfed3871c93a1de4 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 22 Oct 2009 11:45:57 +0200 Subject: [PATCH 13/16] Add a function to convert from any color space directly to any other space. --- scikits/image/color/colorconv.py | 54 ++++++++++++++++++++- scikits/image/color/tests/test_colorconv.py | 22 ++++++++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index effb7dc6..8fccf6ba 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -43,8 +43,8 @@ References from __future__ import division -__all__ = ['rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb', 'rgb2rgbcie', - 'rgbcie2rgb'] +__all__ = ['convert_colorspace', 'rgb2hsv', 'hsv2rgb', 'rgb2xyz', 'xyz2rgb', + 'rgb2rgbcie', 'rgbcie2rgb'] __docformat__ = "restructuredtext en" @@ -52,6 +52,56 @@ import numpy as np from scipy import linalg +def convert_colorspace(arr, fromspace, tospace): + """Convert an image array to a new color space. + + Parameters + ---------- + arr : ndarray + The image to convert. + fromspace : str + The color space to convert from. Valid color space strings are + ['RGB', 'HSV', 'RGB CIE', 'XYZ']. Value may also be specified as lower + case. + tospace : str + The color space to convert to. Valid color space strings are + ['RGB', 'HSV', 'RGB CIE', 'XYZ']. Value may also be specified as lower + case. + + Returns + ------- + newarr : ndarray + The converted image. + + Notes + ----- + Conversion occurs through the "central" RGB color space, i.e. conversion + from XYZ to HSV is implemented as XYZ -> RGB -> HSV instead of directly. + + Examples + -------- + >>> import os + >>> from scikits.image import data_dir + >>> from scikits.image.io import imread + + >>> lena = imread(os.path.join(data_dir, 'lena.png')) + >>> lena_hsv = convert_colorspace(lena, 'RGB', 'HSV') + """ + fromdict = {'RGB':lambda im: im, 'HSV':hsv2rgb, 'RGB CIE':rgbcie2rgb, + 'XYZ':xyz2rgb} + todict = {'RGB':lambda im:im, 'HSV':rgb2hsv, 'RGB CIE':rgb2rgbcie, + 'XYZ':rgb2xyz} + + fromspace = fromspace.upper() + tospace = tospace.upper() + if not fromspace in fromdict.keys(): + raise ValueError, 'fromspace needs to be one of %s'%fromdict.keys() + if not tospace in todict.keys(): + raise ValueError, 'tospace needs to be one of %s'%todict.keys() + + return todict[tospace](fromdict[fromspace](arr)) + + def _prepare_colorarray(arr, dtype="float32"): """Check the shape of the array, and give it the requested type""" if type(arr) != np.ndarray: diff --git a/scikits/image/color/tests/test_colorconv.py b/scikits/image/color/tests/test_colorconv.py index 5fcfe053..9473b456 100644 --- a/scikits/image/color/tests/test_colorconv.py +++ b/scikits/image/color/tests/test_colorconv.py @@ -20,7 +20,8 @@ from scikits.image.io import imread from scikits.image.color import ( rgb2hsv, hsv2rgb, rgb2xyz, xyz2rgb, - rgb2rgbcie, rgbcie2rgb + rgb2rgbcie, rgbcie2rgb, + convert_colorspace ) from scikits.image import data_dir @@ -130,6 +131,25 @@ class TestColorconv(TestCase): assert_almost_equal(rgbcie2rgb(rgb2rgbcie(self.colbars_array)), self.colbars_array) + def test_convert_colorspace(self): + colspaces = ['HSV', 'RGB CIE', 'XYZ'] + colfuncs_from = [hsv2rgb, rgbcie2rgb, xyz2rgb] + colfuncs_to = [rgb2hsv, rgb2rgbcie, rgb2xyz] + + assert_almost_equal(convert_colorspace(self.colbars_array, 'RGB', + 'RGB'), self.colbars_array) + for i, space in enumerate(colspaces): + gt = colfuncs_from[i](self.colbars_array) + assert_almost_equal(convert_colorspace(self.colbars_array, space, + 'RGB'), gt) + gt = colfuncs_to[i](self.colbars_array) + assert_almost_equal(convert_colorspace(self.colbars_array, 'RGB', + space), gt) + + self.assertRaises(ValueError, convert_colorspace, self.colbars_array, + 'nokey', 'XYZ') + self.assertRaises(ValueError, convert_colorspace, self.colbars_array, + 'RGB', 'nokey') if __name__ == "__main__": run_module_suite() From 91b0d6380012e0731a89a6bab7552fd97f127ed6 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 23 Oct 2009 10:35:27 +0200 Subject: [PATCH 14/16] Remove explicit checks of image type and NaN, and correct dtype descriptor. --- scikits/image/color/colorconv.py | 29 +++++++++------------ scikits/image/color/tests/test_colorconv.py | 9 ------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index 8fccf6ba..d0ac2fbf 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -57,7 +57,7 @@ def convert_colorspace(arr, fromspace, tospace): Parameters ---------- - arr : ndarray + arr : array_like The image to convert. fromspace : str The color space to convert from. Valid color space strings are @@ -102,10 +102,9 @@ def convert_colorspace(arr, fromspace, tospace): return todict[tospace](fromdict[fromspace](arr)) -def _prepare_colorarray(arr, dtype="float32"): - """Check the shape of the array, and give it the requested type""" - if type(arr) != np.ndarray: - raise TypeError, "the input array must be a numpy.ndarray" +def _prepare_colorarray(arr, dtype=np.float32): + """Check the shape of the array, and give it the requested type.""" + arr = np.asanyarray(arr) if arr.ndim != 3 or arr.shape[2] != 3: msg = "the input array must be have a shape == (.,.,3))" @@ -113,12 +112,13 @@ def _prepare_colorarray(arr, dtype="float32"): return arr.astype(dtype) + def rgb2hsv(rgb): """RGB to HSV color space conversion. Parameters ---------- - rgb : ndarray + rgb : array_like The image in RGB format, in a 3-D array of shape (.., .., 3). Returns @@ -190,7 +190,7 @@ def hsv2rgb(hsv): Parameters ---------- - hsv : ndarray + hsv : array_like The image in HSV format, in a 3-D array of shape (.., .., 3). Returns @@ -231,7 +231,7 @@ def hsv2rgb(hsv): t = arr[:,:,2] * (1 - (1 - f) * arr[:,:,1]) v = arr[:,:,2] - hi = np.dstack([hi, hi, hi]).astype("uint8") % 6 + hi = np.dstack([hi, hi, hi]).astype(np.uint8) % 6 out = np.choose(hi, [np.dstack((v, t, p)), np.dstack((q, v, p)), np.dstack((p, v, t)), @@ -239,9 +239,6 @@ def hsv2rgb(hsv): np.dstack((t, p, v)), np.dstack((v, p, q))]) - # remove NaN - out[np.isnan(out)] = 0 - return out @@ -286,7 +283,7 @@ def _convert(matrix, arr): ---------- matrix : array_like The 3x3 matrix to use. - arr : ndarray + arr : array_like The input array. Returns @@ -310,7 +307,7 @@ def xyz2rgb(xyz): Parameters ---------- - xyz : ndarray + xyz : array_like The image in XYZ format, in a 3-D array of shape (.., .., 3). Returns @@ -349,7 +346,7 @@ def rgb2xyz(rgb): Parameters ---------- - rgb : ndarray + rgb : array_like The image in RGB format, in a 3-D array of shape (.., .., 3). Returns @@ -387,7 +384,7 @@ def rgb2rgbcie(rgb): Parameters ---------- - rgb : ndarray + rgb : array_like The image in RGB format, in a 3-D array of shape (.., .., 3). Returns @@ -420,7 +417,7 @@ def rgbcie2rgb(rgbcie): Parameters ---------- - rgbcie : ndarray + rgbcie : array_like The image in RGB CIE format, in a 3-D array of shape (.., .., 3). Returns diff --git a/scikits/image/color/tests/test_colorconv.py b/scikits/image/color/tests/test_colorconv.py index 9473b456..ac861555 100644 --- a/scikits/image/color/tests/test_colorconv.py +++ b/scikits/image/color/tests/test_colorconv.py @@ -57,9 +57,6 @@ class TestColorconv(TestCase): def test_rgb2hsv_error_one_element(self): self.assertRaises(ValueError, rgb2hsv, self.img_rgb[0,0]) - def test_rgb2hsv_error_list(self): - self.assertRaises(TypeError, rgb2hsv, [self.img_rgb[0,0]]) - # HSV to RGB def test_hsv2rgb_conversion(self): @@ -77,9 +74,6 @@ class TestColorconv(TestCase): def test_hsv2rgb_error_one_element(self): self.assertRaises(ValueError, hsv2rgb, self.img_rgb[0,0]) - def test_hsv2rgb_error_list(self): - self.assertRaises(TypeError, hsv2rgb, [self.img_rgb[0,0]]) - # RGB to XYZ def test_rgb2xyz_conversion(self): @@ -101,9 +95,6 @@ class TestColorconv(TestCase): def test_rgb2xyz_error_one_element(self): self.assertRaises(ValueError, rgb2xyz, self.img_rgb[0,0]) - def test_rgb2xyz_error_list(self): - self.assertRaises(TypeError, rgb2xyz, [self.img_rgb[0,0]]) - # XYZ to RGB def test_xyz2rgb_conversion(self): From a93e5f9e6c195985385f936b281654619e601eb4 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 23 Oct 2009 10:51:53 +0200 Subject: [PATCH 15/16] Add color spaces work to contributors file. --- CONTRIBUTORS.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 0f56ce4d..45836e7f 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -17,5 +17,5 @@ OpenCV functions and better OSX library loader - Ralf Gommers - Image IO and plots in documentation + Image IO, color spaces and plots in documentation From 04f01ffce4994452809cd58276ccf7ba3173217a Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 23 Oct 2009 15:06:27 +0200 Subject: [PATCH 16/16] Add note on assumed data range. --- scikits/image/color/colorconv.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py index d0ac2fbf..d7c5f4d2 100644 --- a/scikits/image/color/colorconv.py +++ b/scikits/image/color/colorconv.py @@ -133,6 +133,8 @@ def rgb2hsv(rgb): Notes ----- + The conversion assumes an input data range of [0, 1] for all color components. + Conversion between RGB and HSV color spaces results in some loss of precision, due to integer arithmetic and rounding [1]_. @@ -205,6 +207,8 @@ def hsv2rgb(hsv): Notes ----- + The conversion assumes an input data range of [0, 1] for all color components. + Conversion between RGB and HSV color spaces results in some loss of precision, due to integer arithmetic and rounding [1]_.