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{rgb} =} xyz2rgb (@var{xyz}) 19## @deftypefnx {Function File} {@var{rgb_map} =} xyz2rgb (@var{xyz_map}) 20## Transform a colormap or image from CIE XYZ to sRGB color space. 21## 22## A color in the CIE XYZ color space consists of three values X, Y and Z. 23## Those values are designed to be colorimetric, meaning that their values 24## do not depend on the display device hardware. 25## 26## A color in the RGB space consists of red, green, and blue intensities. 27## The output RGB values are calculated to be nonlinear sRGB values 28## with the white point D65. This means the output values are in the 29## colorimetric (sRGB) colorspace. 30## 31## Input values of class single and double are acceptecd. 32## The shape and the class of the input are conserved. 33## 34## note: outside the definition range (0<=R, G, B<=1) this function might 35## return different (but also nonsense) values than Matlab. 36## 37## @seealso{rgb2xyz, rgb2lab, rgb2hsv, rgb2ind, rgb2ntsc} 38## @end deftypefn 39 40## Author: Hartmut Gimpel <hg_code@gmx.de> 41## algorithm taken from the following book: 42## Burger, Burge "Digitale Bildverarbeitung", 3rd edition (2015) 43 44function rgb = xyz2rgb (xyz) 45 46 if (nargin != 1) 47 print_usage (); 48 endif 49 50 [xyz, cls, sz, is_im, is_nd, is_int] ... 51 = colorspace_conversion_input_check ("xyz2rgb", "XYZ", xyz, 1); 52 # only accept single and double inputs because valid xyz values can be >1 53 54 ## transform from CIE XYZ to linear sRGB values with whitepoint D65 55 ## (source of matrix: book of Burger) 56 matrix_xyz2rgb_D65 = ... 57 [3.240479, -1.537150, -0.498535; 58 -0.969256, 1.875992, 0.041556; 59 0.055648, -0.204043, 1.057311]; 60 61 # Matlab uses the following slightly different conversion matrix 62 # matrix_xyz2rgb_D65 = ... 63 # [3.2406, -1.5372, -0.4986; 64 # -0.9689, 1.8758, 0.0415; 65 # 0.0557, -0.2040, 1.0570]; 66 67 rgb_lin = xyz * matrix_xyz2rgb_D65'; 68 69 ## transform from linear sRGB values to non-linear sRGB values 70 ## (modified gamma transform) 71 rgb = rgb_lin; 72 mask = rgb_lin <= 0.0031308; 73 rgb(mask) = 12.92 .* rgb_lin(mask); 74 rgb(! mask) = 1.055 .* (rgb_lin(! mask) .^ (1/2.4)) -0.055; 75 76 rgb = colorspace_conversion_revert (rgb, cls, sz, is_im, is_nd, is_int, 0); 77 78endfunction 79 80## Test pure colors, gray and some other colors 81## (This set of test values is taken from the book by Burger.) 82%!assert (xyz2rgb ([0, 0, 0]), [0 0 0], 1e-3) 83%!assert (xyz2rgb ([0.4125, 0.2127, 0.0193]), [1 0 0], 1e-3) 84%!assert (xyz2rgb ([0.7700, 0.9278, 0.1385]), [1 1 0], 1e-3) 85%!assert (xyz2rgb ([0.3576, 0.7152, 0.1192]), [0 1 0], 1e-3) 86%!assert (xyz2rgb ([0.5380, 0.7873, 1.0694]), [0 1 1], 1e-3) 87%!assert (xyz2rgb ([0.1804, 0.07217, 0.9502]), [0 0 1], 1e-3) 88%!assert (xyz2rgb ([0.5929, 0.28484, 0.9696]), [1 0 1], 1e-3) 89%!assert (xyz2rgb ([0.9505, 1.0000, 1.0888]), [1 1 1], 1e-3) 90%!assert (xyz2rgb ([0.2034, 0.2140, 0.2330]), [0.5 0.5 0.5], 1e-3) 91%!assert (xyz2rgb ([0.2155, 0.1111, 0.0101]), [0.75 0 0], 1e-3) 92%!assert (xyz2rgb ([0.0883, 0.0455, 0.0041]), [0.5 0 0], 1e-3) 93%!assert (xyz2rgb ([0.0210, 0.0108, 0.0010]), [0.25 0 0], 1e-3) 94%!assert (xyz2rgb ([0.5276, 0.3812, 0.2482]), [1 0.5 0.5], 1e-3) 95 96## Test tolarant input checking on floats 97%!assert (xyz2rgb ([1.5 1 1]), [1.5712, 0.7109 0.9717], 1e-3) 98 99%!test 100%! xyz_map = rand (64, 3); 101%! assert (rgb2xyz (xyz2rgb (xyz_map)), xyz_map, 3e-4); 102%!test 103%! xyz_img = rand (64, 64, 3); 104%! assert (rgb2xyz (xyz2rgb (xyz_img)), xyz_img, 3e-4); 105 106## support sparse input (the only useful xyz value with zeros is black) 107%!assert (xyz2rgb (sparse ([0 0 0])), [0 0 0], 1e-3) 108 109## conserve class of single input 110%!assert (class (xyz2rgb (single([0.5 0.5 0.5]))), 'single') 111 112## Test input validation 113%!error xyz2rgb () 114%!error xyz2rgb (1,2) 115%!error <invalid data type 'cell'> xyz2rgb ({1}) 116%!error <XYZ must be a colormap or XYZ image> xyz2rgb (ones (2,2)) 117 118## Test ND input 119%!test 120%! xyz = rand (16, 16, 3, 5); 121%! rgb = zeros (size (xyz)); 122%! for i = 1:5 123%! rgb(:,:,:,i) = xyz2rgb (xyz(:,:,:,i)); 124%! endfor 125%! assert (xyz2rgb (xyz), rgb) 126