1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
########################################################################
##
## Copyright (C) 2004-2024 The Octave Project Developers
##
## See the file COPYRIGHT.md in the top-level directory of this
## distribution or <https://octave.org/copyright/>.
##
## 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{Y}, @var{newmap}] =} cmpermute (@var{X}, @var{map})
## @deftypefnx {} {[@var{Y}, @var{newmap}] =} cmpermute (@var{X}, @var{map}, @var{index})
## Reorder colors in a colormap.
##
## 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}.
##
## When called with an optional third argument the order of colors in the new
## colormap is defined by @var{index}.
##
## @strong{Caution:} @var{index} should not have repeated elements or the
## function will fail.
##
## @end deftypefn
function [Y, newmap] = cmpermute (X, map, index)
if (nargin < 2)
print_usage ();
endif
cls = class (X);
if (! any (strcmp (cls, {"uint8", "uint16", "single", "double"})))
error ("cmpermute: invalid data type '%s'", cls);
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 (! iscolormap (map) || min (map(:)) < 0 || max (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,:);
## build reverse index
rindex = zeros (size (index));
rindex(index) = 1:length (index);
## preserve class of input image in output
if (strcmp (cls, "double"))
Y = rindex(X);
elseif (strcmp (cls, "single"))
rindex = single (rindex);
Y = rindex(X);
else
## adapt indices
rindex = feval (cls, rindex - 1);
## 0-based indices
Y = rindex(single (X) + 1);
endif
endfunction
%!demo
%! [Y, newmap] = cmpermute ([1:4], hot (4), 4:-1:1)
%! ## colormap will be arranged in reverse order (so will image)
%!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));
%!test # reverse map, 0-based index
%! [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 = 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));
%!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);
## Test input validation
%!error <Invalid call> cmpermute ()
%!error <Invalid call> cmpermute (1)
%!error <invalid data type 'uint32'> cmpermute (uint32 (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)
|