1## Copyright (C) 2015 Hartmut Gimpel
2##
3## This program is free software; you can redistribute it and/or
4## modify it under the terms of the GNU General Public License as
5## published by the Free Software Foundation; either version 3 of the
6## License, or (at your option) any later version.
7##
8## This program is distributed in the hope that it will be useful, but
9## WITHOUT ANY WARRANTY; without even the implied warranty of
10## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11## General Public License for more details.
12##
13## You should have received a copy of the GNU General Public License
14## along with this program; if not, see
15## <http:##www.gnu.org/licenses/>.
16
17## -*- texinfo -*-
18## @deftypefn  {Function File} {@var{lab} =} rgb2lab (@var{rgb})
19## @deftypefnx {Function File} {@var{lab_map} =} rgb2lab (@var{rgb_map})
20## Transform a colormap or image from sRGB to CIE L*a*b* color space.
21##
22## A color in the RGB space consists of red, green, and blue intensities.
23## The input RGB values are interpreted as nonlinear sRGB values
24## with the white point D65. This means the input values are assumed to
25## be in the colorimetric (sRGB) colorspace.
26##
27## A color in the CIE L*a*b* (or CIE Lab) space consists of lightness L* and
28## two color-opponent dimensions a* and b*. The whitepoint is taken as D65.
29## The CIE L*a*b* colorspace is also a colorimetric colorspace. It is designed
30## to incorporate the human perception of color differences.
31##
32## Input values of class double, single, uint8 or uint16 are accepted.
33## Output class is generally of type double, only input type single will
34## result in an output type of single. The shape of the input is
35## conserved.
36##
37## note: This function returns slightly different values than the Matlab
38##            version. But it has a better "round trip accuracy" (<2e-5)
39##            for RGB -> Lab -> RGB.
40##
41## @seealso{lab2rgb, rgb2xyz, rgb2hsv, rgb2ind, rgb2ntsc}
42## @end deftypefn
43
44## Author: Hartmut Gimpel <hg_code@gmx.de>
45## algorithm taken from the following book:
46## Burger, Burge "Digitale Bildverarbeitung", 3rd edition  (2015)
47
48function lab = rgb2lab (rgb)
49
50  if (nargin != 1)
51    print_usage ();
52  endif
53
54  [rgb, cls, sz, is_im, is_nd, is_int] ...
55    = colorspace_conversion_input_check ("rgb2lab", "RGB", rgb, 0);
56
57  ## transform from non-linear sRGB values to CIE XYZ values
58  xyz = rgb2xyz (rgb);
59
60  ## transform from CIE XYZ values to CIE L*a*b* values
61  lab = xyz2lab (xyz);
62
63  # always return values of type double for Matlab compatibility (exception: type single)
64  lab = colorspace_conversion_revert (lab, cls, sz, is_im, is_nd, is_int, 1);
65
66endfunction
67
68
69## Test pure colors, gray and some other colors
70## (This set of test values is taken from the book by Burger.)
71%!assert (rgb2lab ([0 0 0]), [0, 0, 0], 1e-2)
72%!assert (rgb2lab ([1 0 0]), [53.24, 80.09, 67.20], 1e-2)
73%!assert (rgb2lab ([1 1 0]), [97.14, -21.55, 94.48], 1e-2)
74%!assert (rgb2lab ([0 1 0]), [87.74, -86.18, 83.18], 1e-2)
75%!assert (rgb2lab ([0 1 1]), [91.11, -48.09, -14.13], 1e-2)
76%!assert (rgb2lab ([0 0 1]), [32.30, 79.19, -107.86], 1e-2)
77%!assert (rgb2lab ([1 0 1]), [60.32, 98.24, -60.83], 1e-2)
78%!assert (rgb2lab ([1 1 1]), [100, 0.00, 0.00], 1e-2)
79%!assert (rgb2lab ([0.5 0.5 0.5]), [53.39, 0.00, 0.00], 1e-2)
80%!assert (rgb2lab ([0.75 0 0]), [39.77, 64.51, 54.13], 1e-2)
81%!assert (rgb2lab ([0.5 0 0]), [25.42, 47.91, 37.91], 1e-2)
82%!assert (rgb2lab ([0.25 0 0]), [9.66, 29.68, 15.24], 1e-2)
83%!assert (rgb2lab ([1 0.5 0.5]), [68.11, 48.39, 22.83], 1e-2)
84
85## Test tolarant input checking on floats
86%!assert (rgb2lab ([1.5 1 1]), [111.47, 43.42, 17.98], 1e-2)
87
88%!test
89%! rgb_map = rand (64, 3);
90%! assert (lab2rgb (rgb2lab (rgb_map)), rgb_map, 2e-5);
91
92%!test
93%! rgb_img = rand (64, 64, 3);
94%! assert (lab2rgb (rgb2lab (rgb_img)), rgb_img, 2e-5);
95
96## support sparse input
97%!assert (rgb2lab (sparse ([0 0 1])), sparse ([32.30, 79.19, -107.86]), 1e-2)
98%!assert (rgb2lab (sparse ([0 1 1])), sparse ([91.11, -48.09, -14.13]), 1e-2)
99%!assert (rgb2lab (sparse ([1 1 1])), sparse ([100, 0.00, 0.00]), 1e-2)
100
101## support integer input (and double output)
102%!assert (rgb2lab (uint8([255 255 255])), [100, 0.00, 0.00], 1e-2)
103
104## conserve class of single input
105%!assert (class (rgb2lab (single([1 1 1]))), 'single')
106
107## Test input validation
108%!error rgb2lab ()
109%!error rgb2lab (1,2)
110%!error <invalid data type 'cell'> rgb2lab ({1})
111%!error <RGB must be a colormap or RGB image> rgb2lab (ones (2,2))
112
113## Test ND input
114%!test
115%! rgb = rand (16, 16, 3, 5);
116%! lab = zeros (size (rgb));
117%! for i = 1:5
118%!   lab(:,:,:,i) = rgb2lab (rgb(:,:,:,i));
119%! endfor
120%! assert (rgb2lab (rgb), lab)
121