Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function [h, margin] = circle_hough(b, rrange, varargin)
- %CIRCLE_HOUGH Hough transform for circles
- % [H, MARGIN] = CIRCLE_HOUGH(B, RADII) takes a binary 2-D image B and a
- % vector RADII giving the radii of circles to detect. It returns the 3-D
- % accumulator array H, and an integer MARGIN such that H(I,J,K) contains
- % the number of votes for the circle centred at B(I-MARGIN, J-MARGIN),
- % with radius RADII(K). Circles which pass through B but whose centres
- % are outside B receive votes.
- %
- % [H, MARGIN] = CIRCLE_HOUGH(B, RADII, opt1, ...) allows options to be
- % set. Each option is a string, which if included has the following
- % effect:
- %
- % 'same' returns only the part of H corresponding to centre positions
- % within the image. In this case H(:,:,k) has the same dimensions as B,
- % and MARGIN is 0. This option should not be used if circles whose
- % centres are outside the image are to be detected.
- %
- % 'normalise' multiplies each slice of H, H(:,:,K), by 1/RADII(K). This
- % may be useful because larger circles get more votes, roughly in
- % proportion to their radius.
- %
- % The spatial resolution of the accumulator is the same as the spatial
- % resolution of the original image. Smoothing the accumulator array
- % allows the effective resolution to be controlled, and this is probably
- % essential for sensitivity to circles of arbitrary radius if the spacing
- % between radii is greater than 1. If time or memory requirements are a
- % problem, a generalisation of this function to allow larger bins to be
- % used from the start would be worthwhile.
- %
- % Each feature in B is allowed 1 vote for each circle. This function
- % could easily be generalised to allow weighted features.
- %
- % See also CIRCLEPOINTS, CIRCLE_HOUGHPEAKS, CIRCLE_HOUGHDEMO
- % Copyright David Young 2008, 2010
- % argument checking
- opts = {'same' 'normalise'};
- narginchk(2, 2+length(opts));
- validateattributes(rrange, {'double'}, {'real' 'positive' 'vector'});
- if ~all(ismember(varargin, opts))
- error('Unrecognised option');
- end
- % get indices of non-zero features of b
- [featR, featC] = find(b);
- % set up accumulator array - with a margin to avoid need for bounds checking
- [nr, nc] = size(b);
- nradii = length(rrange);
- margin = ceil(max(rrange));
- nrh = nr + 2*margin; % increase size of accumulator
- nch = nc + 2*margin;
- h = zeros(nrh*nch*nradii, 1, 'uint32'); % 1-D for now, uint32 a touch faster
- % get templates for circles at all radii - these specify accumulator
- % elements to increment relative to a given feature
- tempR = []; tempC = []; tempRad = [];
- for i = 1:nradii
- [tR, tC] = circlepoints(rrange(i));
- tempR = [tempR tR]; %#ok<*AGROW>
- tempC = [tempC tC];
- tempRad = [tempRad repmat(i, 1, length(tR))];
- end
- % Convert offsets into linear indices into h - this is similar to sub2ind.
- % Take care to avoid negative elements in either of these so can use
- % uint32, which speeds up processing by a factor of more than 3 (in version
- % 7.5.0.342)!
- tempInd = uint32( tempR+margin + nrh*(tempC+margin) + nrh*nch*(tempRad-1) );
- featInd = uint32( featR' + nrh*(featC-1)' );
- % Loop over features
- for f = featInd
- % shift template to be centred on this feature
- incI = tempInd + f;
- % and update the accumulator
- h(incI) = h(incI) + 1;
- end
- % Reshape h, convert to double, and apply options
- h = reshape(double(h), nrh, nch, nradii);
- if ismember('same', varargin)
- h = h(1+margin:end-margin, 1+margin:end-margin, :);
- margin = 0;
- end
- if ismember('normalise', varargin)
- h = bsxfun(@rdivide, h, reshape(rrange, 1, 1, length(rrange)));
- end
- end
Add Comment
Please, Sign In to add comment