changeset 653:72a6590f05aa

cmunique() cmpermute(): have been added to octave core. Get changes back while core is not released
author carandraug
date Fri, 12 Oct 2012 17:41:33 +0000
parents 99c2c68d53de
children c4e8c359d0eb
files NEWS inst/cmpermute.m inst/cmunique.m
diffstat 3 files changed, 259 insertions(+), 193 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS
+++ b/NEWS
@@ -80,6 +80,8 @@
       bwarea
       bweuler
       bwfill
+      cmpermute
+      cmunique
       imhist
       imnoise
       conndef
--- a/inst/cmpermute.m
+++ b/inst/cmpermute.m
@@ -1,103 +1,142 @@
-## Copyright (C) 2004 Josep Mones i Teixidor <jmones@puntbarra.com>
+## Copyright (C) 2004 Josep Mones i Teixidor
+## Copyright (C) 2012 Rik Wehbring 
 ##
-## 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
-## Foundation; either version 3 of the License, or (at your option) any later
-## version.
+## This file is part of Octave.
 ##
-## This program 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.
+## 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.
 ##
-## You should have received a copy of the GNU General Public License along with
-## this program; if not, see <http://www.gnu.org/licenses/>.
+## 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
+## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {[@var{Y}, @var{newmap}] =} cmpermute (@var{X}, @var{map})
+## @deftypefn  {Function File} {[@var{Y}, @var{newmap}] =} cmpermute (@var{X}, @var{map})
 ## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] =} cmpermute (@var{X}, @var{map}, @var{index})
-## Reorders colors in a colormap.
+## Reorder colors in a colormap.
 ##
-## @code{[Y,newmap]=cmpermute(X,map)} rearranges colormap @var{map}
-## randomly returning colormap @var{newmap} and generates indexed image
-## @var{Y} so that it mantains correspondence between indices and the
-## colormap from original indexed image @var{X} (both image and colormap
-## pairs produce the same result).
+## When called with only two arguments, @code{cmpermute} randomly rearranges
+## the colormap @var{map} and returns a new colormap @var{newmap}.  It also
+## returns the indexed image @var{Y} which is the equivalent of the original
+## input image @var{X} when displayed using @var{newmap}.  The input image
+## @var{X} must be an indexed image of class uint8 or double.
 ##
-## @code{[Y,newmap]=cmpermute(X,map,index)} behaves as described above
-## but instead of sorting colors randomly, it uses @var{index} to define
-## the order of the colors in the new colormap.
+## When called with an optional third argument the order of colors in the
+## new colormap is defined by @var{index}.
 ##
-## @strong{Note:} @code{index} shouldn't have repeated elements, this
-## function won't explicitly check this, but it will fail if it has.
+## @strong{Caution:} @code{index} should not have repeated elements or the
+## function will fail.
 ##
 ## @end deftypefn
 
+## Author:  Josep Mones i Teixidor <jmones@puntbarra.com>
+
 function [Y, newmap] = cmpermute (X, map, index)
-  switch(nargin)
-    case(2)
-      index=randperm(rows(map));
-    case(3)
-      if(!isvector(index) || length(index)!=rows(map))
-        error("cmpermute: invalid parameter index.");
-      endif
-    otherwise
-      print_usage;
-  endswitch
+
+  if (nargin < 2 || nargin > 3)
+    print_usage ();
+  endif
+
+  ## FIXME: Matlab only accepts 2 types.  Expand to uint16 & single??
+  if (! (isa (X, "uint8") || isa (X, "double")))
+    error ("cmpermute: X must be of class uint8 or double");
+  endif
+
+  if (! isreal (X) || issparse (X)
+      || (isfloat (X) && (any (X(:) < 1 || any (X(:) != fix (X(:)))))))
+    error ("cmpermute: X must be an indexed image");
+  endif
+
+  if (! isnumeric (map) || iscomplex (map)
+      || ndims (map) != 2 || columns (map) != 3
+      || any (map(:) < 0) || any (map(:) > 1))
+    error ("cmpermute: MAP must be a valid colormap");
+  endif
+
+  if (nargin < 3)
+    index = randperm (rows (map));
+  elseif (! isvector (index) || length (index) != rows (map))
+    error ("cmpermute: invalid parameter INDEX");
+  endif
 
   ## new colormap
-  newmap=map(index,:);
+  newmap = map(index,:);
 
   ## build reverse index
-  rindex = zeros(size(index));
-  rindex(index) = 1:length(index);
+  rindex = zeros (size (index));
+  rindex(index) = 1:length (index);
+ 
+  ## adapt indices
+  if (isa (X, "uint8"))
+    rindex = uint8 (rindex-1);
+    ## 0-based indices
+    Y = rindex(double (X) + 1);
+  else
+    Y = rindex(X);
+  endif
 
-  ## readapt indices
-  if(isa(X,"uint8"))
-    rindex=uint8(rindex-1);
-    ## 0-based indices
-    Y=rindex(double(X)+1);
-  else
-    Y=rindex(X);
-  endif
 endfunction
 
 %!demo
-%! [Y,newmap]=cmpermute([1:4],hot(4),4:-1:1)
-%! # colormap will be arranged in reverse order (so will image)
+%! [Y, newmap] = cmpermute ([1:4], hot (4), 4:-1:1)
+%! ## colormap will be arranged in reverse order (so will image)
 
-%!shared X,map
-%! X=magic(16);
-%! [X,map]=cmunique(X);
+%!shared X, map
+%! X = uint8 (magic (16));
+%! [X, map] = cmunique (X);
 
 %!test # random permutation, 0-based index
-%! [Y,newmap]=cmpermute(X,map);
-%! # test we didn't lose colors
-%! assert(sort(map),sortrows(newmap)); 
-%! # test if images are equal
-%! assert(map(double(X)+1),newmap(double(Y)+1));
+%! [Y, newmap] = cmpermute (X, map);
+%! ## test we didn't lose colors
+%! assert (sort (map), sortrows (newmap)); 
+%! ## test if images are equal
+%! assert (map(double (X)+1), newmap(double (Y)+1));
 
 %!test # reverse map, 0-based index
-%! [Y,newmap]=cmpermute(X,map,rows(map):-1:1);
-%! # we expect a reversed colormap
-%! assert(newmap(rows(newmap):-1:1,:),map);
-%! # we expect reversed indices in image
-%! assert(X,max(Y(:))-Y);
+%! [Y, newmap] = cmpermute (X, map, rows (map):-1:1);
+%! ## we expect a reversed colormap
+%! assert (flipud (newmap), map);
+%! ## we expect reversed indices in image
+%! assert (X, max (Y(:)) - Y);
 
 %!shared X,map
-%! X=magic(20);
-%! [X,map]=cmunique(X);
+%! X = uint16 (magic (20));
+%! [X, map] = cmunique (X);
 
 %!test # random permutation, 1-based index
-%! [Y,newmap]=cmpermute(X,map);
-%! # test we didn't lose colors
-%! assert(sort(map),sortrows(newmap)); 
-%! # test if images are equal
-%! assert(map(X),newmap(Y));
+%! [Y, newmap] = cmpermute (X, map);
+%! ## test we didn't lose colors
+%! assert (sort (map), sortrows (newmap)); 
+%! ## test if images are equal
+%! assert (map(X), newmap(Y));
 
 %!test # reverse map, 1-based index
-%! [Y,newmap]=cmpermute(X,map,rows(map):-1:1);
-%! # we expect a reversed colormap
-%! assert(newmap(rows(newmap):-1:1,:),map);
-%! # we expect reversed indices in image
-%! assert(X,max(Y(:))+1-Y);
+%! [Y, newmap] = cmpermute (X, map, rows (map):-1:1);
+%! ## we expect a reversed colormap
+%! assert (newmap (rows (newmap):-1:1,:), map);
+%! ## we expect reversed indices in image
+%! assert (X, max (Y(:)) + 1 - Y);
+
+## Test input validation
+%!error cmpermute ()
+%!error cmpermute (1,2,3,4)
+%!error <X must be of class uint8> cmpermute (uint16 (magic (16)), jet (256))
+%!error <X must be an indexed image> cmpermute (1+i, jet (256))
+%!error <X must be an indexed image> cmpermute (sparse (1), jet (256))
+%!error <X must be an indexed image> cmpermute (0, jet (256))
+%!error <X must be an indexed image> cmpermute (1.5, jet (256))
+%!error <MAP must be a valid colormap> cmpermute (1, "a")
+%!error <MAP must be a valid colormap> cmpermute (1, i)
+%!error <MAP must be a valid colormap> cmpermute (1, ones (3,3,3))
+%!error <MAP must be a valid colormap> cmpermute (1, ones (3,2))
+%!error <MAP must be a valid colormap> cmpermute (1, [-1 1 1])
+%!error <MAP must be a valid colormap> cmpermute (1, [2 1 1])
+%!error <invalid parameter INDEX> cmpermute (1, [0 1 0;1 0 1], ones (3))
+%!error <invalid parameter INDEX> cmpermute (1, [0 1 0;1 0 1], 1:3)
--- a/inst/cmunique.m
+++ b/inst/cmunique.m
@@ -1,178 +1,203 @@
-## Copyright (C) 2004 Josep Mones i Teixidor <jmones@puntbarra.com>
+## Copyright (C) 2004 Josep Mones i Teixidor
+## Copyright (C) 2012 Rik Wehbring 
 ##
-## 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
-## Foundation; either version 3 of the License, or (at your option) any later
-## version.
+## This file is part of Octave.
 ##
-## This program 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.
+## 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.
 ##
-## You should have received a copy of the GNU General Public License along with
-## this program; if not, see <http://www.gnu.org/licenses/>.
+## 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
+## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {[@var{Y}, @var{newmap}] =} cmunique (@var{X}, @var{map})
+## @deftypefn  {Function File} {[@var{Y}, @var{newmap}] =} cmunique (@var{X}, @var{map})
 ## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] =} cmunique (@var{RGB})
 ## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] =} cmunique (@var{I})
-## Finds colormap with unique colors and corresponding image.
+## Convert an input image @var{X} to an ouput indexed image @var{Y} which uses
+## the smallest colormap possible @var{newmap}.
 ##
-## @code{[Y,newmap]=cmunique(X,map)} returns an indexed image @var{y}
-## along with its associated colormap @var{newmap} equivalent (which
-## produce the same image) to supplied @var{X} and its colormap
-## @var{map}; but eliminating any repeated rows in colormap colors and
-## adjusting indices in the image matrix as needed.
+## When the input is an indexed image (@var{X} with colormap @var{map}) the 
+## output is a colormap @var{newmap} from which any repeated rows have been
+## eliminated.  The output image, @var{Y}, is the original input image with
+## the indices adjusted to match the new, possibly smaller, colormap.
 ##
-## @code{[Y,newmap]=cmunique(RGB)} returns an indexed image @var{y}
-## along with its associated colormap @var{newmap} computed from a
-## true-color image @var{RGB} (a m-by-n-by-3 array), where @var{newmap}
-## is the smallest colormap possible (alhough it could be as long as
-## number of pixels in image).
+## When the input is an RGB image (an @nospell{MxNx3} array), the output
+## colormap will contain one entry for every unique color in the original image.
+## In the worst case the new map could have as many rows as the number of
+## pixels in the original image.
 ##
-## @code{[Y,newmap]=cmunique(I)} returns an indexed image @var{y}
-## along with its associated colormap @var{newmap} computed from a
-## intensity image @var{I}, where @var{newmap} is the smallest
-## colormap possible (alhough it could be as long as number of pixels
-## in image).
+## When the input is a grayscale image @var{I}, the output colormap will
+## contain one entry for every unique intensity value in the original image.
+## In the worst case the new map could have as many rows as the number of
+## pixels in the original image.
 ##
-## @strong{Notes:}
+## Implementation Details:
 ##
-## @var{newmap} is always a @var{m}-by-3 matrix, even if input image is
-## a intensity grey-scale image @var{I} (all three RGB planes are
+## @var{newmap} is always an Mx3 matrix, even if the input image is
+## an intensity grayscale image @var{I} (all three RGB planes are
 ## assigned the same value).
 ##
-## @var{newmap} is always of class double. If we use a RGB or intensity
-## image of class uint8 or uint16, the colors in the colormap will be of
-## class double in the range [0,1] (they are divided by intmax("uint8")
-## and intmax("uint16") respectively.
+## The output image is of class uint8 if the size of the new colormap is
+## less than or equal to 256.  Otherwise, the output image is of class double.
 ##
+## @seealso{rgb2ind, gray2ind}
 ## @end deftypefn
 
-function [Y, newmap] = cmunique (P1, P2)
-  if (nargin<1 || nargin>2)
-    print_usage;
+
+## Author:  Josep Mones i Teixidor <jmones@puntbarra.com>
+
+function [Y, newmap] = cmunique (X, map)
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
   endif
-  
 
-  if(nargin==2)
+  cls = class (X);
+  ## FIXME: Documentation accepts only 3 classes.  Could easily add 'single'.
+  if (! any (isa (X, {"uint8", "uint16", "double"})))
+    error ("cmunique: X is of invalid data type '%s'", cls);
+  endif
+
+  if (nargin == 2)
     ## (X, map) case
-    [newmap,i,j]=unique(P2,'rows');                 ## calculate unique colormap
-    if(isa(P1,"double"))
-      Y=j(P1);                                      ## find new indices
+    if (! isnumeric (map) || iscomplex (map)
+        || ndims (map) != 2 || columns (map) != 3
+        || any (map(:) < 0) || any (map(:) > 1))
+      error ("cmunique: MAP must be a valid colormap");
+    endif
+    [newmap,i,j] = unique (map, "rows");  # calculate unique colormap
+    if (isa (X, "double"))
+      Y = j(X);               # find new indices
     else
-      Y=j(double(P1)+1);                            ## find new indices
+      Y = j(double (X) + 1);  # find new indices
     endif
   else
-    switch(size(P1,3))
-      case(1)
+    switch (size (X,3))
+      case (1)
         ## I case
-        [newmap,i,j]=unique(P1);                        ## calculate unique colormap
-        newmap=repmat(newmap,1,3);                      ## get a RGB colormap
-        Y=reshape(j,rows(P1),columns(P1));              ## Y is j reshaped
-      case(3)
+        [newmap,i,j] = unique (X);               # calculate unique colormap
+        newmap = repmat (newmap,1,3);            # get a RGB colormap
+        Y = reshape (j, rows (X), columns (X));  # Y is j reshaped
+      case (3)
         ## RGB case
-        map=[P1(:,:,1)(:), P1(:,:,2)(:), P1(:,:,3)(:)]; ## build a map with all values
-        [newmap,i,j]=unique(map, 'rows');               ## calculate unique colormap
-        Y=reshape(j,rows(P1),columns(P1));              ## Y is j reshaped
+        ## build a map with all values
+        map = [X(:,:,1)(:), X(:,:,2)(:), X(:,:,3)(:)];
+        [newmap,i,j] = unique (map, "rows");     # calculate unique colormap
+        Y = reshape (j, rows (X), columns (X));  # Y is j reshaped
       otherwise
-        error("cmunique: first parameter is invalid.");
+        error ("cmunique: X is not a valid image");
     endswitch
     
     ## if image was uint8 or uint16 we have to convert newmap to [0,1] range
-    if(!isa(P1,"double"))
-      newmap=double(newmap)/double(intmax(class(P1)));
+    if (! isa (X, "double"))
+      newmap = double (newmap) / double (intmax (class (X)));
     endif
   endif
 
-  if(rows(newmap)<=256)
+  if (rows (newmap) <= 256)
     ## convert Y to uint8 (0-based indices then)
-    Y=uint8(Y-1);
+    Y = uint8 (Y-1);
   endif
-  
+
 endfunction
 
+
 %!demo
-%! [Y,newmap]=cmunique([1:4;5:8],[hot(4);hot(4)])
-%! # Both rows are equal since map maps colors to the same value
-%! # cmunique will give the same indices to both
+%! [Y, newmap] = cmunique ([1:4;5:8], [hot(4);hot(4)])
+%! ## Both rows are equal since map maps colors to the same value
+%! ## cmunique will give the same indices to both
 
-%!# This triggers invalid first parameter
-%!error(cmunique(zeros(3,3,2)));
-
-%!# Check that output is uint8 in short colormaps
+## Check that output is uint8 in short colormaps
 %!test
-%! [Y,newmap]=cmunique([1:4;5:8], [hot(4);hot(4)]);
-%! assert(Y,uint8([0:3;0:3]));
-%! assert(newmap,hot(4));
+%! [Y, newmap] = cmunique ([1:4;5:8], [hot(4);hot(4)]);
+%! assert (Y, uint8 ([0:3;0:3]));
+%! assert (newmap, hot (4));
 
-%!# Check that output is double in bigger
+## Check that output is double in bigger
 %!test
-%! [Y,newmap]=cmunique([1:300;301:600], [hot(300);hot(300)]);
-%! assert(Y,[1:300;1:300]);
-%! assert(newmap,hot(300));
+%! [Y, newmap] = cmunique ([1:300;301:600], [hot(300);hot(300)]);
+%! assert (Y, [1:300;1:300]);
+%! assert (newmap, hot (300));
 
-%!# Check boundary case 256
+## Check boundary case 256
 %!test
-%! [Y,newmap]=cmunique([1:256;257:512], [hot(256);hot(256)]);
-%! assert(Y,uint8([0:255;0:255]));
-%! assert(newmap,hot(256));
+%! [Y, newmap] = cmunique ([1:256;257:512], [hot(256);hot(256)]);
+%! assert (Y, uint8 ([0:255;0:255]));
+%! assert (newmap, hot (256));
 
-%!# Check boundary case 257
+## Check boundary case 257
 %!test
-%! [Y,newmap]=cmunique([1:257;258:514], [hot(257);hot(257)]);
-%! assert(Y,[1:257;1:257]);
-%! assert(newmap,hot(257));
+%! [Y, newmap] = cmunique ([1:257;258:514], [hot(257);hot(257)]);
+%! assert (Y, [1:257;1:257]);
+%! assert (newmap, hot (257));
 
-%!# Random RGB image
+## Random RGB image
 %!test
-%! RGB=rand(10,10,3);
-%! [Y,newmap]=cmunique(RGB);
-%! assert(RGB(:,:,1),newmap(:,1)(Y+1));
-%! assert(RGB(:,:,2),newmap(:,2)(Y+1));
-%! assert(RGB(:,:,3),newmap(:,3)(Y+1));
+%! RGB = rand (10,10,3);
+%! [Y, newmap] = cmunique (RGB);
+%! assert (RGB(:,:,1), newmap(:,1)(Y+1));
+%! assert (RGB(:,:,2), newmap(:,2)(Y+1));
+%! assert (RGB(:,:,3), newmap(:,3)(Y+1));
 
-%!# Random uint8 RGB image
+## Random uint8 RGB image
 %!test
-%! RGB=uint8(rand(10,10,3)*255);
-%! RGBd=double(RGB)/255;
-%! [Y,newmap]=cmunique(RGB);
-%! assert(RGBd(:,:,1),newmap(:,1)(Y+1));
-%! assert(RGBd(:,:,2),newmap(:,2)(Y+1));
-%! assert(RGBd(:,:,3),newmap(:,3)(Y+1));
+%! RGB = uint8 (rand (10,10,3)*255);
+%! RGBd = double (RGB) / 255;
+%! [Y, newmap] = cmunique (RGB);
+%! assert (RGBd(:,:,1), newmap(:,1)(Y+1));
+%! assert (RGBd(:,:,2), newmap(:,2)(Y+1));
+%! assert (RGBd(:,:,3), newmap(:,3)(Y+1));
 
-%!# Random uint16 RGB image
+## Random uint16 RGB image
 %!test
-%! RGB=uint16(rand(10,10,3)*65535);
-%! RGBd=double(RGB)/65535;
-%! [Y,newmap]=cmunique(RGB);
-%! assert(RGBd(:,:,1),newmap(:,1)(Y+1));
-%! assert(RGBd(:,:,2),newmap(:,2)(Y+1));
-%! assert(RGBd(:,:,3),newmap(:,3)(Y+1));
+%! RGB = uint16 (rand (10,10,3)*65535);
+%! RGBd = double (RGB) / 65535;
+%! [Y, newmap] = cmunique (RGB);
+%! assert (RGBd(:,:,1), newmap(:,1)(Y+1));
+%! assert (RGBd(:,:,2), newmap(:,2)(Y+1));
+%! assert (RGBd(:,:,3), newmap(:,3)(Y+1));
 
-%!# Random I image
+## Random I image
+%!test
+%! I = rand (10,10);
+%! [Y, newmap] = cmunique (I);
+%! assert (I, newmap(:,1)(Y+1));
+%! assert (I, newmap(:,2)(Y+1));
+%! assert (I, newmap(:,3)(Y+1));
+
+## Random uint8 I image
 %!test
-%! I=rand(10,10);
-%! [Y,newmap]=cmunique(I);
-%! assert(I,newmap(:,1)(Y+1));
-%! assert(I,newmap(:,2)(Y+1));
-%! assert(I,newmap(:,3)(Y+1));
+%! I = uint8 (rand (10,10)*256);
+%! Id = double (I) / 255;
+%! [Y, newmap] = cmunique (I);
+%! assert (Id, newmap(:,1)(Y+1));
+%! assert (Id, newmap(:,2)(Y+1));
+%! assert (Id, newmap(:,3)(Y+1));
 
-%!# Random uint8 I image
+## Random uint16 I image
 %!test
-%! I=uint8(rand(10,10)*256);
-%! Id=double(I)/255;
-%! [Y,newmap]=cmunique(I);
-%! assert(Id,newmap(:,1)(Y+1));
-%! assert(Id,newmap(:,2)(Y+1));
-%! assert(Id,newmap(:,3)(Y+1));
+%! I = uint16 (rand (10,10)*65535);
+%! Id = double (I) / 65535;
+%! [Y,newmap] = cmunique (I);
+%! assert (Id,newmap (:,1)(Y+1));
+%! assert (Id,newmap (:,2)(Y+1));
+%! assert (Id,newmap (:,3)(Y+1));
 
-%!# Random uint16 I image
-%!test
-%! I=uint16(rand(10,10)*65535);
-%! Id=double(I)/65535;
-%! [Y,newmap]=cmunique(I);
-%! assert(Id,newmap(:,1)(Y+1));
-%! assert(Id,newmap(:,2)(Y+1));
-%! assert(Id,newmap(:,3)(Y+1));
+## Test input validation
+%!error cmpermute ()
+%!error cmpermute (1,2,3)
+%!error <X is of invalid data type> cmunique (single (magic (16)))
+%!error <MAP must be a valid colormap> cmunique (1, "a")
+%!error <MAP must be a valid colormap> cmunique (1, i)
+%!error <MAP must be a valid colormap> cmunique (1, ones (3,3,3))
+%!error <MAP must be a valid colormap> cmunique (1, ones (3,2))
+%!error <MAP must be a valid colormap> cmunique (1, [-1 1 1])
+%!error <MAP must be a valid colormap> cmunique (1, [2 1 1])