changeset 609:ea8f2e7d270a

rgb2gray: perform weighted conversion based on luminance values
author carandraug
date Mon, 24 Sep 2012 16:59:13 +0000
parents 1b8b83d01211
children 4c92bffbf4cc
files NEWS inst/rgb2gray.m
diffstat 2 files changed, 55 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS
+++ b/NEWS
@@ -59,6 +59,11 @@
       isrgb
       isind
       mat2gray
+      rgb2gray
+
+ ** `rgb2gray' now also supports images of the class single and performs a
+    weighted conversion to keep the image luminance instead of a the mean
+    through each color.
 
  ** `imhist' is much more compatible with matlab and among other changes,
     it now uses the whole range of the class for the histogram rather than
--- a/inst/rgb2gray.m
+++ b/inst/rgb2gray.m
@@ -1,4 +1,5 @@
 ## Copyright (C) 2000, 2001 Kai Habel <kai.habel@gmx.de>
+## Copyright (C) 2012 Carnë Draug <carandraug+dev@gmail.com>
 ##
 ## This program 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
@@ -17,13 +18,14 @@
 ## @deftypefn {Function File} @var{gray}= rgb2gray (@var{rgb})
 ## Convert RGB image or colormap to grayscale.
 ##
-## If the input is an RGB image, the conversion to a gray image is computed as
-## the mean value of the color channels. Supported classes are single, double,
-## uint8 and uint16.
+## If @var{rgb} is an RGB image, the conversion to grayscale is weighted based
+## on the luminance values (see @code{rgb2ntsc}).  Supported classes are single,
+## double,  uint8 and uint16.
 ##
-## If the input is a color map it is converted into the YIQ space
-## of ntsc. The luminance value (Y) is taken to create a gray color map.
-## R = G = B = Y
+## If @var{rgb} is a colormap it is converted into the YIQ space of ntsc.  The
+## luminance value (Y) is taken to create a gray colormap.
+##
+## @seealso{mat2gray, ntsc2rgb, rgb2ind, rgb2ntsc, rgb2ycbcr}
 ## @end deftypefn
 
 function gray = rgb2gray (rgb)
@@ -33,20 +35,48 @@
   endif
 
   if (iscolormap (rgb))
-    ntscmap = rgb2ntsc (rgb);
-    gray    = ntscmap (:, 1) * ones (1, 3);
-  elseif (isimage (rgb) && ndims(rgb) == 3)
-    switch(class(rgb))
-    case {"single", "double"}
-      gray = mean(rgb,3);
-    case "uint8"
-      gray = uint8(mean(rgb,3));
-    case "uint16"
-      gray = uint16(mean(rgb,3));
-    otherwise
-      error("rgb2gray: unsupported class %s", class(rgb));
-    endswitch
+    gray = rgb2ntsc (rgb) (:, 1) * ones (1, 3);
+  elseif (isimage (rgb) && ndims (rgb) == 3)
+
+    ## FIXME when warning for broadcasting is turned off by default, this
+    ## unwind_protect block could be removed
+
+    ## we are using broadcasting on the code below so we turn off the
+    ## warnings but will restore to previous state at the end
+    bc_warn = warning ("query", "Octave:broadcast");
+    unwind_protect
+      warning ("off", "Octave:broadcast");
+
+      ## mutiply each color by the luminance factor (this is also matlab compatible)
+      ##      0.29894 * red + 0.58704 * green + 0.11402 * blue
+      gray = im2double (rgb) .* permute ([0.29894, 0.58704, 0.11402], [1, 3, 2]);
+      gray = sum (gray, 3);
+
+      switch (class (rgb))
+      case {"single", "double"}
+        ## do nothing. All is good
+      case "uint8"
+        gray = im2uint8 (gray);
+      case "uint16"
+        gray = im2uint16 (gray);
+      otherwise
+        error ("rgb2gray: unsupported class %s", class(rgb));
+      endswitch
+
+    unwind_protect_cleanup
+      ## restore broadcats warning status
+      warning (bc_warn.state, "Octave:broadcast");
+    end_unwind_protect
   else
-    error("rgb2gray: the input must either be an RGB image or a colormap");
+    error ("rgb2gray: the input must either be an RGB image or a colormap");
   endif
 endfunction
+
+# simplest test, double image, each channel on its own and then all maxed
+%!shared img
+%! img = zeros (2, 2, 3);
+%! img(:,:,1) = [1 0; 0 1];
+%! img(:,:,2) = [0 1; 0 1];
+%! img(:,:,3) = [0 0; 1 1];
+%! img = rgb2gray (img);
+%!assert ([img(1,1) img(1,2) img(2,1) img(2,2)], [0.29894 0.58704 0.11402 1]);