Mercurial > octave-dspies
changeset 15693:a1b634240352
maint: merge default into image-overhaul head, specially changeset 806ea52. Resolving many conflicts and fixing bugs related to correctly indexing on image class (float vs integer have different offset)
author | Carnë Draug <carandraug+dev@gmail.com> |
---|---|
date | Wed, 28 Nov 2012 06:01:09 +0100 |
parents | 37a21f615d67 (diff) 806ea52af230 (current diff) |
children | 0f924f0b0be3 |
files | scripts/image/gray2ind.m scripts/image/ind2gray.m scripts/image/ind2rgb.m scripts/image/private/ind2x.m scripts/image/rgb2ind.m |
diffstat | 5 files changed, 152 insertions(+), 87 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/image/gray2ind.m Tue Nov 27 16:38:13 2012 -0800 +++ b/scripts/image/gray2ind.m Wed Nov 28 06:01:09 2012 +0100 @@ -28,16 +28,16 @@ ## 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 if @var{n} is less than or equal to -## 256. Otherwise, the output is of class uint16. -## @seealso{ind2gray, rgb2ind} +## 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. +## @seealso{ind2gray, rgb2ind} ## @end deftypefn ## Author: Tony Richardson <arichard@stark.cc.oh.us> ## Created: July 1994 ## Adapted-By: jwe -function [img, map] = gray2ind (I, n = 64) +function [I, map] = gray2ind (I, n = 64) if (nargin < 1 || nargin > 2) print_usage (); @@ -45,55 +45,59 @@ error ("gray2ind: I must be a grayscale or binary image"); 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"); endif + + ## default n is different if image is logical + if (nargin == 1 && islogical (I)) + 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"}))) error ("gray2ind: invalid data type '%s'", cls); - elseif (isfloat (I) && (any (I(:) < 0) || any (I(:) > 1))) + elseif (isfloat (I) && (min (I(:) < 0) || max (I(:) > 1))) error ("gray2ind: floating point images may only contain values between 0 and 1"); endif - ## Create grayscale colormap - if (nargin == 1 && islogical (I)) - n = 2; - endif map = gray (n); ## Set up scale factor if (isinteger (I)) - low = intmin (cls); - if (low != 0) - I -= low; # shift to zero-based indexing - endif - scale = double (intmax (cls)) - double (low); + low = double (intmin (cls)); + scale = double (intmax (cls)) - low; + I = double (I) - low; else - scale = 1; # floating point doesn't need scaling + scale = 1; endif - - ## Scale image - img = I * ((n-1)/scale); - - ## Round and convert to appropriate output type. ## Note: no separate call to round () necessary because ## type conversion does that automatically. - if (n <= 256) - img = uint8 (img) + 1; + I = I * ((n-1)/scale); + if (n < 256) + I = uint8 (I); + elseif (n < 65536) + I = uint16 (I); else - img = uint16 (img) + 1; + ## 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 ([1 17 33 64])) -%!assert (gray2ind ([0 0.25 0.5 1], 400), uint16 ([1 101 201 400])) -%!assert (gray2ind (logical ([1 0 0 1])), uint8 ([2 1 1 2])) -%!assert (gray2ind (uint8 ([0 64 128 192 255])), uint8 ([1 17 33 48 64])) +%!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])) +%!assert (gray2ind (uint8 ([0 64 128 192 255])), uint8 ([0 16 32 47 63])) %!test %! i2g = ind2gray (1:100, gray (100)); %! g2i = gray2ind (i2g, 100); -%! assert (g2i, uint8 (1:100)); +%! assert (g2i, uint8 (0:99)); %% Test input validation %!error gray2ind ()
--- a/scripts/image/ind2gray.m Tue Nov 27 16:38:13 2012 -0800 +++ b/scripts/image/ind2gray.m Wed Nov 28 06:01:09 2012 +0100 @@ -20,8 +20,10 @@ ## @deftypefn {Function File} {@var{I} =} ind2gray (@var{x}) ## @deftypefnx {Function File} {@var{I} =} ind2gray (@var{x}, @var{map}) ## Convert a color indexed image to a grayscale intensity image. +## ## If @var{map} is omitted, the current colormap is used to determine the -## intensities. +## intensities. If it doesn't contain enough colors, it is padded it with the +## last color in the map. ## ## The output @var{I} is of the same class as the input @var{x} and may be ## one of @code{uint8}, @code{uint16}, @code{single}, or @code{double}. @@ -38,32 +40,19 @@ ## Created: July 1994 ## Adapted-By: jwe -function I = ind2gray (x, map) +function I = ind2gray (x, map = colormap ()) if (nargin < 1 || nargin > 2) print_usage (); endif - - if (! isreal (x) || issparse (x) - || (isfloat (x) && (any (x(:) < 1 || any (x(:) != fix (x(:))))))) - error ("ind2gray: X must be an indexed image"); - endif - cls = class (x); - if (! any (isa (x, {"logical", "uint8", "uint16", "single", "double"}))) - error ("ind2gray: invalid data type '%s'", cls); - endif - - if (nargin == 1) - map = colormap (); - elseif (! iscolormap (map)) - error ("ind2gray: MAP must be a valid colormap"); - endif + [x, map] = ind2x ("ind2rgb", x, map); ## Convert colormap to luminance intensity values - map *= [0.299; 0.587; 0.114]; + map *= [0.29894; 0.58704; 0.11402]; - ## Convert colormap to same class as that of input so that - ## indexing in colormap will produce output of the same type as the input. + ## Convert colormap to same class as that of input so that when reshape + ## later, produces output of the same type as the input + cls = class (x); if (isinteger (x)) map *= intmax (cls); elseif (strcmp (cls, "single")) @@ -75,12 +64,10 @@ endfunction - -%!test +%!shared i2g %! i2g = ind2gray (1:100, gray (100)); -%! assert (i2g, 0:1/99:1, eps); -%! g2i = gray2ind (i2g, 100); -%! assert (g2i, uint8 (1:100)); +%!assert (i2g, 0:1/99:1, eps); +%!assert (gray2ind (i2g, 100), uint8 (0:99)); %%test input validation %!error ind2gray ()
--- a/scripts/image/ind2rgb.m Tue Nov 27 16:38:13 2012 -0800 +++ b/scripts/image/ind2rgb.m Wed Nov 28 06:01:09 2012 +0100 @@ -36,35 +36,12 @@ ## Created: July 1994 ## Adapted-By: jwe -function [R, G, B] = ind2rgb (x, map) +function [R, G, B] = ind2rgb (x, map = colormap ()) if (nargin < 1 || nargin > 2) print_usage (); endif - - if (! isreal (x) || issparse (x) - || (isfloat (x) && (any (x(:) < 1 || any (x(:) != fix (x(:))))))) - error ("ind2rgb: X must be an indexed image"); - endif - cls = class (x); - if (! any (isa (x, {"logical", "uint8", "uint16", "single", "double"}))) - error ("ind2rgb: invalid data type '%s'", cls); - endif - - if (nargin == 1) - map = colormap (); - elseif (! iscolormap (map)) - error ("ind2rgb: MAP must be a valid colormap"); - endif - - ## Do we have enough colors in the color map? - maxidx = max (x(:)); - rm = rows (map); - if (rm < maxidx) - ## Pad with the last color in the map. - pad = repmat (map(end,:), maxidx-rm, 1); - map(end+1:maxidx, :) = pad; - endif + [x, map] = ind2x ("ind2rgb", x, map); ## Compute result [row, col] = size (x); @@ -80,8 +57,27 @@ endfunction - -%% FIXME: Need some functional tests or %!demo blocks +%!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 +%! 0.2 0.4 0.6 +%! 0.4 0.4 0.5 +%! 0.3 0.7 1.0 +%! 0.1 0.5 0.8]; +%! ergb(:,:,1) = [0.2 0.3 0.1; 0.4 0.2 0.1; 0.0 0.2 0.3]; +%! ergb(:,:,2) = [0.4 0.7 0.5; 0.4 0.4 0.5; 0.0 0.4 0.7]; +%! ergb(:,:,3) = [0.6 1.0 0.8; 0.5 0.6 0.8; 0.0 0.6 1.0]; +%! ## test basic usage with 1 and 3 outputs +%! [rgb] = ind2rgb (img, map); +%! [r, g, b] = ind2rgb (img, map); +%!assert (ergb, rgb); +%!assert (ergb, reshape ([r(:) g(:) b(:)], [size(img) 3])); +%! ## test correction for integers +%! img = uint8 (img -1); +%! [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)") %%test input validation %!error ind2rgb () @@ -97,4 +93,3 @@ %!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]) -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/image/private/ind2x.m Wed Nov 28 06:01:09 2012 +0100 @@ -0,0 +1,56 @@ +## Copyright (C) 1994-2012 John W. Eaton +## Copyright (C) 2012 Carnë Draug +## +## 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 +## <http://www.gnu.org/licenses/>. + +## private function for the ind2something functions which have a lot of code +## in common + +function [x, map] = ind2x (name, 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); + endif + + ## Check the color map. + if (! iscolormap (map)) + error ("%s: MAP must be a valid colormap", name); + 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 + maxidx = max (x(:)); + if (isinteger (x)) + if (maxidx == intmax (class (x))) + x = single (x); + endif + x += 1; + maxidx += 1; + endif + + rm = rows (map); + if (rm < maxidx) + ## Pad with the last color in the map. + pad = repmat (map(end,:), maxidx-rm, 1); + map(end+1:maxidx, :) = pad; + endif + +endfunction
--- a/scripts/image/rgb2ind.m Tue Nov 27 16:38:13 2012 -0800 +++ b/scripts/image/rgb2ind.m Wed Nov 28 06:01:09 2012 +0100 @@ -1,4 +1,5 @@ ## Copyright (C) 1994-2012 John W. Eaton +## Copyright (C) 2012 Carnë Draug ## ## This file is part of Octave. ## @@ -23,7 +24,6 @@ ## @seealso{ind2rgb, rgb2hsv, rgb2ntsc} ## @end deftypefn -## Bugs: The color map may have duplicate entries. ## 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 ## Author: Tony Richardson <arichard@stark.cc.oh.us> @@ -51,15 +51,38 @@ x = reshape (1:numel (R), size (R)); - map = [R(:), G(:), B(:)]; + map = unique([R(:) G(:) B(:)], "rows"); + [~, x] = ismember ([R(:) G(:) B(:)], map, "rows"); + x = reshape (x, size (R)); + ## a colormap is of class double and values between 0 and 1 + switch class (R) + case {"single", "double", "logical"} + ## do nothing, return the same + case {"uint8", "uint16"} + map = double (map) / double (intmax (class (R))); + case "int16" + map = (double (im) + 32768) / 65535; + otherwise + error ("unsupported image class %s", im_class); + endswitch + + ## we convert to the smallest class necessary to encode the image. Matlab + ## documentation does not mention what it does when uint16 is not enough... + ## When an indexed image is of integer class, there's a -1 offset to the + ## colormap, hence the adjustment + if (rows (map) < 256) + x = uint8 (x - 1); + elseif (rows (map) < 65536) + x = uint16 (x - 1); + 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) -