function [e,tol] = edge(a,tol,method,k)
%EDGE	Edge extraction.
%	BW = EDGE(I,'method') finds the edges in the intensity image
%	I and returns a binary matrix BW where the edges have 
%	value 1 and all other pixels are zero.  
%
%	Possible methods are 'sobel','roberts','prewitt', or 
%	'marr-hildreth'.  The default is 'sobel'.
%
%	'sobel' and 'prewitt' find edges where the first derivative of
%	the image intensity is maximum (or minimum).  They are sensitive 
%	to horizontal and vertical edges and use a Sobel (or Prewitt) 
%	approximation to the derivative.
%	'roberts' also finds edges at extremum of the first derivative.
%	It is sensitive	to diagonal edges and uses a Roberts approximation
%	to the derivative.
%	'marr-hildreth' finds edges by looking for zero crossings 
%	of the Laplacian of Gaussian filtered version of I.
%
%	BW = EDGE(I,TOL,'method') uses the value TOL to set the noise
%	tolerance.  All edges that aren't stronger than TOL are 
%	ignored.  [BW,TOL] = EDGE(...) returns this tolerance.  Set
%	TOL to [] to use the computed default.
%
%	BW = EDGE(I,TOL,'method',K) allows the specification of
%	a directionality factor, K.  K must be a 1-by-2 vector,
%	K = [kx ky].  K=[1 0] looks for vertical edges, K=[0 1]
%	looks for horizontal edges, and K=[1 1], the default, looks
%	for non-directional edges.
%
%	BW = EDGE(I,TOL,'marr',H) can be used to specify the 'log'
%	filter H for the 'marr-hildreth' method.
%
%	Without output arguments, EDGE displays the resulting binary
%	image and returns the tolerance in ans.
%
%	See also FSPECIAL.

%	Clay M. Thompson 10-8-92
%	Copyright (c) 1993 by The MathWorks, Inc.
%	$Revision: 1.14 $  $Date: 1993/09/09 11:09:16 $

if nargin<4
  kx = 1; ky = 1; % Directionality factor
else
  kx = k(1); ky = k(2); 
end
if nargin<2, method = 'sobel'; tol = []; end
if nargin==2, 
  if isstr(tol),
    method = tol; tol = [];
  else
    method = 'sobel';
  end
end

[m,n] = size(a);
rr = [2:m-1]; cc=[2:n-1];

case = lower(method(1));

%
% Determine edges in blocks
%
nr = length(rr); nc = length(cc);

blk = bestblk([nr nc]);
nblks = floor([nr nc]./blk); nrem = [nr nc] - nblks.*blk;
mblocks = nblks(1); nblocks = nblks(2);
mb = blk(1); nb = blk(2);

if case == 's', % Sobel method
  op = [-1 -2 -1;0 0 0;1 2 1]/8; % Sobel approximation to derivative
  bx = abs(filter2(op',a)); by = abs(filter2(op,a));
  b = kx*bx.*bx + ky*by.*by;
  if isempty(tol), % Determine cutoff based on RMS estimate of noise
    cutoff = 4*sum(sum(b(rr,cc)))/prod(size(b(rr,cc))); tol = sqrt(cutoff);
  else 	 	 % Use relative tolerance specified by the user
    cutoff = (tol).^2;
  end
  e = zeros(m,n);
  rows = 1:blk(1);
  for i=0:mblocks,
    if i==mblocks, rows = (1:nrem(1)); end
    for j=0:nblocks,
      if j==0, cols = 1:blk(2); elseif j==nblocks, cols=(1:nrem(2)); end
      if ~isempty(rows) & ~isempty(cols)
        r = rr(i*mb+rows); c = cc(j*nb+cols);
        e(r,c) = (b(r,c)>cutoff) & ...
             ( ( (bx(r,c) > kx*by(r,c)) & ...
                 (b(r,c-1) <= b(r,c)) & (b(r,c) > b(r,c+1)) ) | ...
             ( (by(r,c) > kx*bx(r,c)) & ...
               (b(r-1,c) <= b(r,c)) & (b(r,c) > b(r+1,c)) ) );
      end
    end
  end

elseif case == 'p', % Prewitt method
  op = [-1 -1 -1;0 0 0;1 1 1]/6; % Prewitt approximation to derivative
  bx = abs(filter2(op',a)); by = abs(filter2(op,a));
  b = kx*bx.*bx + ky*by.*by;
  if isempty(tol), % Determine cutoff based on RMS estimate of noise
    cutoff = 4*sum(sum(b(rr,cc)))/prod(size(b(rr,cc))); tol = sqrt(cutoff);
  else 	 	 % Use relative tolerance specified by the user
    cutoff = (tol).^2;
  end
  e = zeros(m,n);
  rows = 1:blk(1);
  for i=0:mblocks,
    if i==mblocks, rows = (1:nrem(1)); end
    for j=0:nblocks,
      if j==0, cols = 1:blk(2); elseif j==nblocks, cols=(1:nrem(2)); end
      if ~isempty(rows) & ~isempty(cols)
        r = rr(i*mb+rows); c = cc(j*nb+cols);
        e(r,c) = (b(r,c)>cutoff) & ...
           ( ( (bx(r,c) > kx*by(r,c)) & ...
               (b(r,c-1) <= b(r,c)) & (b(r,c) > b(r,c+1)) ) | ...
             ( (by(r,c) > ky*bx(r,c)) & ...
               (b(r-1,c) <= b(r,c)) & (b(r,c) > b(r+1,c)) ) );
      end
    end
  end

elseif case == 'r', % Roberts method
  op = [1 0;0 -1]/sqrt(2); % Roberts approximation to diagonal derivative
  bx = abs(filter2(op,a)); by = abs(filter2(rot90(op),a));
  b = kx*bx.*bx + ky*by.*by;
  if isempty(tol), % Determine cutoff based on RMS estimate of noise
    cutoff = 6*sum(sum(b(rr,cc)))/prod(size(b(rr,cc))); tol = sqrt(cutoff);
  else 	 	 % Use relative tolerance specified by the user
    cutoff = (tol).^2;
  end
  e = zeros(m,n);
  rows = 1:blk(1);
  for i=0:mblocks,
    if i==mblocks, rows = (1:nrem(1)); end
    for j=0:nblocks,
      if j==0, cols = 1:blk(2); elseif j==nblocks, cols=(1:nrem(2)); end
      if ~isempty(rows) & ~isempty(cols)
        r = rr(i*mb+rows); c = cc(j*nb+cols);
        e(r,c) = (b(r,c)>cutoff) & ...
           ( ( (bx(r,c) > kx*by(r,c)) & ...
               (b(r-1,c-1) <= b(r,c)) & (b(r,c) > b(r+1,c+1)) ) | ...
             ( (by(r,c) > ky*bx(r,c)) & ...
               (b(r-1,c+1) <= b(r,c)) & (b(r,c) > b(r+1,c-1)) ) );
      end
    end
  end

elseif case == 'm', % Laplacian-based method
  if nargin<4, op = fspecial('log',5,.5); else op = k; end
  r = [3:m-2]; c=[3:n-2];
  b = filter2(op,a);
  if isempty(tol), % Determine cutoff based on RMS estimate of noise
    cutoff = 0.75*sum(sum(abs(b(r,c))))/((m-1)*(n-1));
    tol = cutoff;
  else 	 	 % Use relative tolerance specified by the user
    cutoff = tol;
  end

  % Convert image to -,0,+ ranges and then spread the values
  % out so that different ways to sum 4 indices are distinguishable.
  bb = grayslice(b,[-cutoff cutoff])-1;
  k = find(bb==2); bb(k) = bb(k)+3;

  % Sum 4-connected pixels
  b = filter2([0 1 0;1 0 1;0 1 0],bb);

  % Only the 6 possible sums below are valid zero-crossings.
  e = zeros(m,n);
  rows = 1:blk(1);
  for i=0:mblocks,
    if i==mblocks, rows = (1:nrem(1)); end
    for j=0:nblocks,
      if j==0, cols = 1:blk(2); elseif j==nblocks, cols=(1:nrem(2)); end
      if ~isempty(rows) & ~isempty(cols)
        r = rr(i*mb+rows); c = cc(j*nb+cols);
        e(r,c) = b(r,c)==5 | b(r,c)==6 | b(r,c)==7 | ...
                 b(r,c)==10 | b(r,c)==11 | b(r,c)==15;
      end
    end
  end
else
  error([method,' is not a valid method.']);
end

if nargout==0,
  imshow(e,2)
  e = tol;
  return
end
