changeset 15714:b1cd65881592

Clean up scripts in image directory. Use Octave coding conventions. Redo docstrings. Add %!tests. * brighten.m: Put input validation first. Use iscolormap to simplify input checking. * cmunique.m: Use faster method of validating input class. * colormap.m: Tweak docstring. Improve input validation. * contrast.m: Tweak docstring. Use cmap instead of map as variable name for clarity. * gray2ind.m: Wrap long lines. Use faster method of validating input class. Delete unreachable code for n>65536. * hsv2rgb.m: Use faster method of validating input class. * imwrite.m: Tweak FIXME notes. * ind2gray.m: Use correct caller name for ind2x. Update %!tests with new 2-input calling convention. * ind2rgb.m: Tweak docstring. Update %!tests with new 2-input calling convention. * iscolormap.m: Tweak docstring. Re-order validation tests. * ntsc2rgb.m: Use faster method of validating input class. Better input validation. Add %!tests. * private/ind2x.m: Use more descriptive variable names. * rgb2hsv.m: Tweak docstring. Use faster method of validating input class. * rgb2ind.m: Tweak docstring. Wrap long lines. * rgb2ntsc.m: Use faster method of validating input class. Improve input validation. Add %!tests. * rgbplot.m: Match variable names in docstring to those in function prototype.
author Rik <rik@octave.org>
date Sun, 02 Dec 2012 10:02:57 -0800
parents 168e380c8f18
children 6ae93518356c
files scripts/image/brighten.m scripts/image/cmunique.m scripts/image/colormap.m scripts/image/contrast.m scripts/image/gray2ind.m scripts/image/hsv2rgb.m scripts/image/imwrite.m scripts/image/ind2gray.m scripts/image/ind2rgb.m scripts/image/iscolormap.m scripts/image/ntsc2rgb.m scripts/image/private/ind2x.m scripts/image/rgb2hsv.m scripts/image/rgb2ind.m scripts/image/rgb2ntsc.m scripts/image/rgbplot.m
diffstat 16 files changed, 117 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/image/brighten.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/brighten.m	Sun Dec 02 10:02:57 2012 -0800
@@ -34,22 +34,24 @@
 
 function rmap = brighten (arg1, beta)
 
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+  endif
+
   h = -1;
   if (nargin == 1)
     beta = arg1;
-    m = colormap;
+    m = colormap ();
     h = gcf ();
-  elseif (nargin == 2)
+  else
     if (ishandle (arg1))
       h = arg1;
       m = get (h, "colormap");
-    elseif (ismatrix (arg1) && columns (arg1) == 3)
+    elseif (iscolormap (arg1))
       m = arg1;
     else
-      error ("brighten: first argument must be an Nx3 matrix or a handle");
+      error ("brighten: first argument must be a colormap or a graphics handle");
     endif
-  else
-    print_usage ();
   endif
 
   if (! isscalar (beta) || beta <= -1 || beta >= 1)
--- a/scripts/image/cmunique.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/cmunique.m	Sun Dec 02 10:02:57 2012 -0800
@@ -62,7 +62,7 @@
 
   cls = class (X);
   ## FIXME: Documentation accepts only 3 classes.  Could easily add 'single'.
-  if (! any (isa (X, {"uint8", "uint16", "double"})))
+  if (! any (strcmp (cls, {"uint8", "uint16", "double"})))
     error ("cmunique: X is of invalid data type '%s'", cls);
   endif
 
--- a/scripts/image/colormap.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/colormap.m	Sun Dec 02 10:02:57 2012 -0800
@@ -22,8 +22,8 @@
 ## @deftypefnx {Function File} {@var{cmap} =} colormap (@var{map})
 ## @deftypefnx {Function File} {@var{cmap} =} colormap ("default")
 ## @deftypefnx {Function File} {@var{cmap} =} colormap ("list")
-## @deftypefnx {Function File} {@var{cmap} =} colormap ("register", "name")
-## @deftypefnx {Function File} {@var{cmap} =} colormap ("unregister", "name")
+## @deftypefnx {Function File} {@var{cmap} =} colormap ("register", "@var{name}")
+## @deftypefnx {Function File} {@var{cmap} =} colormap ("unregister", "@var{name}")
 ## Query or set the current colormap.
 ##
 ## @code{colormap (@var{map})} sets the current colormap to @var{map}.  The
@@ -68,8 +68,9 @@
     endif
 
     if (! isempty (map))
-      if (! ismatrix (map) || ndims (map) != 2 || columns (map) != 3)
-        error ("colormap: MAP must be an N x 3 ([R,G,B]) matrix");
+      if (! (isnumeric (map) && isreal (map)
+             && ndims (map) == 2 && columns (map) == 3))
+        error ("colormap: MAP must be a real-valued N x 3 ([R,G,B]) matrix");
       endif
       if (any (map(:) < 0) || any (map(:) > 1))
         error ("colormap: all MAP values must be in the range [0,1]");
@@ -98,4 +99,4 @@
 endfunction
 
 
-%% 
+%% FIXME: Need some demos/tests
--- a/scripts/image/contrast.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/contrast.m	Sun Dec 02 10:02:57 2012 -0800
@@ -17,18 +17,18 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} {@var{map} =} contrast (@var{x})
-## @deftypefnx {Function File} {@var{map} =} contrast (@var{x}, @var{n})
+## @deftypefn  {Function File} {@var{cmap} =} contrast (@var{x})
+## @deftypefnx {Function File} {@var{cmap} =} contrast (@var{x}, @var{n})
 ## Return a gray colormap that maximizes the contrast in an image.  The
 ## returned colormap will have @var{n} rows.  If @var{n} is not defined
 ## then the size of the current colormap is used.
 ## @seealso{colormap, brighten}
 ## @end deftypefn
 
-function map = contrast (x, n)
+function cmap = contrast (x, n)
 
   if (nargin == 1)
-    n = rows (colormap);
+    n = rows (colormap ());
   elseif (nargin == 2)
     if (! isscalar (n))
       error ("contrast: N must be a scalar");
@@ -39,10 +39,10 @@
 
   x = x(:);
   minx = min (x);
-  map = find (diff (sort ([round(n * ((x - minx) ./ (max(x) - minx))); [0:n]'])));
-  minm = min (map);
-  map = (map - minm) ./ (max (map) - minm);
-  map = [map, map, map];
+  cmap = find (diff (sort ([round(n * ((x - minx) ./ (max(x) - minx))); [0:n]'])));
+  minm = min (cmap);
+  cmap = (cmap - minm) ./ (max (cmap) - minm);
+  cmap = [cmap, cmap, cmap];
 
 endfunction
 
--- a/scripts/image/gray2ind.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/gray2ind.m	Sun Dec 02 10:02:57 2012 -0800
@@ -28,8 +28,8 @@
 ## If not given @var{n} defaults to 64 for grayscale images or 2 for
 ## binary black and white images.
 ##
-## The output @var{img} is of class uint8 or uint 16 if @var{n} is less than or
-## equal to 256 or 65536 respectively.  Otherwise, the output is of class double.
+## The output @var{img} is of class uint8 if @var{n} is less than or
+## equal to 256; Otherwise the return class is uint16.
 ## @seealso{ind2gray, rgb2ind}
 ## @end deftypefn
 
@@ -46,7 +46,7 @@
   elseif (! isscalar (n) || n < 1 || n > 65536)
     error ("gray2ind: N must be a positive integer in the range [1, 65536]");
   elseif (! ismatrix (I) || ndims (I) != 2)
-    error ("gray2ind: first input argument must be a gray scale image");
+    error ("gray2ind: I must be a grayscale or binary image");
   endif
 
   ## default n is different if image is logical
@@ -54,12 +54,8 @@
     n = 2;
   endif
 
-  if (! isscalar (n) || n < 0)
-    error ("gray2ind: second input argument must be a positive integer");
-  endif
-
   cls = class (I);
-  if (! any (isa (I, {"logical", "uint8", "uint16", "int16", "single", "double"})))
+  if (! any (strcmp (cls, {"logical", "uint8", "uint16", "int16", "single", "double"})))
     error ("gray2ind: invalid data type '%s'", cls);
   elseif (isfloat (I) && (min (I(:) < 0) || max (I(:) > 1)))
     error ("gray2ind: floating point images may only contain values between 0 and 1");
@@ -75,20 +71,19 @@
   else
     scale = 1;
   endif
+  I *= (n-1)/scale;
+
   ## Note: no separate call to round () necessary because
   ##       type conversion does that automatically.
-  I = I * ((n-1)/scale);
   if (n < 256)
     I = uint8 (I);
-  elseif (n < 65536)
+  else
     I = uint16 (I);
-  else
-    ## if uint16 is not enough, we return double in which case index
-    ## values should start at 1.
-    I = round (I) + 1;
   endif
+
 endfunction
 
+
 %!assert (gray2ind ([0 0.25 0.5 1]), uint8 ([0 16 32 63]))
 %!assert (gray2ind ([0 0.25 0.5 1], 400), uint16 ([0 100 200 399]))
 %!assert (gray2ind (logical ([1 0 0 1])), uint8 ([1 0 0 1]))
--- a/scripts/image/hsv2rgb.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/hsv2rgb.m	Sun Dec 02 10:02:57 2012 -0800
@@ -46,7 +46,7 @@
   endif
 
   cls = class (hsv_map);
-  if (! any (isa (hsv_map, {"uint8", "uint16", "single", "double"})))
+  if (! any (strcmp (cls, {"uint8", "uint16", "single", "double"})))
     error ("hsv2rgb: invalid data type '%s'", cls);
   elseif (isfloat (hsv_map) && (any (hsv_map(:) < 0) || any (hsv_map(:) > 1)))
     error ("hsv2rgb: floating point images may only contain values between 0 and 1");
@@ -96,6 +96,8 @@
              + (hue >= 1/6 & hue < 1/2)
              + (hue >= 1/2 & hue < 2/3) .* (4 - 6 * hue));
 
+  ## FIXME: hsv2rgb does not preserve class of image.
+  ##        Should it also convert back to uint8, uint16 for integer images?
   ## If input was an image, convert it back into one.
   if (is_image)
     rgb_map = reshape (rgb_map, sz);
--- a/scripts/image/imwrite.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/imwrite.m	Sun Dec 02 10:02:57 2012 -0800
@@ -135,7 +135,7 @@
       if ((nd == 2 || nd == 3) && strcmp (img_class, "double"))
         img = uint8 (img * 255);
       endif
-      ## FIXME -- should we handle color images w/ alpha channel here?
+      ## FIXME: should we handle color images with alpha channel here?
       if (nd == 3 && size (img, 3) < 3)
         error ("imwrite: invalid dimensions for truecolor image");
       endif
@@ -165,8 +165,8 @@
       error ("imwrite: invalid indexed image colormap");
     endif
 
-    ## FIXME -- we should really be writing indexed images here but
-    ## __magick_write__ needs to be fixed to handle them.
+    ## FIXME: we should really be writing indexed images here but
+    ##        __magick_write__ needs to be fixed to handle them.
 
     [r, g, b] = ind2rgb (img, map);
     tmp = uint8 (cat (3, r, g, b) * 255);
--- a/scripts/image/ind2gray.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/ind2gray.m	Sun Dec 02 10:02:57 2012 -0800
@@ -45,13 +45,13 @@
   if (nargin != 2)
     print_usage ();
   endif
-  [x, map] = ind2x ("ind2rgb", x, map);
+  [x, map] = ind2x ("ind2gray", x, map);
 
   ## Convert colormap to luminance intensity values 
   map *= [0.29894; 0.58704; 0.11402];
 
-  ## Convert colormap to same class as that of input so that when reshape
-  ## later, produces output of the same type as the input
+  ## Convert colormap to same class as that of input so that reshape
+  ## will produce output of the same type as the input.
   cls = class (x);
   if (isinteger (x))
     ## if we later add support for int16 images, this will not work. Look into
@@ -66,19 +66,21 @@
 
 endfunction
 
+
 %!shared i2g
 %! i2g = ind2gray (1:100, gray (100));
 %!assert (i2g, 0:1/99:1, eps);
 %!assert (gray2ind (i2g, 100), uint8 (0:99));
 
-%%test input validation
+%% Test input validation
 %!error ind2gray ()
+%!error ind2gray (1)
 %!error ind2gray (1,2,3)
-%!error <X must be an indexed image> ind2gray ({1})
-%!error <X must be an indexed image> ind2gray (1+i)
-%!error <X must be an indexed image> ind2gray (sparse (1))
-%!error <X must be an indexed image> ind2gray (0)
-%!error <X must be an indexed image> ind2gray (1.1)
+%!error <X must be an indexed image> ind2gray ({1}, jet (64))
+%!error <X must be an indexed image> ind2gray (1+i, jet (64))
+%!error <X must be an indexed image> ind2gray (sparse (1), jet (64))
+%!error <X must be an indexed image> ind2gray (0, jet (64))
+%!error <X must be an indexed image> ind2gray (1.1, jet (64))
 %!error <MAP must be a valid colormap> ind2gray (1, {1})
 %!error <MAP must be a valid colormap> ind2gray (1, 1+i)
 %!error <MAP must be a valid colormap> ind2gray (1, ones (2,2,2))
--- a/scripts/image/ind2rgb.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/ind2rgb.m	Sun Dec 02 10:02:57 2012 -0800
@@ -18,11 +18,11 @@
 
 ## -*- texinfo -*-
 ## @deftypefn  {Function File} {@var{rgb} =} ind2rgb (@var{x}, @var{map})
-## @deftypefnx {Function File} {[@var{R}, @var{G}, @var{B}] =} ind2rgb (@dots{})
+## @deftypefnx {Function File} {[@var{R}, @var{G}, @var{B}] =} ind2rgb (@var{x}, @var{map})
 ## Convert an indexed image to red, green, and blue color components.
 ##
 ## The image @var{x} must be an indexed image which will be converted using the
-## colormap @var{cmap}.  If @var{cmap} does not contain enough colors for the
+## colormap @var{map}.  If @var{map} does not contain enough colors for the
 ## image, pixels in @var{x} outside the range are mapped to the last color in
 ## the map.
 ##
@@ -59,6 +59,7 @@
 
 endfunction
 
+
 %!shared img, map, ergb, rgb, r, g, b
 %! img = [2 4 5; 3 2 5; 1 2 4];
 %! map = [0.0  0.0  0.0
@@ -79,19 +80,20 @@
 %! [rgb] = ind2rgb (img, map);
 %!assert (ergb, rgb);
 %! ## check it fails when image is a float with an index value of 0
-%!fail("[rgb] = ind2rgb (double(img), map)")
+%!fail ("[rgb] = ind2rgb (double(img), map)")
 
-%%test input validation
+%% Test input validation
 %!error ind2rgb ()
 %!error ind2rgb (1,2,3)
-%!error <X must be an indexed image> ind2rgb ({1})
-%!error <X must be an indexed image> ind2rgb (1+i)
-%!error <X must be an indexed image> ind2rgb (sparse (1))
-%!error <X must be an indexed image> ind2rgb (0)
-%!error <X must be an indexed image> ind2rgb (1.1)
+%!error <X must be an indexed image> ind2rgb ({1}, jet (64))
+%!error <X must be an indexed image> ind2rgb (1+i, jet (64))
+%!error <X must be an indexed image> ind2rgb (sparse (1), jet (64))
+%!error <X must be an indexed image> ind2rgb (0, jet (64))
+%!error <X must be an indexed image> ind2rgb (1.1, jet (64))
 %!error <MAP must be a valid colormap> ind2rgb (1, {1})
 %!error <MAP must be a valid colormap> ind2rgb (1, 1+i)
 %!error <MAP must be a valid colormap> ind2rgb (1, ones (2,2,2))
 %!error <MAP must be a valid colormap> ind2rgb (1, ones (2,4))
 %!error <MAP must be a valid colormap> ind2rgb (1, [-1])
 %!error <MAP must be a valid colormap> ind2rgb (1, [2])
+
--- a/scripts/image/iscolormap.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/iscolormap.m	Sun Dec 02 10:02:57 2012 -0800
@@ -20,10 +20,10 @@
 ## @deftypefn {Function File} {} iscolormap (@var{cmap})
 ## Return true if @var{cmap} is a colormap.
 ##
-## A colormap is an @var{n} row by 3 column matrix.  The columns contain red,
-## green, and blue intensities respectively.  All entries must be between 0
-## and 1 inclusive.
-##
+## A colormap is a real matrix with @var{n} rows and 3 columns.
+## Each row represents a single color.  The columns contain red, green,
+## and blue intensities respectively.  All entries must be between 0 and 1
+## inclusive.
 ## @seealso{colormap, rgbplot}
 ## @end deftypefn
 
@@ -36,7 +36,7 @@
   endif
 
   retval = (isnumeric (cmap) && isreal (cmap) &&
-            columns (cmap) == 3 && ndims (cmap) == 2 && isa (cmap, "double") &&
+            ndims (cmap) == 2 && columns (cmap) == 3 && isa (cmap, "double") &&
             min (cmap(:)) >= 0 && max (cmap(:)) <= 1);
 
 endfunction
@@ -45,8 +45,9 @@
 %!assert (iscolormap (jet (64)))
 %!assert (iscolormap ({0 1 0}), false)
 %!assert (iscolormap ([0 1i 0]), false)
+%!assert (iscolormap (ones (3,3,3)), false)
 %!assert (iscolormap (ones (3,4)), false)
-%!assert (iscolormap (ones (3,3,3)), false)
 %!assert (iscolormap (single (jet (64))), false)
 %!assert (iscolormap ([0 0 -2]), false)
 %!assert (iscolormap ([0 0 2]), false)
+
--- a/scripts/image/ntsc2rgb.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/ntsc2rgb.m	Sun Dec 02 10:02:57 2012 -0800
@@ -46,7 +46,7 @@
   endif
 
   cls = class (yiq);
-  if (! any (isa (yiq, {"uint8", "uint16", "single", "double"})))
+  if (! any (strcmp (cls, {"uint8", "uint16", "single", "double"})))
     error ("ntsc2rgb: invalid data type '%s'", cls);
   endif
 
@@ -57,7 +57,6 @@
     yiq = [yiq(:,:,1)(:), yiq(:,:,2)(:), yiq(:,:,3)(:)];
     ## Convert to a double image.
     if (isinteger (yiq))
-      cls = class (yiq);
       low = double (intmin (cls));
       high = double (intmax (cls));
       yiq = (double (yiq) - low) / (high - low);
@@ -66,12 +65,12 @@
     is_image = false;
   endif
 
-  if (! ismatrix (yiq) || columns (yiq) != 3)
-    error ("ntsc2rgb: argument must be a matrix of size Nx3 or NxMx3");
+  if (! isreal (yiq) || columns (yiq) != 3 || issparse (yiq))
+    error ("ntsc2rgb: input must be a matrix of size Nx3 or NxMx3");
   endif
 
-  ## Conversion matrix constructed from 'inv (rgb2ntsc matrix)'.  See
-  ## programming notes in rgb2ntsc.m.  Note: Matlab matrix for inverse
+  ## Conversion matrix constructed from 'inv (rgb2ntsc matrix)'.
+  ## See programming notes in rgb2ntsc.m.  Note: Matlab matrix for inverse
   ## is slightly different.  We prefer this matrix so that
   ## x == ntsc2rgb (rgb2ntsc (x)) rather than maintaining strict compatibility
   ## with Matlab.
@@ -81,6 +80,8 @@
 
   rgb = yiq * trans;
 
+  ## FIXME: ntsc2rgb does not preserve class of image.
+  ##        Should it also convert back to uint8, uint16 for integer images?
   ## If input was an image, convert it back into one.
   if (is_image)
     rgb = reshape (rgb, sz);
@@ -89,6 +90,11 @@
 endfunction
 
 
+%% Test pure R, G, B colors
+%!assert (ntsc2rgb ([.299  .596  .211]), [1 0 0], 1e-5)
+%!assert (ntsc2rgb ([.587 -.274 -.523]), [0 1 0], 1e-5)
+%!assert (ntsc2rgb ([.114 -.322  .312]), [0 0 1], 1e-5)
+
 %!test
 %! rgb_map = rand (64, 3);
 %! assert (ntsc2rgb (rgb2ntsc (rgb_map)), rgb_map, 1e-3);
@@ -97,14 +103,6 @@
 %! rgb_img = rand (64, 64, 3);
 %! assert (ntsc2rgb (rgb2ntsc (rgb_img)), rgb_img, 1e-3);
 
-%%!test
-%%! ntsc_map = rand (64, 3);
-%%! assert (rgb2ntsc (ntsc2rgb (ntsc_map)), ntsc_map, 1e-3);
-%
-%%!test
-%%! ntsc_img = rand (64, 64, 3);
-%%! assert (rgb2ntsc (ntsc2rgb (ntsc_img)), ntsc_img, 1e-3);
-
 %% Test input validation
 %!error ntsc2rgb ()
 %!error ntsc2rgb (1,2)
--- a/scripts/image/private/ind2x.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/private/ind2x.m	Sun Dec 02 10:02:57 2012 -0800
@@ -17,26 +17,25 @@
 ## along with Octave; see the file COPYING.  If not, see
 ## <http://www.gnu.org/licenses/>.
 
-## private function for the ind2something functions which have a lot of code
-## in common
+## private function for the ind2XXX functions which have a lot of code in common
 
-function [x, map] = ind2x (name, x, map)
+function [x, map] = ind2x (caller, x, map)
 
   ## Check if X is an indexed image.
   if (ndims (x) != 2 || issparse (x) || (isfloat (x) && ! isindex (x)) ||
-      ! ismember (class (x), {"double", "single", "uint8", "uint16"}))
-    error ("%s: X must be an indexed image", name);
+      ! any (strcmp (class (x), {"uint8", "uint16", "single", "double"})))
+    error ("%s: X must be an indexed image", caller);
   endif
 
-  ## Check the color map.
+  ## Check if map is a valid colormap.
   if (! iscolormap (map))
-    error ("%s: MAP must be a valid colormap", name);
+    error ("%s: MAP must be a valid colormap", caller);
   endif
 
   ## Do we have enough colors in the color map?
   ## there's an offset of 1 when the indexed image is an integer class so we fix
   ## it now and convert it to float only if really necessary and even then only
-  ## to single precision since its enough for both uint8 and uint16
+  ## to single precision since that is enough for both uint8 and uint16.
   maxidx = max (x(:));
   if (isinteger (x))
     if (maxidx == intmax (class (x)))
@@ -46,10 +45,10 @@
     maxidx += 1;
   endif
 
-  rm = rows (map);
-  if (rm < maxidx)
+  num_colors = rows (map);
+  if (num_colors < maxidx)
     ## Pad with the last color in the map for matlab compatibility
-    pad = repmat (map(end,:), maxidx-rm, 1);
+    pad = repmat (map(end,:), maxidx - num_colors, 1);
     map(end+1:maxidx, :) = pad;
   endif
 
--- a/scripts/image/rgb2hsv.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/rgb2hsv.m	Sun Dec 02 10:02:57 2012 -0800
@@ -24,7 +24,7 @@
 ##
 ## A color in the RGB space consists of red, green, and blue intensities.
 ##
-## A color in HSV space is represented by hue, saturation and value
+## A color in HSV space is represented by hue, saturation, and value
 ## (brightness) levels.  Value gives the amount of light in the color.  Hue
 ## describes the dominant wavelength.  Saturation is the amount of hue mixed
 ## into the color.
@@ -41,7 +41,7 @@
   endif
 
   cls = class (rgb);
-  if (! any (isa (rgb, {"uint8", "uint16", "single", "double"})))
+  if (! any (strcmp (cls, {"uint8", "uint16", "single", "double"})))
     error ("rgb2hsv: invalid data type '%s'", cls);
   elseif (isfloat (rgb) && (any (rgb(:) < 0) || any (rgb(:) > 1)))
     error ("rgb2hsv: floating point images may only contain values between 0 and 1");
@@ -54,7 +54,6 @@
     rgb = [rgb(:,:,1)(:), rgb(:,:,2)(:), rgb(:,:,3)(:)];
     ## Convert to a double image.
     if (isinteger (rgb))
-      cls = class (rgb);
       low = double (intmin (cls));
       high = double (intmax (cls));
       rgb = (double (rgb) - low) / (high - low);
@@ -64,7 +63,7 @@
   endif
 
   if (! ismatrix (rgb) || columns (rgb) != 3 || issparse (rgb))
-    error ("rgb2hsv: input must be a matrix of size Nx3");
+    error ("rgb2hsv: input must be a matrix of size Nx3 or MxNx3");
   endif
 
   ## get the max and min for each row
@@ -100,6 +99,8 @@
 
   hsv_map = [h, s, v];
 
+  ## FIXME: rgb2hsv does not preserve class of image.
+  ##        Should it also convert back to uint8, uint16 for integer images?
   ## If input was an image, convert it back into one.
   if (is_image)
     hsv_map = reshape (hsv_map, sz);
--- a/scripts/image/rgb2ind.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/rgb2ind.m	Sun Dec 02 10:02:57 2012 -0800
@@ -20,12 +20,14 @@
 ## -*- texinfo -*-
 ## @deftypefn  {Function File} {[@var{x}, @var{map}] =} rgb2ind (@var{rgb})
 ## @deftypefnx {Function File} {[@var{x}, @var{map}] =} rgb2ind (@var{R}, @var{G}, @var{B})
-## Convert an image in red-green-blue (RGB) space to an indexed image.
+## Convert an image in red-green-blue (RGB) color space to an indexed image.
 ## @seealso{ind2rgb, rgb2hsv, rgb2ntsc}
 ## @end deftypefn
 
-## FIXME: This function has a very different syntax than the Matlab one of the same name.
-##        Octave function does no support N, MAP, DITHER, or TOL arguments
+## FIXME: This function has a very different syntax than the Matlab
+##        one of the same name.
+##        Octave function does not support N, MAP, DITHER, or TOL arguments.
+
 ## Author: Tony Richardson <arichard@stark.cc.oh.us>
 ## Created: July 1994
 ## Adapted-By: jwe
@@ -51,7 +53,7 @@
 
   x = reshape (1:numel (R), size (R));
 
-  map    = unique([R(:) G(:) B(:)], "rows");
+  map    = unique ([R(:) G(:) B(:)], "rows");
   [~, x] = ismember ([R(:) G(:) B(:)], map, "rows");
   x      = reshape (x, size (R));
 
@@ -78,11 +80,14 @@
   else
     ## leave it as double
   endif
+
 endfunction
 
+
 %% FIXME: Need some functional tests or %!demo blocks
 
 %% Test input validation
 %!error rgb2ind ()
 %!error rgb2ind (1,2)
 %!error rgb2ind (1,2,3,4)
+
--- a/scripts/image/rgb2ntsc.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/rgb2ntsc.m	Sun Dec 02 10:02:57 2012 -0800
@@ -51,7 +51,7 @@
   endif
 
   cls = class (rgb);
-  if (! any (isa (rgb, {"uint8", "uint16", "single", "double"})))
+  if (! any (strcmp (cls, {"uint8", "uint16", "single", "double"})))
     error ("rgb2ntsc: invalid data type '%s'", cls);
   elseif (isfloat (rgb) && (any (rgb(:) < 0) || any (rgb(:) > 1)))
     error ("rgb2ntsc: floating point images may only contain values between 0 and 1");
@@ -72,8 +72,8 @@
     is_image = false;
   endif
 
-  if (! ismatrix (rgb) || columns (rgb) != 3 || issparse (rgb))
-    error ("rgb2ntsc: argument must be a matrix of size Nx3 or NxMx3");
+  if (! isreal (rgb) || columns (rgb) != 3 || issparse (rgb))
+    error ("rgb2ntsc: input must be a matrix of size Nx3 or NxMx3");
   endif
 
   ## Reference matrix for transformation from http://en.wikipedia.org/wiki/YIQ
@@ -86,6 +86,8 @@
   ## Convert data. 
   yiq = rgb * trans;
 
+  ## FIXME: rgb2ntsc does not preserve class of image.
+  ##        Should it also convert back to uint8, uint16 for integer images?
   ## If input was an image, convert it back into one.
   if (is_image)
     yiq = reshape (yiq, sz);
@@ -94,8 +96,10 @@
 endfunction
 
 
-%% Test RED conversion
-%assert (rgb2ntsc ([1 0 0]), [0.299 0.587 0.114])
+%% Test pure RED, GREEN, BLUE colors
+%assert (rgb2ntsc ([1 0 0]), [.299  .587  .114])
+%assert (rgb2ntsc ([0 1 0]), [.596 -.274 -.322])
+%assert (rgb2ntsc ([1 0 1]), [.211 -.523  .312])
 
 %!test
 %! rgb_map = rand (64, 3);
--- a/scripts/image/rgbplot.m	Sun Dec 02 17:29:47 2012 +0100
+++ b/scripts/image/rgbplot.m	Sun Dec 02 10:02:57 2012 -0800
@@ -50,7 +50,7 @@
   endif
 
   if (! iscolormap (cmap))
-    error ("rgbplot: CMAP must be a colormap");
+    error ("rgbplot: CMAP must be a valid colormap");
   elseif (! ischar (style))
     error ("rgbplot: STYLE must be a string");
   endif
@@ -69,7 +69,7 @@
   xlabel ("color index");
 
   if (nargout > 0)
-    retval = h;
+    h = htmp;
   endif
 
 endfunction
@@ -81,7 +81,8 @@
 %! subplot (1, 2, 2)
 %! rgbplot (ocean, "composite");
 
-%%test input validation
+%% Test input validation
 %!error rgbplot ()
 %!error rgbplot (1,2)
-%!error <CMAP must be a colormap> rgbplot ({0 1 0})
+%!error <CMAP must be a valid colormap> rgbplot ({0 1 0})
+