1######################################################################## 2## 3## Copyright (C) 2018-2021 The Octave Project Developers 4## 5## See the file COPYRIGHT.md in the top-level directory of this 6## distribution or <https://octave.org/copyright/>. 7## 8## This file is part of Octave. 9## 10## Octave is free software: you can redistribute it and/or modify it 11## under the terms of the GNU General Public License as published by 12## the Free Software Foundation, either version 3 of the License, or 13## (at your option) any later version. 14## 15## Octave is distributed in the hope that it will be useful, but 16## WITHOUT ANY WARRANTY; without even the implied warranty of 17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18## GNU General Public License for more details. 19## 20## You should have received a copy of the GNU General Public License 21## along with Octave; see the file COPYING. If not, see 22## <https://www.gnu.org/licenses/>. 23## 24######################################################################## 25 26## -*- texinfo -*- 27## @deftypefn {} {@var{I} =} rgb2gray (@var{rgb_img}) 28## @deftypefnx {} {@var{gray_map} =} rgb2gray (@var{rgb_map}) 29## Transform an image or colormap from red-green-blue (RGB) color space to 30## a grayscale intensity image. 31## 32## The input may be of class uint8, int8, uint16, int16, single, or double. 33## The output is of the same class as the input. 34## 35## Implementation Note: 36## The grayscale intensity is calculated as 37## 38## @example 39## @group 40## @var{I} = 0.298936*@var{R} + 0.587043*@var{G} + 0.114021*@var{B} 41## @end group 42## @end example 43## 44## @noindent 45## which corresponds to the luminance channel when RGB is translated to 46## @nospell{YIQ} as documented in @url{https://en.wikipedia.org/wiki/YIQ}. 47## @seealso{rgb2hsv, rgb2ind} 48## @end deftypefn 49 50function I = rgb2gray (rgb) 51 52 if (nargin != 1) 53 print_usage (); 54 endif 55 56 is_int = isinteger (rgb); 57 if (is_int) 58 cls = class (rgb); 59 endif 60 [rgb, sz, is_im, is_nd] ... 61 = colorspace_conversion_input_check ("rgb2gray", "RGB", rgb); 62 63 ## Reference matrix for transform from http://en.wikipedia.org/wiki/YIQ. 64 ## Matlab uses this matrix for their conversion with oddly more precision. 65 xform = [0.298936; 0.587043; 0.114021]; 66 I = rgb * xform; 67 68 sz(3) = 1; # grayscale images have 3rd dimension of length 1 69 I = colorspace_conversion_revert (I, sz, is_im, is_nd); 70 71 ## Restore integer class if necessary 72 if (is_int) 73 if (cls(end) == "8") # uint8 or int8 74 I *= 255; 75 if (cls(1) == "i") # int8 76 I -= 128; 77 endif 78 else # uint16 or int16 79 I *= 65535; 80 if (cls(1) == "i") # int16 81 I -= 32768; 82 endif 83 endif 84 I = feval (cls, I); 85 endif 86 87endfunction 88 89 90## Test pure RED, GREEN, BLUE colors 91%!assert (rgb2gray ([1 0 0]), 0.298936) 92%!assert (rgb2gray ([0 1 0]), 0.587043) 93%!assert (rgb2gray ([0 0 1]), 0.114021) 94 95## test tolerance input checking on floats 96%! assert (rgb2gray ([1.5 1 1]), 1.149468, -1.6e-3); 97 98## Test ND input 99%!test 100%! rgb = rand (16, 16, 3, 5); 101%! I = zeros (16, 16, 1, 5); 102%! for i = 1:5 103%! I(:,:,1,i) = rgb2gray (rgb(:,:,:,i)); 104%! endfor 105%! assert (rgb2gray (rgb), I); 106 107## Test output class and size for input images. 108## Most of the tests only test for colormap input. 109 110%!test 111%! I = rgb2gray (rand (10, 10, 3)); 112%! assert (class (I), "double"); 113%! assert (size (I), [10 10]); 114 115%!test 116%! I = rgb2gray (rand (10, 10, 3, "single")); 117%! assert (class (I), "single"); 118%! assert (size (I), [10 10]); 119 120%!test 121%! rgb = (rand (10, 10, 3) * 3 ) - 0.5; # values outside range [0 1] 122%! I = rgb2gray (rgb); 123%! assert (class (I), "double"); 124%! assert (size (I), [10 10]); 125 126%!test 127%! rgb = (rand (10, 10, 3, "single") * 3 ) - 0.5; # values outside range [0 1] 128%! I = rgb2gray (rgb); 129%! assert (class (I), "single"); 130%! assert (size (I), [10 10]); 131 132%!test 133%! I = rgb2gray (randi ([0 255], 10, 10, 3, "uint8")); 134%! assert (class (I), "uint8"); 135%! assert (size (I), [10 10]); 136 137%!test 138%! I = rgb2gray (randi ([0 65535], 10, 10, 3, "uint16")); 139%! assert (class (I), "uint16"); 140%! assert (size (I), [10 10]); 141 142%!test 143%! I = rgb2gray (randi ([-128 127], 10, 10, 3, "int8")); 144%! assert (class (I), "int8"); 145%! assert (size (I), [10 10]); 146 147%!test 148%! I = rgb2gray (randi ([-32768 32767], 10, 10, 3, "int16")); 149%! assert (class (I), "int16"); 150%! assert (size (I), [10 10]); 151 152%!test 153%! rgb_double = reshape ([1 0 0 0 0 1 0 0 0 0 1 0], [2 2 3]); 154%! rgb_uint8 = reshape (uint8 ([255 0 0 0 0 255 0 0 0 0 255 0]), 155%! [2 2 3]); 156%! rgb_int16 = int16 (double (rgb_double * uint16 (65535)) - 32768); 157%! expected = [0.298936, 0.114021; 0.587043, 0.0]; 158%! 159%! assert (rgb2gray (rgb_double), expected); 160%! assert (rgb2gray (rgb_uint8), uint8 (expected*255)); 161%! assert (rgb2gray (single (rgb_double)), single (expected)); 162 163## Test input validation 164%!error rgb2gray () 165%!error rgb2gray (1,2) 166%!error <invalid data type 'cell'> rgb2gray ({1}) 167%!error <RGB must be a colormap or RGB image> rgb2gray (ones (2,2)) 168