Finding a circle from a grayscale image in MATLAB

I have the image shown below. My goal is to locate the circle shown in the second image. I have used [centers,radii] = imfindcircles(IM,[100 300]);

but found nothing.

Is there another way to detect the circle? How can i do this?

Original Image: enter image description here

Circle: I painted it with paint. enter image description here

+3


source to share


2 answers


Here is an alternative solution to imfindcircles. Basically a threshold image by extending it with a disk structuring element and then, after finding the edges, apply the Hough transform to define the circle using the circle_hough

file sharing algorithm available here .

Here is the code:

clear
clc
close all

A = imread('CircleIm.jpg');

%// Some pre-processing. Treshold image and dilate it.
B = im2bw(A,.85);

se = strel('disk',2);

C = imdilate(B,se);

D = bwareaopen(C,10000);

%// Here imfill is not necessary but you might find it useful in other situations.
E = imfill(D,'holes');

%// Detect edges
F = edge(E);

%// circle_hough from the File Exchange.

%// This code is based on Andrey answer here:
%https://dsp.stackexchange.com/questions/5930/find-circle-in-noisy-data.

%// Generate range of radii.
 radii = 200:10:250;

h = circle_hough(F, radii,'same');
[~,maxIndex] = max(h(:));
[i,j,k] = ind2sub(size(h), maxIndex);
radius = radii(k);
center.x = j;
center.y = i;

%// Generate circle to overlay
N = 200;

theta=linspace(0,2*pi,N);
rho=ones(1,N)*radius;

%Cartesian coordinates
[X,Y] = pol2cart(theta,rho); 

figure;

subplot(2,2,1)
imshow(B);
title('Thresholded image  (B)','FontSize',16)

subplot(2,2,2)
imshow(E);
title('Filled image (E)','FontSize',16)

subplot(2,2,3)
imshow(F);hold on

plot(center.x-X,center.y-Y,'r-','linewidth',2);

title('Edge image + circle (F)','FontSize',16)

subplot(2,2,4)
imshow(A);hold on
plot(center.x-X,center.y-Y,'r-','linewidth',2);
title('Original image + circle (A)','FontSize',16)

      

Which gives the following:



enter image description here

You can play with the parameters passed to the threshold, or expand to see how this affects the result.

Hope it helps!

+5


source


Here's another approach to solving this problem. It is not based on the Hough transform as imfindcircles and the previous answer.

Basically:

  • Image segment (threshold estimated using the Otsu method)
  • Find the connected components and leave only 2% of them, starting with the ones whose area is larger.
  • Expand the image with a small circle (disk)
  • Find the newly connected components and take the component with the largest area as a circle


HT is sometimes slow, depending on input size and resolution. It may be helpful to compare the execution times of both approaches (HT, non HT).

The proposed method can also detect objects of a different shape (non-circular).

function[circle] = ipl_find_circle(I)

% NOTE: I is assumed to be a grayscale image

% Step 1: Segment image using Otsuยดs method
t = graythresh(I); 
BW = im2bw(I, t); 

% Step 2: Leave just "big" components on binary image
[L, num] = bwlabel(BW); 
stats = regionprops(L, 'Area', 'PixelIdxList');
area_vector = [stats(:).Area];
area_vector = sort(area_vector);
threshold_pos = floor(num * 0.98);
threshold = area_vector(threshold_pos);

for i=1:num
    if(stats(i).Area < threshold)
        BW(stats(i).PixelIdxList) = false;
    end
end

% Step 3: Dilate image with a circle of small radius
str = strel('disk', 5); 
BW = imdilate(BW, str); 

% Step 4: Take component with biggest area as the circle
L = bwlabel(BW); 
stats = regionprops(L, 'Area', 'BoundingBox', 'Centroid', 'EquivDiameter');
area_vector = [stats(:).Area];
[max_value, max_idx] = max(area_vector);
soi = stats(max_idx);

% Set output variable
circle = imcrop(I, soi.BoundingBox);

% Display results
radius = soi.EquivDiameter/2;
N = 1000;
theta = linspace(0, 2*pi, N);
rho = ones(1, N) * radius;
[X,Y] = pol2cart(theta, rho);
X = soi.Centroid(1) - X;
Y = soi.Centroid(2) - Y;

figure; 
subplot(1,2,1);
imshow(I);
hold on;
plot(X, Y, '-r', 'LineWidth', 2);
title('Original graycale image + circle', 'FontSize', 12)

subplot(1,2,2);
imshow(circle);
title('Circle region', 'FontSize', 12);

end

      

+2


source







All Articles