changeset 613:c33c12769b71

im2bw: added tests, use more of other functions, more input check at start, support for int16 input images
author carandraug
date Wed, 26 Sep 2012 07:23:53 +0000
parents 7c1df1b5f058
children 3a17c7402cc3
files NEWS inst/im2bw.m
diffstat 2 files changed, 64 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS
+++ b/NEWS
@@ -53,6 +53,7 @@
       bwfill
       imhist
       conndef
+      im2bw
       im2double
       im2uint8
       im2uint16
@@ -67,6 +68,9 @@
     weighted conversion to keep the image luminance instead of a the mean
     through each color.
 
+ ** `im2bw' now supports input images of the int16 class and deals better with
+    RGB images since it uses `rgb2gray' internally (see changes to rgb2gray).
+
  ** `imhist' is much more compatible with matlab and among other changes,
     it now uses the whole range of the class for the histogram rather than
     the minimum and maximum of the input image.
--- a/inst/im2bw.m
+++ b/inst/im2bw.m
@@ -1,4 +1,5 @@
 ## Copyright (C) 2000 Kai Habel <kai.habel@gmx.de>
+## Copyright (C) 2012 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
@@ -14,56 +15,74 @@
 ## this program; if not, see <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {@var{BW} =} im2bw (@var{I}, threshold)
+## @deftypefn {Function File} {@var{BW} =} im2bw (@var{img}, threshold)
 ## @deftypefnx {Function File} {@var{BW} =} im2bw (@var{X}, @var{cmap}, threshold)
-## Converts image data types to a black-white (binary) image.
-## The treshold value should be in the range [0,1].
+## Convert image to binary, black and white, by threshold.
+##
+## The input image @var{img} can either be a grayscale or RGB image.  In the later
+## case, @var{img} is first converted to grayscale with @code{rgb2gray}.  Input
+## can also be an indexed image @var{X} in which case the colormap @var{cmap}
+## needs to be specified.
+##
+## The value of @var{threshold} should be in the range [0,1] independently of the
+## class of @var{img}.  Values from other classes can be converted to the correct
+## value with @code{im2double} for example.  For an automatic threshold, consider
+## using @code{graythresh}.
+##
+## @example
+## @group
+## bw = im2bw (img, graythresh (img));
+## @end group
+## @end example
+##
+## @seealso{graythresh, ind2gray, rgb2gray}
 ## @end deftypefn
 
-function BW = im2bw (img, a, b)
-  if (nargin < 2 || nargin > 3)
+function BW = im2bw (img, cmap, thres)
+  if (nargin < 1 || nargin > 3)
     print_usage;
+  elseif (nargin == 3 && !isind (img))
+    error ("im2bw: there must be only two arguments for non indexed images")
+  elseif (nargin == 3 && !iscolormap (cmap))
+    error ("im2bw: `cmap' must be the a colormap for indexed images")
+  elseif (nargin == 2)
+    thres = cmap;
   endif
-  
+
+  if (!isnumeric || !isscalar (thres) || !isreal (thres) || !isa (thres, "double") || thres < 0 || thres > 1)
+    error ("im2bw: `threshold' must be a scalar of class double in the interval [0, 1]")
+  endif
+
   ## Convert img to gray scale
-  if (isrgb(img))
-    img = rgb2gray(img);
-    if (nargin != 2)
-      error("im2bw: two input arguments must be given when the image is a color image");
-    endif
-    t = a;
-  elseif (isind (img) && ismatrix(a) && columns (a) == 3)
-    img = ind2gray (img, a);
-    if (nargin != 3)
-      error("im2bw: three input arguments must be given when the image is indexed");
-    endif
-    t = b;
-  elseif (isgray(img))
-    if (nargin != 2)
-      error("im2bw: two input arguments must be given when the image is gray scale");
-    endif
-    t = a;
+  if (nargin == 3)
+    ## indexed image (we already checked that is indeed indexed earlier)
+    img = ind2gray (img, cmap);
+  elseif (isrgb (img))
+    img = rgb2gray (img);
+  elseif (isgray (img))
+    ## do nothing. All is good
   else
     error ("im2bw: first input argument must be an image");
   endif
 
-  ## Do the thresholding
-  if (isscalar (t))
-    if (t < 0 || t > 1)
-      error("im2bw: threshold must be in the interval [0, 1]");
-    endif
-    switch (class(img))
-      case {"double", "single"}
-        BW = (img >= t);
-      case {"uint8"}
-        BW = (img >= 255*t);
-      case {"uint16"}
-        BW = (img >= 65535*t);
-      otherwise
-        error("im2bw: unsupport image class");
-    endswitch
-  else
-    error ("im2bw: threshold value must be scalar");
-  endif
+  ## Convert the threshold value to same image class to do the thresholding which
+  ## is faster than converting the image to double and keep the threshold value
+  switch (class (img))
+    case {"double", "single"}
+      ## do nothing
+    case {"uint8"}
+      thres = im2uint8 (thres);
+    case {"uint16"}
+      thres = im2uint16 (thres);
+    case {"int16"}
+      thres = im2int16 (thres);
+    otherwise
+      ## we should have never got here in the first place anyway
+      error("im2bw: unsupported image class");
+  endswitch
 
+  BW = (img >= thres);
 endfunction
+
+%!assert(im2bw ([0 0.5 1], 0.5), [0 1 1]);                   # basic usage
+%!assert(im2bw (uint8 ([0 120 255], 0.5)), [0 0 1]);         # with a uint8 input