Subversion Repositories seema-scanner

Rev

Blame | Last modification | View Log | RSS feed

% ========================================================================================= 
% Author: Andre A. Boechat
% File: hough_ellipse.m
% Date: February 27, 2014, 10:12:22 AM
% Description: Implementation of the classical Hough Transform algorithm to detect 
% ellipses.
% 
% Reference: 
% [1] Y. Xie and Q. Ji, “A new efficient ellipse detection method,” Pattern
% Recognition, 2002. Proceedings. 16th …, vol. 2, pp. 957–960, 2002.
%
% [2] http://en.wikipedia.org/wiki/Hough_transform
% [3] http://en.wikipedia.org/wiki/Randomized_Hough_transform
% ========================================================================================= 
%
% Usage:
% [PARAMETERS] = hough_ellipse(IMG, MIN2A = 10, MIN_VOTES = 10)
%
% Inputs:
% IMG is the inputs image. Images composed of only edges are better.
% MIN2A is the minimum length of the major axis (default 10).
% MIN_VOTES is the minimum number of votes on a "b" value (half-length of the minor 
%   axis) to validate the existence of an ellipse.
%
% Outputs:
% PARAMETERS is the parameters of the best fitted ellipse on the image and is 
%   composed of [x0 y0 a b alpha] (ellipse's center, major and minor 
%   half-length axis and orientation, respectively).
% 
% 
% Possible improvement: to return a matrix with all best fitted ellipses on the 
% image. It adds another loop to the algorithm.

function [parameters] = hough_ellipse(img, min2a, min_votes)

    [width height] = size(img);
    %% Finding all nonzero pixels of the image, possible ellipse's pixels.
    [ys xs] = find(img);
    pixels = [xs ys];
    %% Accumulator for the minor axis' half-length. The indexes correspond to the
    %% possible b values. 
    %% TODO: the data structure can be improved (tree with the possible values?).
    acc = zeros(1, max(width, height)/2);
    %% ij1, ij2 are indexes of (x1, y1) and (x2, y2), following the reference [1].
    for ij1 = 1:(length(xs)-1)
        for ij2 = length(xs):-1:(ij1+1)
            x1 = pixels(ij1, 1);
            y1 = pixels(ij1, 2);
            x2 = pixels(ij2, 1);
            y2 = pixels(ij2, 2);
            d12 = norm([x1 y1] - [x2 y2]);
            acc = acc * 0;
            if  x1 - x2 && d12 > min2a
                %% Center
                x0 = (x1 + x2)/2;
                y0 = (y1 + y2)/2;
                %% Half-length of the major axis.
                a = d12/2;
                %% Orientation.
                alpha = atan((y2 - y1)/(x2 - x1));
                %% Distances between the two points and the center.
                d01 = norm([x1 y1] - [x0 y0]);
                d02 = norm([x2 y2] - [x0 y0]);
                for ij3 = 1:length(xs)
                    %% The third point must be a different point, obviously.
                    if (ij3 == ij1) && (ij3 == ij2)
                        continue;
                    end
                    x3 = pixels(ij3, 1);
                    y3 = pixels(ij3, 2);
                    d03 = norm([x3 y3] - [x0 y0]);
                    %% Distance f
                    if  d03 >= a
                        continue;
                    end
                    f = norm([x3 y3] - [x2 y2]);
                    %% Estimating the half-length of the minor axis.
                    cos2_tau = ((a^2 + d03^2 - f^2) / (2 * a * d03))^2;
                    sin2_tau = 1 - cos2_tau;
                    b = round(sqrt((a^2 * d03^2 * sin2_tau) /...
                                (a^2 - d03^2 * cos2_tau)));
                    %% Changing the score of the accumulator, if b is a valid value.
                    %% NOTE: the accumulator's length gives us the biggest expected
                    %% value for b, which means, in this current implementation,
                    %% we wouldn't detect ellipses whose half of minor axis is
                    %% greater than the image's size (look at the acc's declaration).
                    if b > 0 && b <= length(acc)
                        acc(b) = acc(b)+1;
                    end
                    end
                %% Taking the highest score.
                [sv si] = max(acc);
                if sv > min_votes
                    %% Ellipse detected!
                    %% The index si gives us the best b value.
                    parameters = [x0 y0 a si alpha];
                    return;
                end
                    end
                    end
                    end
    printf("No ellipses detected!\n");
end