1## Copyright (C) 2000 Kai Habel <kai.habel@gmx.de>
2## Copyright (C) 2012-2016 Carnë Draug <carandraug@octave.org>
3##
4## This program is free software; you can redistribute it and/or
5## modify it under the terms of the GNU General Public License as
6## published by the Free Software Foundation; either version 3 of the
7## License, or (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful, but
10## WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12## General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, see
16## <http:##www.gnu.org/licenses/>.
17
18## -*- texinfo -*-
19## @deftypefn  {Function File} {} im2bw (@var{img})
20## @deftypefnx {Function File} {} im2bw (@var{X}, @var{cmap})
21## @deftypefnx {Function File} {} im2bw (@dots{}, @var{threshold})
22## @deftypefnx {Function File} {} im2bw (@dots{}, @var{method})
23## Convert image to binary, black and white, by threshold.
24##
25## The input image @var{img} can either be a grayscale or RGB image.  In the later
26## case, @var{img} is first converted to grayscale with @code{rgb2gray}.  Input
27## can also be an indexed image @var{X} in which case the colormap @var{cmap}
28## needs to be specified.
29##
30## The value of @var{threshold} should be in the range [0,1] independently of the
31## class of @var{img}.  Values from other classes can be converted to the correct
32## value with @code{im2double}:
33##
34## @example
35## bw = im2bw (img_of_class_uint8, im2double (thresh_of_uint8_class));
36## @end example
37##
38## For an automatic threshold value, consider using @code{graythresh}.
39## The argument @var{method} is a string that specifies a valid algorithm
40## available in @code{graythresh}.  The following are equivalent:
41##
42## @example
43## bw = im2bw (img, "moments");
44## bw = im2bw (img, graythresh (img, "moments"));
45## @end example
46##
47## @seealso{graythresh, ind2gray, otsuthresh, rgb2gray}
48## @end deftypefn
49
50function BW = im2bw (img, cmap, thresh = 0.5)
51
52  if (nargin < 1 || nargin > 3)
53    print_usage ();
54  elseif (nargin == 3 && ! isind (img))
55    error ("im2bw: IMG must be an indexed image when are 3 input arguments");
56  elseif (nargin == 3 && ! iscolormap (cmap))
57    error ("im2bw: CMAP must be a colormap");
58  elseif (nargin == 2)
59    thresh = cmap;
60  endif
61
62  if (! isimage (img))
63    error ("im2bw: IMG must be an image");
64  elseif (! ischar (thresh) && ! (isnumeric (thresh) && isscalar (thresh)
65                                  && thresh >= 0 && thresh <= 1))
66    error ("im2bw: THRESHOLD must be a string or a scalar in the interval [0 1]");
67  endif
68
69  if (islogical (img))
70    warning ("im2bw: IMG is already binary so nothing is done");
71    tmp = img;
72
73  else
74    ## Convert img to gray scale
75    if (nargin == 3)
76      ## indexed image (we already checked that is indeed indexed earlier)
77      img = ind2gray (img, cmap);
78    elseif (isrgb (img))
79      img = rgb2gray (img);
80    else
81      ## Everything else, we do nothing, no matter how many dimensions
82    endif
83
84    if (ischar (thresh))
85      thresh = graythresh (img, thresh);
86    endif
87
88    ## Convert the threshold value to same class as the image which
89    ## is faster and saves more memory than the opposite.
90    if (isinteger (img))
91      ## We do the conversion from double to int ourselves (instead
92      ## of using im2uint* functions), because those functions round
93      ## during the conversion but we need thresh to be the limit.
94      ## See bug #46390.
95      cls = class(img);
96      I_min = double (intmin (cls));
97      I_range = double (intmax (cls)) - I_min;
98      thresh = cast (floor ((thresh * I_range) + I_min), cls);
99    elseif (isfloat (img))
100      ## do nothing
101    else
102      ## we should have never got here in the first place anyway
103      error ("im2bw: unsupported image of class '%s'", class (img));
104    endif
105
106    tmp = (img > thresh);
107  endif
108
109  if (nargout > 0)
110    BW = tmp;
111  else
112    imshow (tmp);
113  endif
114
115endfunction
116
117%!assert(im2bw ([0 0.4 0.5 0.6 1], 0.5), logical([0 0 0 1 1])); # basic usage
118%!assert(im2bw (uint8 ([0 100 255]), 0.5), logical([0 0 1]));   # with a uint8 input
119
120## We use "bw = im2bw (...)" because otherwise it would display a figure
121%!warning <is already binary so nothing is done> bw = im2bw (logical ([0 1 0]));
122%!warning <is already binary so nothing is done> bw = im2bw (logical ([0 1 0]), 1);
123
124%!test
125%! warning ("off", "all", "local");
126%! assert (im2bw (logical ([0 1 0])),    logical ([0 1 0]))
127%! assert (im2bw (logical ([0 1 0]), 0), logical ([0 1 0]))
128%! assert (im2bw (logical ([0 1 0]), 1), logical ([0 1 0]))
129
130## bug #46390 (on the rounding/casting of the threshold value)
131%!assert (nnz (im2bw (uint8 ([0:255]), 0.9)), 26)
132
133%!test
134%! img = uint8 ([0:255]);
135%! s = 0;
136%! for i=0:.1:1
137%!   s += nnz (im2bw (img, i));
138%! endfor
139%! assert (s, 1405)
140
141## threshold may be a negative value in the image class so care must
142## taken when casting and rounding it.
143%!assert (nnz (im2bw (int16 ([-128:127]), 0.499)), 194)
144%!assert (nnz (im2bw (int16 ([-128:127]), 0.500)), 128)
145%!assert (nnz (im2bw (int16 ([-128:127]), 0.501)), 62)
146
147%!test
148%! img = uint16 ([0:intmax("uint16")]);
149%! s = 0;
150%! for i=0:.1:1
151%!   s += nnz (im2bw (img, i));
152%! endfor
153%! assert (s, 360445)
154
155%!test
156%! img = int16 ([intmin("int16"):intmax("int16")]);
157%! s = 0;
158%! for i=0:.1:1
159%!   s += nnz (im2bw (img, i));
160%! endfor
161%! assert (s, 360445)
162
163%!test
164%! im = [((randn(10)/10)+.3) ((randn(10)/10)+.7)];
165%! assert (im2bw (im, "Otsu"), im2bw (im, graythresh (im, "Otsu")))
166%! assert (im2bw (im, "moments"), im2bw (im, graythresh (im, "moments")))
167
168%!test
169%! im = [((randn(10)/10)+.3) ((randn(10)/10)+.7)];
170%! im = reshape (im, [10 10 1 2]);
171%! assert (im2bw (im, "Otsu"), im2bw (im, graythresh (im, "Otsu")))
172%! assert (im2bw (im, "moments"), im2bw (im, graythresh (im, "moments")))
173