Mercurial > hg > octave-image
diff 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 (2014-03-24) |
parents | 40269ff6760d |
children |
line wrap: on
line diff
--- a/inst/imcast.m +++ b/inst/imcast.m @@ -18,20 +18,24 @@ ## @deftypefnx {Function File} {} imcast (@var{img}, @var{type}, "indexed") ## Convert image to specific data type @var{type}. ## -## This is the same as calling one of the following +## 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. ## -## @itemize @bullet -## @item im2double -## @item im2int16 -## @item im2single -## @item im2uint8 -## @item im2uint16 -## @end itemize +## 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). ## -## @seealso{im2uint8, im2double, im2int16, im2single, im2uint16} +## 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 img = imcast (img, itype, varargin) +function imout = imcast (img, outcls, varargin) if (nargin < 2 || nargin > 3) print_usage (); @@ -39,18 +43,107 @@ error ("imcast: third argument must be the string \"indexed\""); endif - ## We could confirm that the image really is an indexed image in - ## case the user says so, but the functions im2xxx already do it. + 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) - switch itype - case "double", img = im2double (img, varargin{:}); - case "uint8", img = im2uint8 (img, varargin{:}); - case "uint16", img = im2uint16 (img, varargin{:}); - case "single", img = im2single (img, varargin{:}); - case "int16", img = im2int16 (img, varargin{:}); - otherwise - error ("imcast: unsupported TYPE \"%s\"", itype); - endswitch + 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 @@ -73,7 +166,6 @@ %! im = randi ([0 65535], 40, "uint16"); %! assert (imcast (im, "uint8"), im2uint8 (im)) %! assert (imcast (im, "single"), im2single (im)) -%! assert (imcast (im, "uint8", "indexed"), im2uint8 (im, "indexed")) %! assert (imcast (im, "single", "indexed"), im2single (im, "indexed")) %!test @@ -85,6 +177,8 @@ %! 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")