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







