Merge pull request #35 from amueller/color_converters_dtype

ENH: Use dtype converters in color space manipulation.
This commit is contained in:
Stefan van der Walt
2011-09-27 14:50:55 -07:00
2 changed files with 38 additions and 30 deletions
+36 -28
View File
@@ -50,6 +50,7 @@ __docformat__ = "restructuredtext en"
import numpy as np
from scipy import linalg
from ..util import dtype
def convert_colorspace(arr, fromspace, tospace):
@@ -87,17 +88,17 @@ def convert_colorspace(arr, fromspace, tospace):
>>> 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}
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())
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())
raise ValueError('tospace needs to be one of %s' % todict.keys())
return todict[tospace](fromdict[fromspace](arr))
@@ -133,7 +134,8 @@ def rgb2hsv(rgb):
Notes
-----
The conversion assumes an input data range of [0, 1] for all color components.
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]_.
@@ -160,26 +162,26 @@ def rgb2hsv(rgb):
# -- S channel
delta = arr.ptp(-1)
out_s = delta / out_v
out_s[delta==0] = 0
out_s[delta == 0] = 0
# -- 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)
out[idx, 0] = 2. + (arr[idx, 2] - arr[idx, 0] ) / delta[idx]
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)
out[idx, 0] = 4. + (arr[idx, 0] - arr[idx, 1] ) / delta[idx]
out_h = (out[:,:,0] / 6.) % 1.
idx = (arr[:, :, 2] == out_v)
out[idx, 0] = 4. + (arr[idx, 0] - arr[idx, 1]) / delta[idx]
out_h = (out[:, :, 0] / 6.) % 1.
# -- output
out[:,:,0] = out_h
out[:,:,1] = out_s
out[:,:,2] = out_v
out[:, :, 0] = out_h
out[:, :, 1] = out_s
out[:, :, 2] = out_v
# remove NaN
out[np.isnan(out)] = 0
@@ -207,7 +209,8 @@ def hsv2rgb(hsv):
Notes
-----
The conversion assumes an input data range of [0, 1] for all color components.
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]_.
@@ -228,12 +231,12 @@ def hsv2rgb(hsv):
"""
arr = _prepare_colorarray(hsv)
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.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(np.uint8) % 6
out = np.choose(hi, [np.dstack((v, t, p)),
@@ -250,14 +253,14 @@ def hsv2rgb(hsv):
# Primaries for the coordinate systems
#---------------------------------------------------------------
cie_primaries = np.array([700, 546.1, 435.8])
sb_primaries = np.array([1./155, 1./190, 1./225]) * 1e5
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 = np.array([[0.412453, 0.357580, 0.180423],
xyz_from_rgb = np.array([[0.412453, 0.357580, 0.180423],
[0.212671, 0.715160, 0.072169],
[0.019334, 0.119193, 0.950227]])
@@ -284,6 +287,7 @@ grey_from_rgb = np.array([[0.2125, 0.7154, 0.0721],
# The conversion functions that make use of the matrices above
#-------------------------------------------------------------
def _convert(matrix, arr):
"""Do the color space conversion.
@@ -296,9 +300,10 @@ def _convert(matrix, arr):
Returns
-------
out : ndarray
out : ndarray, dtype=float
The converted array.
"""
arr = dtype.img_as_float(arr)
arr = _prepare_colorarray(arr)
arr = np.swapaxes(arr, 0, 2)
oldshape = arr.shape
@@ -350,6 +355,7 @@ def xyz2rgb(xyz):
"""
return _convert(rgb_from_xyz, xyz)
def rgb2xyz(rgb):
"""RGB to XYZ color space conversion.
@@ -388,6 +394,7 @@ def rgb2xyz(rgb):
"""
return _convert(xyz_from_rgb, rgb)
def rgb2rgbcie(rgb):
"""RGB to RGB CIE color space conversion.
@@ -422,6 +429,7 @@ def rgb2rgbcie(rgb):
"""
return _convert(rgbcie_from_rgb, rgb)
def rgbcie2rgb(rgbcie):
"""RGB CIE to RGB color space conversion.
@@ -457,6 +465,7 @@ def rgbcie2rgb(rgbcie):
"""
return _convert(rgb_from_rgbcie, rgbcie)
def rgb2grey(rgb):
"""Compute luminance of an RGB image.
@@ -499,4 +508,3 @@ def rgb2grey(rgb):
return _convert(grey_from_rgb, rgb)[..., 0]
rgb2gray = rgb2grey
+2 -2
View File
@@ -37,7 +37,7 @@ class TestColorconv(TestCase):
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]])
[1, 0, 1, 0, 1, 0, 1, 0]]).astype(np.float)
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)
@@ -144,7 +144,7 @@ class TestColorconv(TestCase):
'RGB', 'nokey')
def test_rgb2grey(self):
x = np.array([1, 1, 1]).reshape((1, 1, 3))
x = np.array([1, 1, 1]).reshape((1, 1, 3)).astype(np.float)
g = rgb2grey(x)
assert_array_almost_equal(g, 1)