image thumbnail
from A Fast Corner Detector Based on the Chord-to-Point Distance Accumulation Technique by Mohammad Awrangjeb
Reference: A Fast Corner Detector Based on the Chord-to-Point Distance Accumulation Technique, IEEE.

fast_cpda(varargin)
function [cout,marked_img,cd] = fast_cpda(varargin)

% ================== About =============================
% ======================================================
% The following code is of the fast cpda detector: M. Awrangjeb, G. Lu, C.
% S. Fraser and M. Ravanbakhsh A Fast Corner Detector Based on the Chord-to-Point Distance Accumulation Technique, 
% Proceedings of the 2009 Digital Image Computing: Techniques and
% Applications (DICTA 2009), pp. 519-525, Publisher  	
% IEEE Computer Society  Washington, DC, USA 
% ================== License ===========================
% ======================================================
% Al rights reserved to the authors. The code is useable for research and non-commercial purposes only.
% Please site the above published article whereby necessary.

% ================== Acknowledgement ===================
% ======================================================
% Part of this code (e.g., edge detection function) is from the source code of He & Yung
% detector: X. C. He and N. H. C. Yung, "Curvature scale space corner detector with adaptive threshold and dynamic region of support",
% Proc. International Conference on Pattern Recognition (ICPR 2004)}, vol. 2, pp. 791--794, Cambridge, UK, August 2004.
% Available at http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=7652&objectType=file
% Thanks to He and Yung for their kind help.

% Parse the input parameters
[I,sig,High,Low,Gap_size,EP] = parse_inputs(varargin{:});
% I         : the input grayscale image
% High      : the high threshold for the Canny edge detector in [0,1] (default = 0.7)
% Low       : the low threshold for the Canny edge detector in [0,1] (default = 0.2)
% Gap_size  : The maximum gap between the successive edge-points. If the
%           gap between the sucessive points is more than Gap_size, then
%           they would be in two different edges (default = 1 pixel)
% EP        : A flag to indicate whether the end-points of a curve be
%           detected as corners (default = 0)

% Detect edges
BW = edge(I,'canny',[Low,High]);  % [Low,High] low and high sensitivity thresholds
% BW = edge(I,'canny'); % If sensitivity thresholds are not specified Canny edge detector selects itself
% output:  binary edge-image BW of the same size as I, with 1's where the function finds edges in I and 0's elsewhere

% Extract curves from the edge-image
[curve,curve_start,curve_end,curve_mode,curve_num,TJ,img1] = extract_curve(BW,Gap_size);  
% curve         : MATLAB cell data structure where each cell is a 2D array containing
%               pixel locations (x and y values)
% curve_start   : starting points of extracted curves
% curve_end     : ending points of extracted curves
% curve_mode    : two curve modes - 'line' and 'loop'. If the both ends of
%               a curve are at maximum 25 square pixels (default) away, then the
%               curve is a loop curve, otherwise a line curve
% curve_num     : number of extracted curves
% TJ            : the T-junction found in the edge-extraction process
% img1          : output image containing the extracted edges

%imshow(img1);
[sizex sizey] = size(I);
if size(curve{1})>0
    
    tic
    [point_selected smoothed_curve Width Sigma] = selectPoint(curve, curve_mode, curve_num, sizex, sizey);
    
    % Detect corners on the extracted edges
    [corner_out index cd2] = getcorner(curve,curve_mode,curve_start,curve_num,sizex,sizey,img1,point_selected,smoothed_curve,Width); 
    
    % corner_out	: n by 2 matrix containing the positions of the
    %               detected corners, where n is the number of detected
    %               corners
    % index         : MATLAB cell data structure where each cell is an 1D
    %               column matrix contaning the edge pixel numbers (in curve) where
    %               the corners are detected
    % Sig           : the sigma values used to smooth the curves
    % cd2           : cpda curvature values of the detected corners
    
    % Update the T-junctions
    [corner_final cd3] = Refine_TJunctions(corner_out,TJ,cd2,curve, curve_num, curve_start, curve_end, curve_mode,EP);
    % corner_final  : n by 2 matrix containing the positions of the
    %               detected corners, where n is the number of detected
    %               corners
    % cd3           : cpda curvature values of the detected corners
    Total_time_for_corner_detection = toc
    
    img=img1; % to show corners on the edge image
    %img=I; % to show corners on the input image
    for i=1:size(corner_final,1)
        img=mark(img,corner_final(i,1),corner_final(i,2),7);
    end

    marked_img=img;
    figure(); imshow(marked_img);
    imwrite(marked_img,'corners.bmp','BMP');
    cout = corner_final;
    cd = cd3;
else
    cout = [];
    marked_img = [];
    cd = [];
end

here = 1;

%%%%%%%%%%% select points from extracted curves
function [point_selected smoothed_curve Width Sig] = selectPoint(curve, curve_mode, curve_num, sizex, sizey);


%S = 1.5*s;
s = 3.0;
S = 4.0;
[gau w] = find_Gaussian(s);
[Gau W] = find_Gaussian(S);
extra = W-w;
gau1 = [zeros(1,extra) gau zeros(1,extra)];
DoG = Gau-gau1;
%t = 0.1;

%smoothed_curve = cell(curve_num);
%point_selected = cell;
Width = w; Sig = s;
for i = 1:curve_num    
    x = curve{i}(:,2) - sizey/2;
    y = sizex/2 - curve{i}(:,1);
    L = size(x,1);
    if (L>W)
    % Calculate curvature
        if curve_mode(i,:)=='loop'
            x1=[x(L-W+1:L);x;x(1:W)];
            y1=[y(L-W+1:L);y;y(1:W)];
        else
            x1=[ones(W,1)*2*x(1)-x(W+1:-1:2);x;ones(W,1)*2*x(L)-x(L-1:-1:L-W)];
            y1=[ones(W,1)*2*y(1)-y(W+1:-1:2);y;ones(W,1)*2*y(L)-y(L-1:-1:L-W)];
        end
       
        xx=conv(x1,DoG);
        xx=xx(W+1:L+3*W);
        yy=conv(y1,DoG);
        yy=yy(W+1:L+3*W);
        K = xx.^2 + yy.^2;
       
        % Find curvature local maxima as corner candidates
        extremum=[];
        N=size(K,1);
        n=0;
        Search=1;
        
        for j=1:N-1
            if (K(j+1)-K(j))*Search>0
                n=n+1;
                extremum(n)=j;  % In extremum, odd points is minima and even points is maxima
                Search=-Search;
            end
        end
        if mod(size(extremum,2),2)==0
            n=n+1;
            extremum(n)=N;
        end
    
        %n=size(extremum,2);
        %flag=ones(size(extremum));
  
        % Compare with adaptive local threshold to remove round corners
        %for j=2:2:n
        %    if K(extremum(j))<t
        %        flag(j)=0;
        %    end
        %end
        extremum=extremum(2:2:n);
        %flag=flag(2:2:n);
        %extremum=extremum(find(flag==1));        
        extremum=extremum-W;
        extremum=extremum(find(extremum>0 & extremum<=L));
        
        xx=conv(x1,gau);
        xx=xx(W+1:L+3*W);
        yy=conv(y1,gau);
        yy=yy(W+1:L+3*W);
        
    smoothed_curve{i} = [xx yy];
    point_selected{i} = extremum;
    %Width = [Width W];
    %Sig = [Sig s];
    else
        smoothed_curve{i} = [];
        point_selected{i} = [];
        %Width = [Width 0];
        %Sig = [Sig 0];
    end
    %here = 1;
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [corners index cd] = getcorner(curve,curve_mode,curve_start,curve_num,sizex,sizey,img,point_selected,sm_curve,W);

corners = [];
%cor = []; % candidate corners
cd = [];
T_angle = 157;
CLen = [10 20 30];
T = 0.2; % define the curvature threshold
for i=1:curve_num;
    C = []; C3 = [];
    %x = curve{i}(:,2) - sizey/2;
    %y = sizex/2 - curve{i}(:,1);
    %curveLen = size(x,1);   
    %[sig] = find_sig(curveLen);
    %[xs ys gau W] = smoothing(x,y,curveLen,curve_mode(i,:),sig,1); % smooth the curve with Gaussian kernel    
    %xs = sm_curve{i}(:,1);
    %ys = sm_curve{i}(:,2);
    %W = Width(i);
    xs = sm_curve{i}(:,2) ;
    ys = sm_curve{i}(:,1);    
    L = size(xs,1);
    curveLen = L-2*W;
    %curveLen = L-2*W;
    %sig = Sigma(i);
    if L>1   
    %if curve_mode(i,:)=='loop'
    %    xs1=[xs(curveLen-W+1:curveLen);xs;xs(1:W)];
    %    ys1=[ys(curveLen-W+1:curveLen);ys;ys(1:W)];
    %else %expand the ends to gaussian window
    %    xs1=[ones(W,1)*2*xs(1)-xs(W+1:-1:2);xs;ones(W,1)*2*xs(curveLen)-xs(curveLen-1:-1:curveLen-W)];
    %    ys1=[ones(W,1)*2*ys(1)-ys(W+1:-1:2);ys;ones(W,1)*2*ys(curveLen)-ys(curveLen-1:-1:curveLen-W)];
    %end   
    %xs = xs1;
    %ys = ys1;
    %L = curveLen+2*W;   
    extremum = point_selected{i};
    if size(extremum,2)>0
        for j = 1:3
            chordLen = CLen(1,j);
            C3(j,1:L) = abs(accumulate_chord_distance(xs,ys,chordLen,L,curve_mode(i,:),extremum,W));        
        end
    c1 = C3(1,W+1:curveLen+W)/max(C3(1,W+1:curveLen+W));
    c2 = C3(2,W+1:curveLen+W)/max(C3(2,W+1:curveLen+W));
    c3 = C3(3,W+1:curveLen+W)/max(C3(3,W+1:curveLen+W));
    
    C = c1.*c2.*c3;
    %A = mean(C); 
    L = curveLen;
    xs = xs(W+1:L+W);
    ys = ys(W+1:L+W);
    %flag = (extremum > W & extremum <= L+W);
    %extremum = extremum(flag == 1);
    %extremum = extremum-W;
    
    % Find curvature local maxima as corner candidates
    %extremum=[];
    %N=size(C,2);
    %n=0;
    %Search=1;
        
    %for j=1:N-1
    %    if (C(j+1)-C(j))*Search>0
    %        n=n+1;
    %        extremum(n)=j;  % In extremum, odd points are minima and even points are maxima
    %        Search=-Search; % minima: when K starts to go up; maxima: when K starts to go down 
    %    end
    %end
    %if mod(size(extremum,2),2)==0 %to make odd number of extrema
    %    n=n+1;
    %    extremum(n)=N;
    %end

    %%% accumulate candidate corners
    %n = size(extremum,2);    
    %for j = 1:n
    %    cor = [cor; curve{i}(extremum(j),:)];  
    %end   
    %%%
    
    n = size(extremum,2);
    flag = ones(size(extremum));
    
    % Compare each maxima with its contour average
    for j=1:n % if the maxima is less than local minima, remove it as flase corner
        if (C(extremum(j)) > T)
            flag(j)=0;
        end
    end
    %extremum = extremum(2:2:n); % only maxima are corners, not minima
    %flag = flag(2:2:n);
    extremum = extremum(find(flag==0));    
        
    % Check corner angle to remove false corners due to boundary noise and trivial details
    %fl = 0;
    %if fl
        %flag=0;
        smoothed_curve=[xs,ys];
        while sum(flag==0)>0
            n=size(extremum,2);
            flag=ones(size(extremum)); 
            for j=1:n % second argument of curve_tangent function is always the position of the extrema in the first argument
                %which is array of points between two exterama
                if j==1 & j==n
                    ang=curve_tangent(smoothed_curve(1:L,:),extremum(j));
                elseif j==1 
                    ang=curve_tangent(smoothed_curve(1:extremum(j+1),:),extremum(j));
                elseif j==n
                    ang=curve_tangent(smoothed_curve(extremum(j-1):L,:),extremum(j)-extremum(j-1)+1);
                else
                    ang=curve_tangent(smoothed_curve(extremum(j-1):extremum(j+1),:),extremum(j)-extremum(j-1)+1);
                end     
                if ang>T_angle & ang<(360-T_angle) % if angle is between T_angle = 162 and (360-T_angle) = 198
                    flag(j)=0;  
                end
            end
             
            if size(extremum,2)==0
                extremum=[];            
            else
                extremum=extremum(find(flag~=0));             
            end
        end   
    %extremum=extremum(find(extremum>0 & extremum<=curveLen)); % find corners which are not endpoints of the curve             
    index{i} = extremum';
   % Sig(i,1) = sig;
    n = size(extremum,2);
    for j = 1:n
        corners = [corners; curve{i}(extremum(j),:)];
        cd = [cd; C(extremum(j))];
    end    
   
    fl = 1;
    if fl
     if curve_mode(i,:)=='loop'       
        if n>1
            compare_corner=corners-ones(size(corners,1),1)*curve_start(i,:);
            compare_corner=compare_corner.^2;
            compare_corner=compare_corner(:,1)+compare_corner(:,2);
            if min(compare_corner)>100       % Add end points far from detected corners, i.e. outside of 5 by 5 neighbor                                                
                left = smoothed_curve(extremum(1):-1:1,:);
                right = smoothed_curve(end:-1:extremum(end),:);
                ang=curve_tangent([left;right],extremum(1)); % detect corner at the first point or last point of the loop curve
                if ang>T_angle & ang<(360-T_angle) % if angle is between T_angle = 162 and (360-T_angle) = 198                
                    
                else%if C(W+1)>T/2
                    corners = [corners; curve_start(i,:)];
                    cd = [cd;5];
                end
            end
        end
     end
    end  
    end
    end
    here = 1;
end

here = 1;


        
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function Cd = accumulate_chord_distance(xs,ys,chordLen,curveLen,curve_mode,point_selected,W);

Cd = zeros(1,curveLen);

for j = 1:size(point_selected,2)
    k = point_selected(j)+W; 
    %if k>W
    xk = xs(k); % (x1,y1) = point at which distance will be accumulated
    yk = ys(k);      
        
    if k-chordLen+1 < 1
        s = 1;
    else
        s = k-chordLen+1;
    end
                
    for i = s:k-1
        if i+chordLen <= curveLen
            x1 = xs(i); % (leftx,lefty) = current left point for which distance will be accumulated
            y1 = ys(i); 

            x2 = xs(i+chordLen); % (rightx,righty) = current right point for which distance will be accumulated
            y2 = ys(i+chordLen);

            a = y2-y1; % coefficients of st. line through points (x1,y1) and (x2,y2)
            b = x1-x2;
            c = x2*y1 - x1*y2;
            dist = (a*xk + b*yk + c)/sqrt(a*a+b*b);
            Cd(1,k) = Cd(1,k)+ dist;
        else
            break;
        end
    end
    %end
end
here = 1;

%%%%%%%%%%%55
function [xse yse] = enlarge(xs,ys,CL,curve_mode);
%CL = chord length
L = size(xs,1);
if curve_mode=='loop' % wrap around the curve by CL pixles at both ends
    xse = [xs(L-CL+1:L);xs;xs(1:CL)];
    yse = [ys(L-CL+1:L);ys;ys(1:CL)];
else % extend each line curve by CL pixels at both ends
    xse = [ones(CL,1)*2*xs(1)-xs(CL+1:-1:2);xs;ones(CL,1)*2*xs(L)-xs(L-1:-1:L-CL)];
    yse = [ones(CL,1)*2*ys(1)-ys(CL+1:-1:2);ys;ones(CL,1)*2*ys(L)-ys(L-1:-1:L-CL)];
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%
function [xs ys gau W] = smoothing(x,y,L,curve_mode,sig,mode);
[gau W] = makeGFilter(sig);

if L>W
    if curve_mode=='loop' % wrap around the curve by W pixles at both ends
        x1 = [x(L-W+1:L);x;x(1:W)];
        y1 = [y(L-W+1:L);y;y(1:W)];
    else % extend each line curve by W pixels at both ends
        x1 = [ones(W,1)*2*x(1)-x(W+1:-1:2);x;ones(W,1)*2*x(L)-x(L-1:-1:L-W)];
        y1 = [ones(W,1)*2*y(1)-y(W+1:-1:2);y;ones(W,1)*2*y(L)-y(L-1:-1:L-W)];
    end
    
    xx=conv(x1,gau);    
    yy=conv(y1,gau);
    if (mode == 1)
        xs=xx(W+1:L+3*W);
        ys=yy(W+1:L+3*W);    
    else
        xs=xx(2*W+1:L+2*W);
        ys=yy(2*W+1:L+2*W);    
    end
else
    xs = [];
    ys = [];    
end

%%%%

function [sig] = find_sig(L);
if L<=100
    sig = 3;
    %wid = 4;
elseif L<=200
    sig = 3;
    %wid = 8;
else
    sig = 3;
    %wid = 12;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
% extract curves from input edge-image
function [curve,curve_start,curve_end,curve_mode,cur_num,TJ,img]=extract_curve(BW,Gap_size)
%   Function to extract curves from binary edge map, if the endpoint of a
%   contour is nearly connected to another endpoint, fill the gap and continue
%   the extraction. The default gap size is 1 pixel
[L,W]=size(BW);
BW1=zeros(L+2*Gap_size,W+2*Gap_size);
BW_edge=zeros(L,W);
BW1(Gap_size+1:Gap_size+L,Gap_size+1:Gap_size+W)=BW;
[r,c]=find(BW1==1); %returns indices of non-zero elements
cur_num=0;

while size(r,1)>0 %when number of rows > 0
    point=[r(1),c(1)];
    cur=point;
    BW1(point(1),point(2))=0; %make the pixel black
    [I,J]=find(BW1(point(1)-Gap_size:point(1)+Gap_size,point(2)-Gap_size:point(2)+Gap_size)==1); 
                               %find if any pixel around the current point is an edge pixel
    while size(I,1)>0 %if number of row > 0
        dist=(I-Gap_size-1).^2+(J-Gap_size-1).^2;
        [min_dist,index]=min(dist);
        p=point+[I(index),J(index)];
        point = p-Gap_size-1; % next is the current point
        cur=[cur;point]; %add point to curve 
        BW1(point(1),point(2))=0;%make the pixel black
        [I,J]=find(BW1(point(1)-Gap_size:point(1)+Gap_size,point(2)-Gap_size:point(2)+Gap_size)==1);
                                %find if any pixel around the current point 
                                %is an edge pixel
    end
    
    % Extract edge towards another direction
    point=[r(1),c(1)];
    BW1(point(1),point(2))=0;
    [I,J]=find(BW1(point(1)-Gap_size:point(1)+Gap_size,point(2)-Gap_size:point(2)+Gap_size)==1);
    
    while size(I,1)>0
        dist=(I-Gap_size-1).^2+(J-Gap_size-1).^2;
        [min_dist,index]=min(dist);
        point=point+[I(index),J(index)]-Gap_size-1;
        cur=[point;cur];
        BW1(point(1),point(2))=0;
        [I,J]=find(BW1(point(1)-Gap_size:point(1)+Gap_size,point(2)-Gap_size:point(2)+Gap_size)==1);
    end
        
    if size(cur,1)>(size(BW,1)+size(BW,2))/25 % for 512 by 512 image, choose curve if its length > 40
        cur_num=cur_num+1;                    % One can change this value to control the length of the extracted edges
        curve{cur_num}=cur-Gap_size;
    end
    [r,c]=find(BW1==1);
    
end

for i=1:cur_num
    curve_start(i,:)=curve{i}(1,:);
    curve_end(i,:)=curve{i}(size(curve{i},1),:);
    if (curve_start(i,1)-curve_end(i,1))^2+...
        (curve_start(i,2)-curve_end(i,2))^2<=25  %if curve's ends are within sqrt(32) pixels
        curve_mode(i,:)='loop';
    else
        curve_mode(i,:)='line';
    end
    BW_edge(curve{i}(:,1)+(curve{i}(:,2)-1)*L)=1;
end
%%%
if cur_num>0
    TJ = find_TJunctions(curve, cur_num, Gap_size+1); % if a contour goes just outsize of ends, i.e., outside of gapsize we note a T-junction there
else
    curve{1} = [];
    curve_start = [];
    curve_end = [];
    curve_mode = [];
    cur_num = [];
    TJ = [];    
end
%%%
img=~BW_edge;
%%%%%%%%%%%%%%%%%%%%%%%%%%%


% find T-junctions within (gap by gap) neighborhood, where gap = Gap_size +
% 1; edges were continued (see edge_extraction procedure) when ends are within (Gap_size by Gap_size)
function TJ = find_TJunctions(curve, cur_num, gap); % finds T-Junctions in planar curves
TJ = [];
for i = 1:cur_num
    cur = curve{i};
    szi = size(cur,1);
    for j = 1:cur_num
        if i ~= j
            temp_cur = curve{j};
            compare_send = temp_cur - ones(size(temp_cur, 1),1)* cur(1,:);
            compare_send = compare_send.^2;
            compare_send = compare_send(:,1)+compare_send(:,2);
            if min(compare_send)<=gap*gap       % Add curve strat-points as T-junctions using a (gap by gap) neighborhood
                TJ = [TJ; cur(1,:)];
            end
            
            compare_eend = temp_cur - ones(size(temp_cur, 1),1)* cur(szi,:);
            compare_eend = compare_eend.^2;
            compare_eend = compare_eend(:,1)+compare_eend(:,2);
            if min(compare_eend)<=gap*gap       % Add end-points T-junctions using a (gap by gap) neighborhood
                TJ = [TJ; cur(szi,:)];
            end
        end
    end
end
%%%

% Compare T-junctions with obtained corners and add T-junctions to corners
% which are far away (outside a 5 by 5 neighborhood) from detected corners
function [corner_final c3] = Refine_TJunctions(corner_out,TJ,c2,curve, curve_num, curve_start, curve_end, curve_mode,EP);
%corner_final = corner_out;
c3=c2;

%%%%% add end points
if EP
    corner_num = size(corner_out,1);
    for i=1:curve_num
            if size(curve{i},1)>0 & curve_mode(i,:)=='line'

                % Start point compare with detected corners
                compare_corner=corner_out-ones(size(corner_out,1),1)*curve_start(i,:);
                compare_corner=compare_corner.^2;
                compare_corner=compare_corner(:,1)+compare_corner(:,2);
                if min(compare_corner)>100       % Add end points far from detected corners 
                    corner_num=corner_num+1;
                    corner_out(corner_num,:)=curve_start(i,:);
                    c3 = [c3;8];
                end

                % End point compare with detected corners
                compare_corner=corner_out-ones(size(corner_out,1),1)*curve_end(i,:);
                compare_corner=compare_corner.^2;
                compare_corner=compare_corner(:,1)+compare_corner(:,2);
                if min(compare_corner)>100
                    corner_num=corner_num+1;
                    corner_out(corner_num,:)=curve_end(i,:);
                    c3 = [c3;9];
                end
            end
    end
end
%%%%%%%%%%%%%%%5

%%%%%Add T-junctions
corner_final = corner_out;
for i=1:size(TJ,1)
    % T-junctions compared with detected corners
    if size(corner_final)>0
        compare_corner=corner_final-ones(size(corner_final,1),1)*TJ(i,:);
        compare_corner=compare_corner.^2;
        compare_corner=compare_corner(:,1)+compare_corner(:,2);
        if min(compare_corner)>100       % Add end points far from detected corners, i.e. outside of 5 by 5 neighbor
            corner_final = [corner_final; TJ(i,:)];
            c3 = [c3;10];
        end
    else
        corner_final = [corner_final; TJ(i,:)];
        c3 = [c3;10];
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% show corners into the output images or into the edge-image
function img1=mark(img,x,y,w)
[M,N,C]=size(img);
img1=img;
if isa(img,'logical')
    img1(max(1,x-floor(w/2)):min(M,x+floor(w/2)),max(1,y-floor(w/2)):min(N,y+floor(w/2)),:)=...
        (img1(max(1,x-floor(w/2)):min(M,x+floor(w/2)),max(1,y-floor(w/2)):min(N,y+floor(w/2)),:)<1);
    img1(x-floor(w/2)+1:x+floor(w/2)-1,y-floor(w/2)+1:y+floor(w/2)-1,:)=...
        img(x-floor(w/2)+1:x+floor(w/2)-1,y-floor(w/2)+1:y+floor(w/2)-1,:);
else
    img1(max(1,x-floor(w/2)):min(M,x+floor(w/2)),max(1,y-floor(w/2)):min(N,y+floor(w/2)),:)=...
        (img1(max(1,x-floor(w/2)):min(M,x+floor(w/2)),max(1,y-floor(w/2)):min(N,y+floor(w/2)),:)<128)*255;
    img1(x-floor(w/2)+1:x+floor(w/2)-1,y-floor(w/2)+1:y+floor(w/2)-1,:)=...
        img(x-floor(w/2)+1:x+floor(w/2)-1,y-floor(w/2)+1:y+floor(w/2)-1,:);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%
function ang=curve_tangent(cur,center) % center is always the position of the corresponding extrema in cur

for i=1:2
    if i==1
        curve=cur(center:-1:1,:);
    else
        curve=cur(center:size(cur,1),:);
    end
    L=size(curve,1);
    
    if L>3
        if sum(curve(1,:)~=curve(L,:))~=0 % if not collinear
            M=ceil(L/2);
            x1=curve(1,1);
            y1=curve(1,2);
            x2=curve(M,1);
            y2=curve(M,2);
            x3=curve(L,1);
            y3=curve(L,2);
        else
            M1=ceil(L/3);
            M2=ceil(2*L/3);
            x1=curve(1,1);
            y1=curve(1,2);
            x2=curve(M1,1);
            y2=curve(M1,2);
            x3=curve(M2,1);
            y3=curve(M2,2);
        end
        
        if abs((x1-x2)*(y1-y3)-(x1-x3)*(y1-y2))<1e-8  % straight line
            tangent_direction=angle(complex(curve(L,1)-curve(1,1),curve(L,2)-curve(1,2)));
        else
            % Fit a circle 
            x0 = 1/2*(-y1*x2^2+y3*x2^2-y3*y1^2-y3*x1^2-y2*y3^2+x3^2*y1+y2*y1^2-y2*x3^2-y2^2*y1+y2*x1^2+y3^2*y1+y2^2*y3)/(-y1*x2+y1*x3+y3*x2+x1*y2-x1*y3-x3*y2);
            y0 = -1/2*(x1^2*x2-x1^2*x3+y1^2*x2-y1^2*x3+x1*x3^2-x1*x2^2-x3^2*x2-y3^2*x2+x3*y2^2+x1*y3^2-x1*y2^2+x3*x2^2)/(-y1*x2+y1*x3+y3*x2+x1*y2-x1*y3-x3*y2);
            % R = (x0-x1)^2+(y0-y1)^2;

            radius_direction=angle(complex(x0-x1,y0-y1));
            if radius_direction<0
                radius_direction = 2*pi-abs(radius_direction);
            end
            
            adjacent_direction=angle(complex(x2-x1,y2-y1));
            
            if adjacent_direction<0
                adjacent_direction = 2*pi-abs(adjacent_direction);
            end
            
            tangent_direction=sign(sin(adjacent_direction-radius_direction))*pi/2+radius_direction;
            if tangent_direction<0
                tangent_direction = 2*pi-abs(tangent_direction);
            elseif tangent_direction>2*pi
                tangent_direction = tangent_direction-2*pi;
            end
        end
    
    else % very short line
        tangent_direction=angle(complex(curve(L,1)-curve(1,1),curve(L,2)-curve(1,2)));
    end
    direction(i)=tangent_direction*180/pi;
end
ang=abs(direction(1)-direction(2));
%%%%%%%%%%%%%%%%%%5

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% parses the inputs into input_parameters
function [I,sig,Hg,Lo,Gap_size,EP] = parse_inputs(varargin);

error(nargchk(0,5,nargin));
Para=[2.5,0.7,0.2,1,0]; %Default experience value;
if nargin>=2
    I=varargin{1};
    for i=2:nargin
        if size(varargin{i},1)>0
            Para(i-1)=varargin{i};
        end
    end
end

if nargin==1
    I=varargin{1};
end
    
if nargin==0 | size(I,1)==0
    [fname,dire]=uigetfile('*.bmp;*.jpg;*.gif','Open the image to be detected');
    I=imread([dire,fname]);
end

sig = Para(1);
Hg = Para(2); % high edge detection threshold
Lo = Para(3); % low edge detection threshold
Gap_size = Para(4);
EP = Para(5);
%%%%%%%%%%%%%%%%%%%%%%%%

function [G W] = makeGFilter(sig);

GaussianDieOff = .0001; 
pw = 1:100;

ssq = sig*sig;
W = max(find(exp(-(pw.*pw)/(2*ssq))>GaussianDieOff));
if isempty(W)
    W = 1;  
end
t = (-W:W);
gau = exp(-(t.*t)/(2*ssq))/(2*pi*ssq); 
G=gau/sum(gau);

function [gau width] = find_Gaussian(sig);
GaussianDieOff = .0001; 
pw = 1:30; 
ssq = sig*sig;
width = max(find(exp(-(pw.*pw)/(2*ssq))>GaussianDieOff));
if isempty(width)
    width = 1;  
end
t = (-width:width);
gau = exp(-(t.*t)/(2*ssq))/(2*pi*ssq); 
gau=gau/sum(gau);

Contact us