Mercurial > hg > octave-image
changeset 801:4598c2a5bf1a
bwmorph: some refactoring and compatibility fixes.
* bwmorph.m: remove many workarounds required for Octave versions pre 3.0.0,
and remove warnings about n>1. For matlab compatibility, convert n<0 to 1,
accept any numeric matrix as valid BW image, and display image if nargout
is 0. Use @strel to create structuring elements. Use function handles
rather than a string and eval, and removing many returns in the middle of
the code. Remove case-sensitivity for operation names. Add many tests.
author | Carnë Draug <carandraug@octave.org> |
---|---|
date | Wed, 09 Oct 2013 02:53:00 +0100 |
parents | 1e708656e295 |
children | bec6e07f4272 |
files | inst/bwmorph.m |
diffstat | 1 files changed, 484 insertions(+), 380 deletions(-) [+] |
line wrap: on
line diff
--- a/inst/bwmorph.m +++ b/inst/bwmorph.m @@ -1,4 +1,5 @@ ## Copyright (C) 2004 Josep Mones i Teixidor <jmones@puntbarra.com> +## Copyright (C) 2013 Carnë Draug <carandraug@octave.org> ## ## 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,80 +15,79 @@ ## this program; if not, see <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {@var{BW2} =} bwmorph (@var{BW}, @var{operation}) -## @deftypefnx {Function File} {@var{BW2} =} bwmorph (@var{BW}, @var{operation}, @var{n}) -## Perform a morphological operation on a binary image. -## -## BW2=bwmorph(BW,operation) performs a morphological operation -## specified by @var{operation} on binary image @var{BW}. All possible -## operations and their meaning are specified in a table below. +## @deftypefn {Function File} {} bwmorph (@var{bw}, @var{operation}) +## @deftypefnx {Function File} {} bwmorph (@var{bw}, @var{operation}, @var{n}) +## Perform morphological operation on binary image. ## -## BW2=bwmorph(BW,operation,n) performs a morphological operation -## @var{n} times. Keep in mind that it has no sense to apply some -## operations more than once, since some of them return the same result -## regardless how many iterations we request. Those return a warning if -## are called with n>1 and they compute the result for n=1. +## For a binary image @var{bw}, performs the morphological @var{operation}, +## @var{n} times. All possible values of @var{operation} are listed on the +## table below. By default, @var{n} is 1. If @var{n} is @code{Inf}, the +## operation is continually performed until it no longer changes the image. +## ## -## @var{n}>1 is actually used for the following operations: diag, -## dilate, erode, majority, shrink, skel, spur, thicken and thin. +## Note that the output will always be of class logical, independently of +## the class of @var{bw}. ## -## @table @code -## @item 'bothat' +## @table @samp +## @item bothat ## Performs a bottom hat operation, a closing operation (which is a ## dilation followed by an erosion) and finally substracts the original -## image. +## image (see @code{imbothat}). ## -## @item 'bridge' +## @item bridge ## Performs a bridge operation. Sets a pixel to 1 if it has two nonzero ## neighbours which are not connected, so it "bridges" them. There are ## 119 3-by-3 patterns which trigger setting a pixel to 1. ## -## @item 'clean' +## @item clean ## Performs an isolated pixel remove operation. Sets a pixel to 0 if all ## of its eight-connected neighbours are 0. ## -## @item 'close' +## @item close ## Performs closing operation, which is a dilation followed by erosion. -## It uses a ones(3) matrix as structuring element for both operations. +## It uses a ones(3) matrix as structuring element for both operations +## (see @code{imclose}). ## -## @item 'diag' +## @item diag ## Performs a diagonal fill operation. Sets a pixel to 1 if that ## eliminates eight-connectivity of the background. ## -## @item 'dilate' -## Performs a dilation operation. It uses ones(3) as structuring element. +## @item dilate +## Performs a dilation operation. It uses ones(3) as structuring element +## (see @code{imdilate}). ## -## @item 'erode' -## Performs an erosion operation. It uses ones(3) as structuring element. +## @item erode +## Performs an erosion operation. It uses ones(3) as structuring element +## (see @code{imerode}). ## -## @item 'fill' +## @item fill ## Performs a interior fill operation. Sets a pixel to 1 if all ## four-connected pixels are 1. ## -## @item 'hbreak' +## @item hbreak ## Performs a H-break operation. Breaks (sets to 0) pixels that are ## H-connected. ## -## @item 'majority' +## @item majority ## Performs a majority black operation. Sets a pixel to 1 if five ## or more pixels in a 3-by-3 window are 1. If not it is set to 0. ## -## @item 'open' +## @item open ## Performs an opening operation, which is an erosion followed by a -## dilation. It uses ones(3) as structuring element. +## dilation. It uses ones(3) as structuring element (see @code{imopen}). ## -## @item 'remove' +## @item remove ## Performs a iterior pixel remove operation. Sets a pixel to 0 if ## all of its four-connected neighbours are 1. ## -## @item 'shrink' +## @item shrink ## Performs a shrink operation. Sets pixels to 0 such that an object ## without holes erodes to a single pixel (set to 1) at or near its ## center of mass. An object with holes erodes to a connected ring lying ## midway between each hole and its nearest outer boundary. It preserves ## Euler number. ## -## @item 'skel' +## @item skel ## Performs a skeletonization operation. It calculates a "median axis ## skeleton" so that points of this skeleton are at the same distance of ## its nearby borders. It preserver Euler number. Please read @@ -96,7 +96,7 @@ ## It uses the same algorithm as skel-pratt but this could change for ## compatibility in the future. ## -## @item 'skel-lantuejol' +## @item skel-lantuejol ## Performs a skeletonization operation as described in Gonzalez & Woods ## "Digital Image Processing" pp 538-540. The text references Lantuejoul ## as authour of this algorithm. @@ -109,21 +109,21 @@ ## @var{n} times or number of iterations specified in algorithm ## description. It's most useful to run this algorithm with @code{n=Inf}. ## -## @item 'skel-pratt' +## @item skel-pratt ## Performs a skeletonization operation as described by William K. Pratt ## in "Digital Image Processing". ## -## @item 'spur' +## @item spur ## Performs a remove spur operation. It sets pixel to 0 if it has only ## one eight-connected pixel in its neighbourhood. ## -## @item 'thicken' +## @item thicken ## Performs a thickening operation. This operation "thickens" objects ## avoiding their fusion. Its implemented as a thinning of the ## background. That is, thinning on negated image. Finally a diagonal ## fill operation is performed to avoid "eight-connecting" objects. ## -## @item 'thin' +## @item thin ## Performs a thinning operation. When n=Inf, thinning sets pixels to 0 ## such that an object without holes is converted to a stroke ## equidistant from its nearest outer boundaries. If the object has @@ -132,10 +132,10 @@ ## without holes to a single pixels and thin to a stroke. It preserves ## Euler number. ## -## @item 'tophat' +## @item tophat ## Performs a top hat operation, a opening operation (which is an ## erosion followed by a dilation) and finally substracts the original -## image. +## image (see @code{imtophat}). ## @end table ## ## Some useful concepts to understant operators: @@ -161,11 +161,6 @@ ## ## @strong{Compatibility notes:} ## @table @code -## @item 'fill' -## Checking MATLAB behaviour is needed because its documentation doesn't -## make clear if it creates a black pixel if all eight-connected pixels -## are black or if four-connected suffice (as we do currently following -## Pratt's book). ## @item 'skel' ## Algorithm used here is described in Pratt's book. When applying it to ## the "circles" image in MATLAB documentation, results are not the @@ -187,219 +182,215 @@ ## @seealso{imdilate, imerode, imtophat, imbothat, makelut, applylut} ## @end deftypefn -## TODO: As soon as Octave doesn't segfault when assigning values to a -## TODO: bool matrix, remove all conversions from lut to logical and -## TODO: just create it as a logical from the beginning. - -## TODO: n behaviour should be tested in all cases for compatibility. +function bw2 = bwmorph (bw, operation, n = 1) + if (nargin < 2 || nargin > 3) + print_usage (); + elseif (! ismatrix (bw) || ! (isbool (bw) || isnumeric (bw))) + ## we can't use isbw because we must accept anything numeric or boolean + ## which will then be converted into boolean anyway. + error ("bwmorph: BW must be a binary image"); + elseif (! ischar (operation)) + error ("bwmorph: OPERATION must be a string"); + elseif (! isnumeric (n) || ! isscalar (n)) + error ("bwmorph: N must be a scalar number"); + endif -function BW2 = bwmorph (BW, operation, n = 1) - if(nargin<2 || nargin>3) - print_usage; - elseif(n<0) - error("bwmorph: n should be > 0"); - elseif(n==0) ## we'll just return the same matrix (check this!) - BW2=BW; + ## For undocumented Matlab compatibility + if (n < 0) + n = 1; + endif + + ## Matlab will accepts anything numeric or boolean. We can at least + ## issue a warning. + if (! isbw (bw, "non-logical")) + warning ("octave:image:non-bw-conversion", + "bwmorph: converting non binary image to binary"); endif - ## post processing command - postcmd=""; - - switch(operation) - case('bothat') - se = ones(3); - BW2 = imbothat (BW, se); - if(n>1) - ## TODO: check if ignoring n>1 is ok. Should I just ignore it - ## TODO: without a warning? - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; + ## Performing on logical matrices is faster. We could do this and + ## then revert back to its original class but will NOT for Matlab + ## compatibility, who always returns a logical matrix. + bw = logical (bw); + + ## Some operations have no effect after being applied the first time. + ## Those will set this to true and later set N to 1 (only exception is + ## if N is set to 0 but even then we can't skip since we will display + ## the image or return it depending on nargout) + loop_once = false; - case('bridge') + post_morph = []; # post processing command (only if needed) + + switch (tolower (operation)) + case "bothat" + loop_once = true; + se = strel ("square", 3); + morph = @(x) imbothat (x, se); + +# case "branchpoints" +# ## not implemented + + case "bridge" + loop_once = true; ## see __bridge_lut_fun__ for rules - ## lut=makelut("__bridge_lut_fun__",3); - lut=logical([0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - BW2=applylut(BW, lut); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; + ## lut = makelut ("__bridge_lut_fun__", 3); + lut = logical ([0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + morph = @(x) applylut (x, lut); - case('clean') - ## BW(j,k)=X&&(X0||X1||...||X7) - ## lut=makelut(inline("x(2,2)&&any((x.*[1,1,1;1,0,1;1,1,1])(:))","x"),3); + case "clean" + loop_once = true; + ## BW(j,k) = X && (X0||X1||...||X7) + ## lut = makelut (inline ("x(2,2)&&any((x.*[1,1,1;1,0,1;1,1,1])(:))", "x"), 3); ## which is the same as... - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity - lut(17)=0; ## isolated to 0 - ## I'd prefer to create lut directly as a logical, but assigning a - ## value to a logical segfaults 2.1.57. We'll change it as soon as - ## it works. - BW2=applylut(BW, logical(lut)); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; + lut = repmat ([false(16, 1); true(16, 1)], 16, 1); # identity + lut(17) = false; # isolated to 0 + morph = @(x) applylut (x, lut); - case('close') - se = ones(3); - BW2 = imclose (BW, se); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; + case "close" + loop_once = true; + se = strel ("square", 3); + morph = @(x) imclose (x, se); - case('diag') + case "diag" ## see __diagonal_fill_lut_fun__ for rules - ## lut=makelut("__diagonal_fill_lut_fun__",3); - lut=logical([0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=applylut(BW, lut);"; - + ## lut = makelut ("__diagonal_fill_lut_fun__", 3); + lut = logical ([0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + morph = @(x) applylut (x, lut); - case('dilate') - cmd="BW2=imdilate(BW, ones(3));"; + case "dilate" + se = strel ("square", 3); + morph = @(x) imdilate (x, se); + +# case "endpoints" +# ## not implemented - case('erode') - cmd="BW2=imerode(BW, ones(3));"; - - case('fill') - ## lut=makelut(inline("x(2,2)||(sum((x&[0,1,0;1,0,1;0,1,0])(:))==4)","x"),3); + case "erode" + ## Matlab bwmorph acts different than their imerode. I'm unsure + ## the cause of the bug but it seems to manifest on the image border + ## only. It may be they have implemented this routines in both the + ## im* functions, and in bwmorph. The rest of bwmorph that uses + ## erosion (open, close, bothat, and tophat a least), suffer the + ## same problem. We do not replicate the bug and use imerode. + se = strel ("square", 3); + morph = @(x) imerode (x, se); + + case "fill" + loop_once = true; + ## lut = makelut (inline ("x(2,2)||(sum((x&[0,1,0;1,0,1;0,1,0])(:))==4)", "x"), 3); ## which is the same as... - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity + lut = repmat ([false(16, 1); true(16, 1)], 16, 1); # identity ## 16 exceptions - lut([171,172,175,176,235,236,239,240,427,428,431,432,491,492,495,496])=1; - BW2=applylut(BW, logical(lut)); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - + lut([171 172 175 176 235 236 239 240 427 428 431 432 491 492 495 496]) = true; + morph = @(x) applylut (x, lut); - case('hbreak') - ## lut=makelut(inline("x(2,2)&&!(all(x==[1,1,1;0,1,0;1,1,1])||all(x==[1,0,1;1,1,1;1,0,1]))","x"),3); + case "hbreak" + loop_once = true; + ## lut = makelut (inline ("x(2,2)&&!(all(x==[1,1,1;0,1,0;1,1,1])||all(x==[1,0,1;1,1,1;1,0,1]))", "x"), 3); ## which is the same as - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity - lut([382,472])=0; ## the 2 exceptions - BW2=applylut(BW, logical(lut)); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; + lut = repmat ([false(16, 1); true(16, 1)], 16, 1); # identity + lut([382 472]) = false; # the 2 exceptions + morph = @(x) applylut (x, lut); - case('majority') - ## lut=makelut(inline("sum((x&ones(3,3))(:))>=5"),3); - lut=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=applylut(BW, lut);"; + case "majority" + ## lut = makelut (inline ("sum((x&ones(3,3))(:))>=5"), 3); + lut = logical ([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + morph = @(x) applylut (x, lut); - case('open') - se = ones(3); - BW2 = imopen (BW, se); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; + case "open" + loop_once = true; + se = strel ("square", 3); + morph = @(x) imopen (x, se); - case('remove') - ## lut=makelut(inline("x(2,2)&&!(sum((x&[0,1,0;1,1,1;0,1,0])(:))==5)","x"),3); - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity + case "remove" + loop_once = true; + ## lut = makelut (inline ("x(2,2)&&!(sum((x&[0,1,0;1,1,1;0,1,0])(:))==5)", "x"), 3); + lut = repmat ([false(16,1); true(16,1)], 16, 1); # identity ## 16 qualifying patterns - lut([187,188,191,192,251,252,255,256,443,444,447,448,507,508,511,512])=0; - BW2=applylut(BW, logical(lut)); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - case('shrink') - ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"S"); - lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;1;0;1;1;1;1;0;1;0;0;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); - ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'S')","m"),3); - lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;0;1;0;0;0;0;0;1;0; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;0;0;0;0;0;1;1;0;0;1;0; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;0;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; + lut ([187 188 191 192 251 252 255 256 443 444 447 448 507 508 511 512]) = false; + morph = @(x) applylut (x, lut); - case({'skel','skel-pratt'}) + case "shrink" + ## lut1 = makelut ("__conditional_mark_patterns_lut_fun__", 3, "S"); + lut1 = logical ([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;1;0;1;1;1;1;0;1;0;0;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); + ## lut2 = makelut (inline ("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'S')", "m"), 3); + lut2 = logical ([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;0;1;0;0;0;0;0;1;0; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;0;0;0;0;0;1;1;0;0;1;0; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;0;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + morph = @(x) x & applylut (applylut (x, lut1), lut2); + + case {"skel", "skel-pratt"} ## WARNING: Result doesn't look as MATLAB's sample. It has been ## WARNING: coded following Pratt's guidelines for what he calls ## WARNING: is a "reasonably close approximation". I couldn't find @@ -410,173 +401,286 @@ ## WARNING: for Perception of Speech and Visual Form, W. ## WARNING: Whaten-Dunn, Ed. MIT Press, Cambridge, MA, 1967. - ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"K"); - lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;1;1;1;1;0]); + ## lut1 = makelut ("__conditional_mark_patterns_lut_fun__", 3, "K"); + lut1 = logical ([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;1;1;1;1;0]); + + ## lut2 = makelut (inline ("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'K')", "m") ,3); + lut2 = logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;1;0;0;0;1;0;1;1;0;0;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;1;0;0;1;1;0;0;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;0;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;1;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + morph = @(x) x & applylut (applylut (x, lut1), lut2); + post_morph = @(x) bwmorph (x, "bridge"); - ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'K')","m"),3); - lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;1;0;0;0;1;0;1;1;0;0;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;1;0;0;1;1;0;0;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;0;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;1;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; - postcmd="BW2=bwmorph(BW2,'bridge');"; + case "skel-lantuejoul" + ## This transform does not fit well in the same loop as the others, + ## since each iteration requires values from the previous one. Because + ## of this, we will set n to 0 in the end. However, we must take care + ## to not touch the input image if n already is zero. + if (n > 0) + se = strel ("square", 3); + bw_tmp = false (size (bw)); # skeleton result + i = 1; + while (i <= n) + if (! any (bw(:))) + ## If erosion from the previous result is 0-matrix then we are + ## over because the top-hat transform below will also be a 0-matrix + ## and we will be |= to a 0-matrix. + break + endif + ebw = imerode (bw, se); + ## the right hand side of |= is the top-hat transform. However, + ## we are not using imtophat because we will also want the output + ## of the erosion for the next iteration. This saves us calling + ## imerode twice for the same thing. + bw_tmp |= bw & ! imdilate (ebw, se); + bw = ebw; + i++; + endwhile + bw = bw_tmp; + n = 0; # don't do anything else + endif - case('skel-lantuejoul') - ## init values - se=true(3,3); ## structuring element used everywhere - BW2=false(size(BW)); ## skeleton result - eBW=BW; ## eBW will hold k-times eroded BW - i=1; - while i<=n - if(!any(eBW)) ## if erosion result is 0-matrix then - break; ## we are over - endif - BW2|=eBW-imdilate(imerode(eBW, se), se); ## eBW - opening operation on eBW - ## contributes to skeleton - eBW=imerode(eBW,se); - i++; - endwhile - return; ## no general loop in this case + case "spur" + ## lut = makelut(inline("xor(x(2,2),(sum((x&[0,1,0;1,0,1;0,1,0])(:))==0)&&(sum((x&[1,0,1;0,0,0;1,0,1])(:))==1)&&x(2,2))","x"),3); + ## which is the same as + lut = repmat ([false(16, 1); true(16,1)], 16, 1); # identity + lut([18, 21, 81, 273]) = false; # 4 qualifying patterns + morph = @(x) applylut (x, lut); - case('spur') - ## lut=makelut(inline("xor(x(2,2),(sum((x&[0,1,0;1,0,1;0,1,0])(:))==0)&&(sum((x&[1,0,1;0,0,0;1,0,1])(:))==1)&&x(2,2))","x"),3); - ## which is the same as - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity - lut([18,21,81,273])=0; ## 4 qualifying patterns - lut=logical(lut); - cmd="BW2=applylut(BW, lut);"; - - case('thicken') + case "thicken" ## This implementation also "thickens" the border. To avoid this, ## a simple solution could be to add a border of 1 to the reversed ## image. - BW2=bwmorph(!BW,'thin',n); - BW2=bwmorph(BW2,'diag'); - return; + bw = bwmorph (! bw, "thin", n); + loop_once = true; + morph = @(x) bwmorph (x, "diag"); - case('thin') - ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"T"); - lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;0;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); - ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'T')","m"),3); - lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;0;1;0;1;1;0;0;0;0;1;0; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;0;0;0;0;1;1;0;0;1;0; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;1;0;0;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; + case "thin" + ## lut1 = makelut ("__conditional_mark_patterns_lut_fun__", 3, "T"); + lut1 = logical ([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;0;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); + ## lut2 = makelut (inline ("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'T')", "m"), 3); + lut2 = logical ([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;0;1;0;1;1;0;0;0;0;1;0; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;0;0;0;0;1;1;0;0;1;0; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;1;0;0;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + morph = @(x) x & applylut (applylut (x, lut1), lut2); - - case('tophat') - se = ones(3); - BW2 = imtophat (BW, se); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - + case "tophat" + ## top hat filtering has no effect after being performed once + ## (inherits this behaviour from closing and opening) + loop_once = true; + se = strel ("square", 3); + morph = @(x) imtophat (x, se); otherwise - error("bwmorph: unknown operation type requested."); + error ("bwmorph: unknown OPERATION '%s' requested", operation); endswitch - ## we use this assignment because of the swap operation inside the - ## while. - BW2=BW; + if (loop_once && n > 1) + n = 1; + endif - ## if it doesn't change we don't need to process it further - i=1; - while(i<=n) ## for wouldn't work because n can be Inf - [BW,BW2]=swap(BW,BW2); - eval(cmd); - if(all((BW2==BW)(:))) + bw2_tmp = bw; ## make sure bw2_tmp will exist later, even if n == 0 + i = 1; + while (i <= n) ## a for loop wouldn't work because n can be Inf + bw2_tmp = morph (bw); + if (isequal (bw, bw2_tmp)) + ## if it doesn't change we don't need to process it further break endif - i+=1; + bw = bw2_tmp; + i++; endwhile ## process post processing commands if needed - if (isempty (postcmd)) - eval(postcmd); + if (! isempty (post_morph) && n > 0) + bw2_tmp = post_morph (bw2_tmp); + endif + + if (nargout > 0) + bw2 = bw2_tmp; + else + imshow (bw2_tmp); endif endfunction -function [b, a] = swap (a, b) -endfunction - %!demo -%! bwmorph(ones(11),'shrink', Inf) +%! bwmorph (true (11), "shrink", Inf) %! # Should return 0 matrix with 1 pixel set to 1 at (6,6) -## TODO: code tests - - ## Test skel-lantuejoul using Gozalez&Woods example (fig 8.39) %!shared slBW, rslBW -%! uint8(0); # fail for 2.1.57 or less instead of crashing later -%! slBW=logical(zeros(12,7)); -%! slBW(2,2)=true; -%! slBW(3:4,3:4)=true; -%! rslBW=slBW; -%! slBW(5:6,3:5)=true; -%! slBW(7:11,2:6)=true; -%! rslBW([6,7,9],4)=true; +%! slBW = logical ([ 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 +%! 0 0 1 1 0 0 0 +%! 0 0 1 1 0 0 0 +%! 0 0 1 1 1 0 0 +%! 0 0 1 1 1 0 0 +%! 0 1 1 1 1 1 0 +%! 0 1 1 1 1 1 0 +%! 0 1 1 1 1 1 0 +%! 0 1 1 1 1 1 0 +%! 0 1 1 1 1 1 0 +%! 0 0 0 0 0 0 0]); +%! +%! rslBW = logical ([ 0 0 0 0 0 0 0 +%! 0 1 0 0 0 0 0 +%! 0 0 1 1 0 0 0 +%! 0 0 1 1 0 0 0 +%! 0 0 0 0 0 0 0 +%! 0 0 0 1 0 0 0 +%! 0 0 0 1 0 0 0 +%! 0 0 0 0 0 0 0 +%! 0 0 0 1 0 0 0 +%! 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0 +%! 0 0 0 0 0 0 0]); +%!assert (bwmorph (slBW, "skel-lantuejoul", 1), [rslBW(1:5,:); false(7, 7)]); +%!assert (bwmorph (slBW, "skel-lantuejoul", 2), [rslBW(1:8,:); false(4, 7)]); +%!assert (bwmorph (slBW, "skel-lantuejoul", 3), rslBW); +%!assert (bwmorph (slBW, "skel-lantuejoul", Inf), rslBW); + +%!error bwmorph ("not a matrix", "dilate") + +## this makes sense to be an error but for Matlab compatibility, it is not +%!assert (bwmorph (magic (10), "dilate"), imdilate (logical (magic (10)), ones (3))); -%!assert(bwmorph(slBW,'skel-lantuejoul',1),[rslBW(1:5,:);logical(zeros(7,7))]); -%!assert(bwmorph(slBW,'skel-lantuejoul',2),[rslBW(1:8,:);logical(zeros(4,7))]); -%!assert(bwmorph(slBW,'skel-lantuejoul',3),rslBW); -%!assert(bwmorph(slBW,'skel-lantuejoul',Inf),rslBW); +%!shared in, out, se +%! in = logical ([1 1 0 0 1 0 1 0 0 0 1 1 1 0 1 1 0 1 0 0 +%! 1 1 1 0 1 0 1 1 1 1 0 1 0 1 0 0 0 0 0 0 +%! 0 1 1 1 0 1 1 0 0 0 1 1 0 0 1 1 0 0 1 0 +%! 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 +%! 0 1 0 0 1 1 0 1 1 0 0 0 0 0 1 1 0 0 1 0 +%! 0 0 1 1 1 1 1 0 0 1 0 1 1 1 0 0 1 0 0 1 +%! 0 1 1 1 1 1 1 0 1 1 1 0 0 0 1 0 0 1 0 0 +%! 1 0 1 1 1 0 1 1 0 1 0 0 1 1 1 0 0 1 0 0 +%! 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 1 1 0 +%! 1 0 1 1 1 1 0 0 0 1 0 0 0 0 0 0 1 1 0 0 +%! 1 1 1 1 1 1 0 1 0 1 0 0 0 0 0 0 1 0 1 1 +%! 0 1 0 1 1 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 +%! 0 0 1 1 0 1 1 1 1 0 0 1 0 0 0 0 1 0 1 1 +%! 0 0 1 1 0 0 1 1 1 0 0 0 1 1 1 1 0 0 0 0 +%! 0 0 1 0 0 0 0 0 0 1 0 0 1 1 1 1 0 0 0 0 +%! 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 +%! 0 1 0 0 0 1 1 0 1 1 0 0 1 1 1 0 1 1 1 1 +%! 1 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 1 1 1 +%! 0 0 1 1 0 1 1 1 1 0 0 0 0 1 1 0 1 1 1 1 +%! 0 1 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 0 1]); +%! se = strel ("arbitrary", ones (3)); +%! +%!assert (bwmorph (in, "dilate"), imdilate (in, se)); +%!assert (bwmorph (in, "dilate", 3), imdilate (imdilate (imdilate (in, se), se), se)); +%!assert (bwmorph (in, "bothat"), imbothat (in, se)); +%!assert (bwmorph (in, "tophat"), imtophat (in, se)); +%!assert (bwmorph (in, "open"), imopen (in, se)); +%!assert (bwmorph (in, "close"), imclose (in, se)); +%! +%!assert (bwmorph ([1 0 0; 1 0 1; 0 0 1], "bridge"), logical ([1 1 0; 1 1 1; 0 1 1])); +%!assert (bwmorph ([0 0 0; 1 0 1; 0 0 1], "clean"), logical ([0 0 0; 0 0 1; 0 0 1])); +%!assert (bwmorph ([0 0 0; 0 1 0; 0 0 0], "clean"), false (3)); +%!assert (bwmorph ([0 1 0; 1 0 0; 0 0 0], "diag"), logical ([1 1 0; 1 1 0; 0 0 0])); +%! +%! in = logical ([0 1 0 1 0 +%! 1 1 1 0 1 +%! 1 0 0 1 0 +%! 1 1 1 0 1 +%! 1 1 1 1 1]); +%! out = logical ([0 1 0 1 0 +%! 1 1 1 1 1 +%! 1 0 0 1 0 +%! 1 1 1 1 1 +%! 1 1 1 1 1]); +%!assert (bwmorph (in, "fill"), out); +%! +%!assert (bwmorph ([1 1 1; 0 1 0; 1 1 1], "hbreak"), logical ([1 1 1; 0 0 0; 1 1 1])); +%! +%! in = logical ([0 1 0 0 0 +%! 1 0 0 1 0 +%! 1 0 1 0 0 +%! 1 1 1 1 1 +%! 1 1 1 1 1]); +%! +%! out = logical ([0 1 0 0 0 +%! 1 0 0 1 0 +%! 1 0 1 0 0 +%! 1 1 0 1 1 +%! 1 1 1 1 1]); +%!assert (bwmorph (in, "remove"), out); +%! +%! out = logical ([0 1 0 0 0 +%! 1 0 0 1 0 +%! 1 0 1 0 0 +%! 1 1 0 1 1 +%! 1 1 1 1 1]); +%!assert (bwmorph (in, "remove", Inf), out); +%! +%! ## tests for spur are failing (matlab incompatible) +%! out = logical ([0 1 0 0 0 +%! 1 0 0 0 0 +%! 1 0 1 0 0 +%! 1 1 1 1 1 +%! 1 1 1 1 1]); +%!assert (bwmorph (in, "spur"), out); +%! +%! out = logical ([0 1 0 0 0 +%! 1 0 0 0 0 +%! 1 0 0 0 0 +%! 1 1 1 1 1 +%! 1 1 1 1 1]); +%!assert (bwmorph (in, "spur", Inf), out);