边缘不完整的圆检测

信息处理 图像处理 图像分割
2022-01-29 16:00:16

我想检测下图中的圆圈,但是这种在轮廓上使用cv2.approxPolyDP并计算多边形边数的方法在这里不起作用,因为缺少一些圆圈。在这种情况下,有没有比使用霍夫变换更快的方法来检测形状?

符号

1个回答

这是约翰·BG。找到了一种检测交通信号圈的方法,避免了需要猜测其参数 Sensitivity 的imfindcircles 。

1.- 获取图像

clear all;clc;close all


A=imread('001.jpg');
figure(1);imshow(A);
% 001
A1=A(:,:,1);
[sz1 sz2]=size(A1)     % sz1: Y axis  sz2: X axis

th1=120                     % binarize
A2=A1;
A2(A2>th1)=255;
A2(A2<=th1)=0;
% figure(2);imshow(A2)

A3=bwmorph(A2,'skel',Inf)             % clean and thin
figure(3);imshow(A3)
% 002 

A4=bwlabel(A3,8);                         % number objects
hf4=figure(4);imshow(A4)

range_A4=unique(A4)';                      %  count objects
amount_segments=max(range_A4)

PA={}                                                                  

PA:单元格 PA 的每个元素包含 1 段的所有像素

CM= [1,1,0;  % yellow   
         1,0,1;  % magenta
         0,1,1;  % cyan 
         1,0,0;   % red
         0,1,0;   % green   
         0,0,1;   % blue    
         1,1,1]   % white   
nCM=[mod([1:1:amount_segments],size(CM,1))];
nCM(nCM==0)=size(CM,1)

for k=1:1:amount_segments % put pixels same object in same cell and colour objects
    [col1,row1,v]=find(A4==k);
    P_segment=[col1 row1];
    PA{k}=P_segment
    hold all                                                           % check all found points belong to same segment
    for m=1:1:length(P_segment)
        plot(hf4.CurrentAxes,P_segment(m,2),P_segment(m,1),'*','LineStyle',':','Color',CM(nCM(k),:))
    end

end
% 003

在此处输入图像描述

nPA=0;                                                        

确认大多数对象很小且不感兴趣

for k=1:1:size(PA,2)
    nPA=[nPA size(PA{k},1)]
end
max(nPA)
figure(5);histogram(nPA,max(nPA))
nPA(1)=[]
% 004

在此处输入图像描述

sizeCelln=@(n,cell1) size(cell1{n},1)

n2 格式:[给定段中的像素数量,标识 A4 中每个段的唯一数字]

n2=[0]                                                  
for k=1:1:amount_segments
    if sizeCelln(k,PA)>floor(max(nPA)/3)
        n2=[n2 k ];                % k is same as A4(PA{k}(1,1),PA{k}(1,2))
    end
end
n2(1)=[];
PA2=PA(n2)                                             

只保留那些大到可能看起来像圆形的

close(hf4);
hf4=figure(4);imshow(A4)
hold all
for k=n2                                                    % check all found points belong to same segment
    L3=PA{k}
    for m=1:1:size(L3,1)
        plot(hf4.CurrentAxes,L3(m,2),L3(m,1),'b*')
    end
end

在此处输入图像描述

以下是圈出的最佳候选对象(仅按像素数量)

s=[0 0 0 0 0 0 0];                

s 格式:[numeral mean(R) var(R) range(x) range(y) midpoint(x) midpoint(y)]

for k=n2                                
    L2=PA{k};
    x_midpoint=.5*(min(L2(:,1))+max(L2(:,1)))
    y_midpoint=.5*(min(L2(:,2))+max(L2(:,2)))
    R=((L2(:,1)-x_midpoint).^2+(L2(:,2)-y_midpoint).^2).^.5
    s=[s; k mean(R) var(R) range(L2(:,1)) range(L2(:,2)) x_midpoint y_midpoint]
end
s(1,:)=[];

与其他几何形状(如直线、正方形、矩形或椭圆)最相似的部分具有/具有明显区别于其他几何形状的特征。

nid=s(:,1);
R0=floor(s(:,2));
Rvar=.1*floor(10*s(:,3));
x_range=s(:,4);y_range=s(:,5);
x_mpoint=s(:,6);y_mpoint=s(:,7)

T1=table(nid,R0,Rvar,x_range,y_range,x_mpoint,y_mpoint)

T1 =
  10×7 table
     nid      R0      Rvar       x_range     y_range     x_mpoint     y_mpoint
     ___    ___    _____    _______    _______    ________    ________
     24     105     31.2         226           199          122             217.5   
     28      67    260.6          92           166          300              218   
     29      70    245.8          95           165         407.5            217.5   
     32      58    416.1        142           121          137              205.5   
     35      52    280.1        126           107          139              204.5   
     43      57    329.4        139           117         106.5            234.5   
     46      51    288.3        124           105          106              235.5   
     50      28    140.9         44             93          409               244.5   
     54      85    733.5        241           108         121.5             280   
     57      69    628.9        196            67          344               272.5  

圆圈具有以下属性:

single point centers 
constant radius
range(x) ~ range(y)

只有沿圆分布的线段点满足这 3 个条件。

n=[1:1:numel(nid)]

R2half_x_range_ratio=R0-abs(x_range)/2
R2half_y_range_ratio=R0-abs(y_range)/2
dxdy=abs(abs(x_range)-abs(y_range))

hf8=figure(6);plot(n,R0,n,Rvar,n,dxdy); grid on
xticks(hf8.CurrentAxes,[1:1:numel(nid)])
hf8.CurrentAxes.XTickLabelMode='manual'
hf8.CurrentAxes.XTickLabel=string(nid)'
xlabel('A4 segment numerals')
legend(hf8.CurrentAxes,'R','var(R)','\Deltax-\Deltay')

在此处输入图像描述

在此处输入图像描述

在这种情况下,捕捉圆的关键参数是最小的半径分散,同时在像素数量最多的片段中。

即使在上图中标有红色箭头的喇叭,找到的圆也相当居中并且半径是正确的。

最低半径色散

n10=find(Rvar==min(Rvar))
nid(n10)

C1=[T1.x_mpoint(n10) T1.y_mpoint(n10)]
R1=T1.R0(n10)
da=2*pi/100;
a=[0:da:2*pi];
Px1=R1*cos(a)+C1(2);Py1=R1*sin(a)+C1(1);
hold all;plot(hf4.CurrentAxes,Px1,Py1,'r','LineWidth',10)

在此处输入图像描述

所以,就是这样,交通信号圈已经被正确检测到了。

以下是已检查的其他标准,但不如最低半径中心方差清晰:

相似的 x 和 y 范围

n11=find(dxdy==min(dxdy))
nid(n11)

C2=[T1.x_mpoint(n11) T1.y_mpoint(n11)]
R2=T1.R0(n11)
Px2=R2*cos(a)+C2(:,2)
Py2=R2*sin(a)+C2(:,1)
hold all;
plot(hf4.CurrentAxes,Px2(1,:),Py2(1,:),'m','LineWidth',2)
plot(hf4.CurrentAxes,Px2(2,:),Py2(2,:),'m','LineWidth',2)

带有 R 的段与半范围最相似

RxRy=abs(R2half_x_range_ratio)-abs(R2half_y_range_ratio)
n12=find(RxRy==min(RxRy))
nid(n12)

C3=[T1.x_mpoint(n12) T1.y_mpoint(n12)]
R3=T1.R0(n12)

丢弃那些半径太小的段

不删除最短段

也就是说,不删除任何半径为 1/3 或小于峰值半径的段。

% 运行这个脚本的第 1 到 68 行,然后跳到这里:

PA2=PA
n2=[1:1:numel(PA)]

T2=table(nid,R0,Rvar,x_range,y_range,x_mpoint,y_mpoint)
 T2 =
   85×7 table
     nid     R0      Rvar        x_range    y_range      x_mpoint     y_mpoint
     ___    ___    _____    _______    _______    ________    ________
      1       4        3.2            14            4                57               3   
      2      10      37.4           37           16               85.5             9   
      3      10      36.1           36           23               94              12.5   
  ..

     83       2       2.2            7             6              431.5           422   
     84       2       0.9            7             2              437.5           428   
     85       3       0.5            9             7              448.5           430.5  

紧凑的脚本可通过电子邮件获得,请随时联系个人资料中的电子邮件地址。也欢迎任何更正评论或建议,以进一步发展此答案。

珍惜时间和注意力

约翰·BG

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

评论:

1.- 当小对象太多时,图表会变得太杂乱。

2.- 起始画面没有透视校正。

这导致圆圈看起来像椭圆。

3.-上述步骤还可以校正透视角度,甚至可以计算附近物体的尺寸。

4.- 交通信号盘必须相对于所有其他圆形形状相对较大,这与照片必须相对靠近信号交通拍摄,以便执行这些步骤。

5.- 命令imfindcircles要求参数Sensitivity上升到 0.95 才能开始检测圆圈,但奇怪的是它显示了一个真正的Sensitivity跨度,其中只捕获了一个有效的圆圈。稍微偏离 0.95,如下面的第二张图所示,添加了许多不相关的圆圈。

Rmin=20;Rmax=200;

close(hf4);
hf4=figure(4);imshow(A4)
[centers, radii] = imfindcircles(A4,[Rmin Rmax],'ObjectPolarity','dark','Sensitivity',.98);
viscircles(centers, radii,'Color','b');

close(hf4);
hf4=figure(4);imshow(A4)
[centers, radii] = imfindcircles(A4,[Rmin Rmax],'ObjectPolarity','dark','Sensitivity',.98);
viscircles(centers, radii,'Color','b');
% 012

在此处输入图像描述