2
$\begingroup$

I want to detect circles in the image below but this approach, of using cv2.approxPolyDP on contours and counting the sides of the polygon, doesn't work here since some of the circle is missing. Is there a faster way of detecting shapes in this case than using the Hough Transform?

sign

$\endgroup$
1
$\begingroup$

this is John BG. Found a way to detect the traffic signal circle avoiding imfindcircles that requires the guessing of its parameter Sensitivity.

1.- Acquiring image

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: each element of cell PA contains all pixels of 1 segment

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

enter image description here

nPA=0;                                                        

confirming that majority objects are small and of no interest

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

enter image description here

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

n2 format: [amount pixels in given segment , unique numeral identifying each segment in 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)                                             

keep only the ones large enough to potentially look like circle

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

enter image description here

Following, the best candidates (by amount pixels only) to circle

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

s format: [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,:)=[];

The segment(s) that best resemble(s) circle(s) has/have characteristics clearly distinctive against other geometries like straight lines, squares, rectangles or ellipses.

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  

Circles have properties like:

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

Only segment points distributed along a circle meet these 3 conditions.

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

enter image description here

enter image description here

In this context the key parameters to catch circles are lowest radius dispersion and at the same time among segments with largest amount of pixels.

Even with the horn marked with a red arrow in the previous figure, the circle found is fairly centred and the radius is correct.

lowest Radius dispersion

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)

enter image description here

So, this is it, the traffic signal circle has been correctly detected.

Following, additional criteria that have been checked, but are not as clear as the lowest radius centred variance:

Similar x and y ranges

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)

Segments with R Most similar to half ranges

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)

discarding those segments with Radius too small

Without removing shortest segments

this is, without removing any segment with radius 1/3rd or shorter than peak radius.

% Run lines 1 to 68 of this script, then hop here:

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  

The compact script is available by email, feel free to contact, email address in Profile. Also welcome any correction comment or suggestion for further development of this answer.

Appreciating time and attention

John BG

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

Comments:

1.- When too many small objects the graphs get too cluttered.

2.- The start picture does not have perspective correction.

This causing circles to look like ellipses.

3.- The above steps also allow correction of perspective angle, and even calculate dimensions of nearby objects.

4.- The traffic signal dish has to be relatively large to all other circle-like shapes which is the same as the photo has to be taken relatively close to the signal traffic, for these steps to.

5.- The command imfindcircles requires the parameter Sensitivity to go up to .95 in order to start detecting circles, but it oddly shows a really span of Sensitivity where just a valid circle is caught. Just a bit off 0.95 and as shown in the 2nd figure below a multitude of non-relevant circles are added.

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

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.