changeset 24610:3ad53e4793fc

rgb2gray: New function to convert RGB images to grayscale images. * scripts/image/rgb2gray.m: New function. * scripts/image/module.mk: Add function to build system. * NEWS: Announce function. * image.txi: Add DOCSTRING to manual. * ind2gray.m, rgb2hsv.m, rgb2ind.m: Replace references to rgb2ntsc in documentation with rgb2gray.
author Rik <rik@octave.org>
date Tue, 16 Jan 2018 21:14:22 -0800
parents 55f61915701b
children afbef2f579c9
files NEWS doc/interpreter/image.txi scripts/image/ind2gray.m scripts/image/module.mk scripts/image/rgb2gray.m scripts/image/rgb2hsv.m scripts/image/rgb2ind.m
diffstat 7 files changed, 153 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Tue Jan 16 17:21:47 2018 -0800
+++ b/NEWS	Tue Jan 16 21:14:22 2018 -0800
@@ -239,6 +239,7 @@
       openvar
       quad2d
       repelem
+      rgb2gray
       rticks
       thetaticks
       vecnorm
--- a/doc/interpreter/image.txi	Tue Jan 16 17:21:47 2018 -0800
+++ b/doc/interpreter/image.txi	Tue Jan 16 21:14:22 2018 -0800
@@ -258,6 +258,8 @@
 
 @DOCSTRING(hsv2rgb)
 
+@DOCSTRING(rgb2gray)
+
 @DOCSTRING(rgb2ntsc)
 
 @DOCSTRING(ntsc2rgb)
--- a/scripts/image/ind2gray.m	Tue Jan 16 17:21:47 2018 -0800
+++ b/scripts/image/ind2gray.m	Tue Jan 16 21:14:22 2018 -0800
@@ -30,7 +30,7 @@
 ##
 ## Implementation Note: There are several ways of converting colors to
 ## grayscale intensities.  This functions uses the luminance value obtained
-## from @code{rgb2ntsc} which is @code{I = 0.299*R + 0.587*G + 0.114*B}.
+## from @code{rgb2gray} which is @code{I = 0.299*R + 0.587*G + 0.114*B}.
 ## Other possibilities include the value component from @code{rgb2hsv} or
 ## using a single color channel from @code{ind2rgb}.
 ## @seealso{gray2ind, ind2rgb}
--- a/scripts/image/module.mk	Tue Jan 16 17:21:47 2018 -0800
+++ b/scripts/image/module.mk	Tue Jan 16 21:14:22 2018 -0800
@@ -54,6 +54,7 @@
   %reldir%/rgb2hsv.m \
   %reldir%/rgb2ind.m \
   %reldir%/rgb2ntsc.m \
+  %reldir%/rgb2gray.m \
   %reldir%/rgbplot.m \
   %reldir%/spinmap.m \
   %reldir%/spring.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/rgb2gray.m	Tue Jan 16 21:14:22 2018 -0800
@@ -0,0 +1,146 @@
+## Copyright (C) 2018 Rik Wehbring
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{I} =} rgb2gray (@var{rgb_img})
+## @deftypefnx {} {@var{gray_map} =} rgb2gray (@var{rgb_map})
+## Transform an image or colormap from red-green-blue (RGB) color space to
+## a grayscale intensity image.
+## 
+## The input may be of class uint8, uint16, single, or double.  The output is
+## of the same class as the input.
+##
+## Implementation Note:
+## The grayscale intensity is calculated as 
+##
+## @example
+## @group
+## @var{I} = 0.2989*@var{R} + 0.5870*@var{G} + 0.1140*@var{B}
+## @end group
+## @end example
+##
+## @noindent
+## which corresponds to the luminance channel when RGB is translated to YIQ
+## as documented in @url{http://en.wikipedia.org/wiki/YIQ}.
+## @seealso{rgb2hsv, rgb2ind}
+## @end deftypefn
+
+function I = rgb2gray (rgb)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  [rgb, sz, is_im, is_nd] ...
+    = colorspace_conversion_input_check ("rgb2gray", "RGB", rgb);
+
+  ## Reference matrix for transform from http://en.wikipedia.org/wiki/YIQ and
+  ## truncated to 4 significant figures.  Matlab uses this matrix for their
+  ## conversion.
+  xform = [0.2989; 0.5870; 0.1140];
+
+  ## Note that if the input is of class single, we also return an image
+  ## of class single.  This is Matlab incompatible by design, since
+  ## Matlab always returning class double, is a Matlab bug (see patch #8709)
+  I = rgb * xform;
+
+  ## Restore size if necessary
+  if (is_im)
+    if (is_nd)
+      I = reshape (I, [sz(1), sz(2), sz(4)]);
+    else
+      I = reshape (I, sz(1:2));
+    endif
+  endif
+
+endfunction
+
+
+## Test pure RED, GREEN, BLUE colors
+%!assert (rgb2gray ([1 0 0]), 0.2989)
+%!assert (rgb2gray ([0 1 0]), 0.5870)
+%!assert (rgb2gray ([0 0 1]), 0.1140)
+
+## test tolerance input checking on floats
+%! assert (rgb2gray ([1.5 1 1]), 1.149, 1e-3);
+
+## Test ND input
+%!test
+%! rgb = rand (16, 16, 3, 5);
+%! I = zeros (16, 16, 5);
+%! for i = 1:5
+%!   I(:,:,i) = rgb2gray (rgb(:,:,:,i));
+%! endfor
+%! assert (rgb2gray (rgb), I);
+
+## Test output class and size for input images.
+## Most of the tests only test for colormap input.
+
+%!test
+%! I = rgb2gray (rand (10, 10, 3));
+%! assert (class (I), "double");
+%! assert (size (I), [10 10]);
+
+%!test
+%! I = rgb2gray (rand (10, 10, 3, "single"));
+%! assert (class (I), "single");
+%! assert (size (I), [10 10]);
+
+%!test
+%! rgb = (rand (10, 10, 3) * 3 ) - 0.5; # values outside range [0 1]
+%! I = rgb2gray (rgb);
+%! assert (class (I), "double");
+%! assert (size (I), [10 10]);
+
+%!test
+%! rgb = (rand (10, 10, 3, "single") * 3 ) - 0.5; # values outside range [0 1]
+%! I = rgb2gray (rgb);
+%! assert (class (I), "single");
+%! assert (size (I), [10 10]);
+
+%!test
+%! I = rgb2gray (randi ([0 255], 10, 10, 3, "uint8"));
+%! assert (class (I), "double");
+%! assert (size (I), [10 10]);
+
+%!test
+%! I = rgb2gray (randi ([0 65535], 10, 10, 3, "uint16"));
+%! assert (class (I), "double");
+%! assert (size (I), [10 10]);
+
+%!test
+%! I = rgb2gray (randi ([-128 127], 10, 10, 3, "int8"));
+%! assert (class (I), "double");
+%! assert (size (I), [10 10]);
+
+%!test
+%! rgb_double = reshape ([1 0 0 0 0 1 0 0 0 0 1 0], [2 2 3]);
+%! rgb_uint8  = reshape (uint8 ([255 0 0 0 0 255 0 0 0 0 255 0]),
+%!                       [2 2 3]);
+%! rgb_int16 = int16 (double (rgb_double * uint16 (65535)) - 32768);
+%! expected = [.2989, .1140; .5870, 0.0];
+%!
+%! assert (rgb2gray (rgb_double), expected);
+%! assert (rgb2gray (rgb_uint8), expected);
+%! assert (rgb2gray (single (rgb_double)), single (expected));
+
+## Test input validation
+%!error rgb2gray ()
+%!error rgb2gray (1,2)
+%!error <invalid data type 'cell'> rgb2gray ({1})
+%!error <RGB must be a colormap or RGB image> rgb2gray (ones (2,2))
--- a/scripts/image/rgb2hsv.m	Tue Jan 16 17:21:47 2018 -0800
+++ b/scripts/image/rgb2hsv.m	Tue Jan 16 21:14:22 2018 -0800
@@ -31,7 +31,7 @@
 ##
 ## Output class and size will be the same as input.
 ##
-## @seealso{hsv2rgb, rgb2ind, rgb2ntsc}
+## @seealso{hsv2rgb, rgb2ind, rgb2gray}
 ## @end deftypefn
 
 ## Author: Kai Habel <kai.habel@gmx.de>
--- a/scripts/image/rgb2ind.m	Tue Jan 16 17:21:47 2018 -0800
+++ b/scripts/image/rgb2ind.m	Tue Jan 16 21:14:22 2018 -0800
@@ -37,7 +37,7 @@
 ## supported, both via a single input (@var{rgb}) or its three color channels
 ## as separate variables.
 ##
-## @seealso{ind2rgb, rgb2hsv, rgb2ntsc}
+## @seealso{ind2rgb, rgb2hsv, rgb2gray}
 ## @end deftypefn
 
 ## FIXME: This function has a very different syntax than the Matlab