【问题标题】:Circle detection from gray level image in MATLABMATLAB中灰度图像的圆形检测
【发布时间】:2014-11-28 04:38:45
【问题描述】:

我有如下所示的图像。我的目标是检测第二张图片中显示的圆圈。我用了[centers,radii] = imfindcircles(IM,[100 300]);,但什么也没找到。

还有其他方法可以检测圆圈吗?我该怎么做?

原图:

圆圈:我用颜料画的。

【问题讨论】:

  • 如果你设置阈值会发生什么?
  • 显然你需要使用imfindcircles的参数。尝试将'ObjectPolarity' 设置为'birght',将'EdgeThreshold' 设置为非常低的值并使用'Sensitivity'

标签: matlab image-processing geometry


【解决方案1】:

这是 imfindcircles 的替代解决方案。基本上对图像进行阈值处理,使用磁盘结构元素对其进行扩展,然后在找到边缘后,应用霍夫变换以使用文件交换here 提供的circle_hough 算法检测圆。

代码如下:

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's 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)

这给出了以下内容:

您可以使用传递给阈值或扩张的参数来查看它如何影响结果。

希望有帮助!

【讨论】:

    【解决方案2】:

    这是解决此问题的另一种方法。它不是基于霍夫变换,因为 imfindcircles 和以前的答案是。

    基本上:

    1. 分割图像(使用 Otsu 方法估计阈值)
    2. 找到连通的组件,只留下 2% 的组件,从面积较大的组件开始
    3. 用小半径的圆(圆盘)放大图像
    4. 再次寻找连通分量,以面积最大的分量为圆

    HT 有时会很慢,具体取决于输入数据的大小和分辨率。比较两种方法(HT、非 HT)的执行时间可能很有用。

    所提出的方法也可能能够检测另一种形状(非圆形)的物体。

    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
    

    【讨论】: