Mercurial > hg > octave-image
view inst/imcast.m @ 886:a0c42a32c6c4
Move conversion between each image type to imcast.
* im2double.m, im2int16.m, im2single.m, im2uint16.m, im2uint8.m: move code
into imcast. Fix several small bugs mainly dealing with indexed and logical
images, small precision for Matlab compatibility, and increased performance.
Expanded documentation. Added new tests.
* imcast.m: implement the conversion between each image type instead of being
a wrapper around functions for each conversion. This reduces code duplication,
and places all very similar (but not equal) code together so that a bug fix in
one can be easily notices that requires application in others. Expand
documetation. Add more tests.
* private/imconversion.m, private/im2float.m: remove no longer necessary
function since this has all been moved to imcast.
* COPYING: remove license for private/im2float.m and private/imconversion.m.
* NEWS: make note of bug fixes for this functions.
author | Carnë Draug <carandraug@octave.org> |
---|---|
date | Mon, 24 Mar 2014 22:00:05 +0000 |
parents | 40269ff6760d |
children |
line wrap: on
line source
## Copyright (C) 2014 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 ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## 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. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see <http://www.gnu.org/licenses/>. ## -*- texinfo -*- ## @deftypefn {Function File} {} imcast (@var{img}, @var{type}) ## @deftypefnx {Function File} {} imcast (@var{img}, @var{type}, "indexed") ## Convert image to specific data type @var{type}. ## ## Converts a valid image @var{img} into another class @var{type}. A valid ## image must be of class logical, uint8, uint16, int16, single, or double. ## Conversion of images of class logical is valid, but not the inverse, i.e., ## conversion of images into logical class is not supported. Use of ## @code{im2bw} is recommended for such cases. ## ## If the image is indexed, the last argument may be the string ## @qcode{"indexed"}. An indexed image may not be of class int16 or ## single (see @code{isind} for details). ## ## Details on how the conversion is performed is class dependent, and can ## be seen on the help text of @code{im2double}, @code{im2single}, ## @code{im2uint8}, @code{im2uint16}, and @code{im2int16}. ## ## @seealso{im2bw, im2uint8, im2double, im2int16, im2single, im2uint16} ## @end deftypefn function imout = imcast (img, outcls, varargin) if (nargin < 2 || nargin > 3) print_usage (); elseif (nargin == 3 && ! strcmpi (varargin{1}, "indexed")) error ("imcast: third argument must be the string \"indexed\""); endif incls = class (img); if (strcmp (outcls, incls)) imout = img; return endif ## we are dealing with indexed images if (nargin == 3) if (! isind (img)) error ("imcast: input should have been an indexed image but it is not."); endif ## Check that the new class is enough to hold all the previous indices ## If we are converting to floating point, then we don't bother ## check the range of indices. Also, note that indexed images of ## integer class are always unsigned. ## we will be converting a floating point image to integer class if (strcmp (outcls, "single") || strcmp (outcls, "double")) if (isinteger (img)) imout = cast (img, outcls) +1; else imout = cast (img, outcls); endif ## we will be converting an indexed image to integer class else if (isinteger (img) && intmax (incls) > intmax (outcls) && max (img(:)) > intmax (outcls)) error ("imcast: IMG has too many colours '%d' for the range of values in %s", max (img(:)), outcls); elseif (isfloat (img)) imax = max (img(:)) -1; if (imax > intmax (outcls)) error ("imcast: IMG has too many colours '%d' for the range of values in %s", imax, outcls); endif img -= 1; endif imout = cast (img, outcls); endif ## we are dealing with "normal" images else problem = false; # did we found a bad conversion? switch (incls) case {"double", "single"} switch (outcls) case "uint8", imout = uint8 (img * 255); case "uint16", imout = uint16 (img * 65535); case "int16", imout = int16 (double (img * uint16 (65535)) -32768); case {"double", "single"}, imout = cast (img, outcls); otherwise, problem = true; endswitch case {"uint8"} switch (outcls) case "double", imout = double (img) / 255; case "single", imout = single (img) / 255; case "uint16", imout = uint16 (img) * 257; # 257 comes from 65535/255 case "int16", imout = int16 ((double (img) * 257) -32768); # 257 comes from 65535/255 otherwise, problem = true; endswitch case {"uint16"} switch (outcls) case "double", imout = double (img) / 65535; case "single", imout = single (img) / 65535; case "uint8", imout = uint8 (img / 257); # 257 comes from 65535/255 case "int16", imout = int16 (double (img) -32768); otherwise, problem = true; endswitch case {"logical"} switch (outcls) case {"double", "single"} imout = cast (img, outcls); case {"uint8", "uint16", "int16"} imout = repmat (intmin (outcls), size (img)); imout(img) = intmax (outcls); otherwise problem = true; endswitch case {"int16"} switch (outcls) case "double", imout = (double (img) + 32768) / 65535; case "single", imout = (single (img) + 32768) / 65535; case "uint8", imout = uint8 ((double (img) + 32768) / 257); # 257 comes from 65535/255 case "uint16", imout = uint16 (double (img) + 32768); otherwise, problem = true; endswitch otherwise error ("imcast: unknown image of class \"%s\"", incls); endswitch if (problem) error ("imcast: unsupported TYPE \"%s\"", outcls); endif endif endfunction %!test %! im = randi ([0 255], 40, "uint8"); %! assert (imcast (im, "uint8"), im2uint8 (im)) %! assert (imcast (im, "uint16"), im2uint16 (im)) %! assert (imcast (im, "single"), im2single (im)) %! assert (imcast (im, "uint8", "indexed"), im2uint8 (im, "indexed")) %! assert (imcast (im, "uint16", "indexed"), im2uint16 (im, "indexed")) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test %! im = randi ([1 256], 40, "double"); %! assert (imcast (im, "uint8"), im2uint8 (im)) %! assert (imcast (im, "uint8", "indexed"), im2uint8 (im, "indexed")) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test %! im = randi ([0 65535], 40, "uint16"); %! assert (imcast (im, "uint8"), im2uint8 (im)) %! assert (imcast (im, "single"), im2single (im)) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test %! im = randi ([1 255], 40, "double"); %! assert (imcast (im, "uint8", "indexed"), im2uint8 (im, "indexed")) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test %! im = rand (40); %! assert (imcast (im, "uint8"), im2uint8 (im)) %!error <unknown image of class> imcast (randi (127, 40, "int8"), "uint8") %!error <unsupported TYPE> imcast (randi (255, 40, "uint8"), "uint32") %!error <unsupported TYPE> imcast (randi (255, 40, "uint8"), "not a class") %!error <range of values> imcast (randi ([0 65535], 40, "uint16"), "uint8", "indexed")