diff --git a/scikits/image/color/colorconv.py b/scikits/image/color/colorconv.py new file mode 100644 index 00000000..cd3c3b63 --- /dev/null +++ b/scikits/image/color/colorconv.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +:author: Nicolas Pinto, 2009 +:license: modified BSD +""" + +from __future__ import division + +__all__ = ["rgb2hsv"] +__docformat__ = "restructuredtext en" + +import numpy as np + +def rgb2hsv(rgb): + + """ + RGB to HSV color space conversion + """ + + 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") + out = np.empty_like(arr) + + # -- V channel + out_v = arr.max(-1) + + # -- S channel + delta = arr.ptp(-1) + out_s = delta / out_v + out_s[delta==0] = 0 + + # -- H channel + # red is max + 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] + + # 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. + + # -- output + out[:,:,0] = out_h + out[:,:,1] = out_s + out[:,:,2] = out_v + + # 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 new file mode 100644 index 00000000..11cff099 --- /dev/null +++ b/scikits/image/color/tests/test_colorconv.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +:author: Nicolas Pinto, 2009 +:license: modified BSD +""" + +from os import path + +import numpy as np +from numpy.testing import * + +from scikits.image.io import imread +from scikits.image.color import ( + rgb2hsv, + ) + +from scikits.image import data + +import colorsys + +class TestColorconv(TestCase): + + img_rgb = imread(path.join(data.MY_PATH, 'color.png')) + img_grayscale = imread(path.join(data.MY_PATH, 'camera.png')) + + def test_rgb2hsv_conversion(self): + rgb = self.img_rgb.astype("float32")[::16, ::16] + hsv = rgb2hsv(rgb).reshape(-1, 3) + # ground truth from colorsys + gt = np.array([colorsys.rgb_to_hsv(pt[0], pt[1], pt[2]) + for pt in rgb.reshape(-1, 3)] + ) + assert_almost_equal(hsv, gt) + + def test_rgb2hsv_error_grayscale(self): + self.assertRaises(ValueError, rgb2hsv, self.img_grayscale) + + 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]]) + +if __name__ == "__main__": + run_module_suite() +