function [cout,lut,mlut] = bwmorph(a,lut,n)
%BWMORPH Binary image morphological operation
%	C = BWMORPH(BW,LUT) filters the binary image BW by the
%	filter h = 2.^[0 3 6;1 4 7;2 5 8] and uses the filtered
%	result (plus 1) to look up the return pixel value in the
%	vector LUT.  LUT is a 512-by-1 look up table that typically
%	contains a 1 for "hit" pixel configurations and zero 
%	everywhere else.  The filter above produces the numbers 0 
%	through 511, one for each possible pixel configuration in 
%	a 3-by-3 neighborhood.  The binary image result is returned
%	in C.
%
%	C = BWMORPH(BW,'operation') applies the morphological operation 
%	'operation' to the binary image BW.  The operation strings are
%	used to create the appropriate LUT.  Possible operations are:
%	  'bothat'  The 'close'ing minus the original image.
%	  'bridge'  Bridge previously unconnected pixels.
%	  'clean'   Remove isolated pixels.
%	  'close'   Binary closure.  The same as 'dilate' followed by 'erode'.
%	  'diag'    Diagonal fill to eliminate 8-connectivity of background.
%	  'dilate'  Add pixels to the boundary of binary objects.
%	  'erode'   Remove pixels from the boundary of binary objects.
%	  'fatten'  Add pixels to boundary without bridging objects.
%	  'fill'    Fill isolated interior pixels.
%	  'hbreak'  Erase H-connected pixels.
%	  'majority'Create a white pixel if 5 or more pixels are white.
%	  'perim4'  4-connected perimeter pixels.
%	  'perim8'  8-connected perimeter pixels.
%	  'open'    Binary opening.  The same as 'erode' followed by 'dilate'.
%	  'remove'  Remove interior pixels.
%	  'shrink'  Shrink objects until they are points (preserves Euler number).
%	  'skel'    Skeletonize objects (preserves Euler number).
%	  'spur'    Remove spur pixels.
%	  'thicken' Thicken objects (preserves Euler number).
%	  'thin'    Thin objects until they are lines (preserves Euler number).
%	  'tophat'  The original image minus its 'open'ing.
%
%	BWMORPH(...,N) applies the operation N times.
%
%	[C,LUT] = BWMORPH(...) returns the LUT used.  The operations that
%	preserve Euler number use two LUTs, a mark and a reject LUT.  Use
%	[C,MLUT,RLUT] = BWMORPH(...) to extract the two LUTs.
%
%	See also ERODE, DILATE, BWEULER, BWPERIM.

%	Clay M. Thompson 7-27-93
%	Copyright (c) 1993 by The MathWorks, Inc.
%	$Revision: 1.6 $  $Date: 1993/10/21 12:59:32 $

global bwmorph_LUT

error(nargchk(2,3,nargin));

if nargin<3, n = 1; end

if isstr(lut),
  op = [lower(lut) '    ']; % Protect against a short operation string
  mlut = [];

  % load LUT if necessary
  if any(size(bwmorph_LUT)~=[512 19]),
    load bwmorph
    bwmorph_LUT = lut;
  end
  if all(op(1:2)=='bo'), % bothat
    [c,lut] = bwmorph(a,'dilate',n);
    [c,lut] = bwmorph(c,'erode',n);
    c = c - a;
    if nargout==0, imshow(c,2), else cout = c; end, return
  elseif all(op(1:2)=='br'), % Bridge
    lut = bwmorph_LUT(:,1);
  elseif all(op(1:3)=='cle'), % Clean
    lut = bwmorph_LUT(:,2);
  elseif all(op(1:3)=='clo'), % close
    c = bwmorph(a,'dilate',n);
    [c,lut] = bwmorph(c,'erode',n);
    if nargout==0, imshow(c,2), else cout = c; end, return
  elseif all(op(1:3)=='dia'), % Diagonal fill
    lut = bwmorph_LUT(:,3);
  elseif all(op(1:3)=='dil'), % Dilate
    lut = bwmorph_LUT(:,4);
  elseif op(1)=='e', % Erode
    lut = bwmorph_LUT(:,5);
  elseif all(op(1:2)=='fa'), % Fatten
    lut = bwmorph_LUT(:,6);
  elseif all(op(1:2)=='fi'), % Interior fill
    lut = bwmorph_LUT(:,7);
  elseif op(1)=='h', % H-break
    lut = bwmorph_LUT(:,8);
  elseif op(1)=='m', % Majority white
    lut = bwmorph_LUT(:,9);
  elseif op(1)=='o', % opening
    c = bwmorph(a,'erode',n);
    [c,lut] = bwmorph(c,'dilate',n);
    if nargout==0, imshow(c,2), else cout = c; end, return
  elseif all(op(1:6)=='perim4'), % 4-connected perimeter
    lut = bwmorph_LUT(:,18);
  elseif all(op(1:6)=='perim8'), % 8-connected perimeter
    lut = bwmorph_LUT(:,19);
  elseif op(1)=='r', % Remove
    lut = bwmorph_LUT(:,10);
  elseif all(op(1:2)=='sh'), % Shrink
    lut = bwmorph_LUT(:,11);
    mlut = bwmorph_LUT(:,12);
  elseif all(op(1:2)=='sk'), % Skeletonize
    lut = bwmorph_LUT(:,13);
    mlut = bwmorph_LUT(:,14);
  elseif all(op(1:2)=='sp'), % Spur
    lut = bwmorph_LUT(:,15);
  elseif all(op(1:4)=='thic'), % Thicken
    lut = bwmorph_LUT(:,20);
    mlut = bwmorph_LUT(:,21);
  elseif all(op(1:4)=='thin'), % Thin
    lut = bwmorph_LUT(:,16);
    mlut = bwmorph_LUT(:,17);
  elseif all(op(1:2)=='to'), % tophat
    c = bwmorph(a,'erode',n);
    [c,lut] = bwmorph(c,'dilate',n);
    c = a - c;
    if nargout==0, imshow(c,2), else cout = c; end, return
  else
    error([deblank(op),' is an ambiguous or unknown operation.']);
  end
else
  mlut = [];
end

if any(size(lut)~=[512 1]), error('LUT must be 512-by-1.'); end
if ~isbw(a), error('BW must contain only zeros and ones.'); end

h = [1     8    64
     2    16   128
     4    32   256];

if isempty(mlut), % Normal hit-or-miss calculation
  c = a;
  for i=1:n,
    c(:) = lut(filter2(h,c)+1);
  end
else 
  if all(op(1:4)=='thic'), % Special thicken calculation
    c = a; m = zeros(size(a)); p = zeros(size(a));
    for i=1:n,
      m(:) = lut(filter2(h,c)+1);
      p(:) = mlut(filter2(h,m)+1);
      c = c | (m & ~p);
    end
  else % Special thin, skel, and shrink calculation
    c = a; m = zeros(size(a)); p = zeros(size(a));
    for i=1:n,
      m(:) = lut(filter2(h,c)+1);
      p(:) = mlut(filter2(h,m)+1);
      c = c & (~m | p);
    end
  end
end

if nargout==0, imshow(c,2), return, end
cout = c;
