Find Smallest Circle Fit to Image Blob

This will seek the smallest circle to fit to a given shape. The inputs wx, wy are the boundaries to the shape.

Further optimizations are likely possible.

Reference Discussions

https://www.wavemetrics.com/forum/general/iso-algorithm-apply-smallest-circle-problem

https://www.wavemetrics.com/forum/general/circle-cut-edges

// calculate the smallest circle to fit boundary defined by wy, wx
Function calc_SmallestCircle(wy,wx)
    wave wy, wx
    
    variable np, npl, npr
    variable px1, py1, px2, py2, px3, py3
    variable vm1, vm2
    
    // restrict to under 1000 points as needed to avoid long times
    np = numpnts(wx)
    npl = log(np)
    if (npl > 3)
        npl = trunc(npl)
        npr = trunc(np/10^npl)
        npl = (npr*10^(npl - 2))/5
        duplicate/O wx wdx
        duplicate/O wy wdy
        Resample/DOWN=(npl) wdx
        Resample/DOWN=(npl) wdy
        np = numpnts(wdx)
    else
        duplicate/O wx, wdx
        duplicate/O wy, wdy
        np = numpnts(wx)
    endif
 
    // calculate the distances  
    make/N=(np)/FREE/D dmaxarray
    dmaxarray = 0
    
    MultiThread dmaxarray = CalcMaxDistance(wdx, wdy, np, p)
    
    // get three points 
    make/N=3/D/FREE wpx, wpy
    npr = 0.03*np
    WaveStats/Q dmaxarray
    vm1 = v_maxloc
    wpx[0] = wdx[vm1]
    wpy[0] = wdy[vm1]
    npl = (vm1 - npr) < 0 ? 0 : vm1 - npr
    dmaxarray[npl,vm1 + npr] = 0
    WaveStats/Q/R=(inf,vm1) dmaxarray
    vm2 = v_maxloc
    wpx[1] = wdx[vm2]
    wpy[1] = wdy[vm2]
    npl = (vm2 + npr) > (np - 1) ? np - 1 : vm2 + npr
    dmaxarray[vm2 - npr, npl] = 0   
    if ((vm2 - vm1) > (np - vm2)) 
        WaveStats/Q/R=(vm1,vm2) dmaxarray
    else
        WaveStats/Q/R=(vm2,np-1) dmaxarray  
    endif
    wpx[2] = wdx[v_maxloc]
    wpy[2] = wdy[v_maxloc]
    dmaxarray[v_maxloc] = 0
    
    GetCircumCenter(wpx,wpy)
    return 0
end
 
ThreadSafe Function CalcMaxDistance(wx,wy,np,pp)
    wave wx, wy
    variable np, pp
    
    variable rmax
    
    // create 2-D wave  
    make/N=(np)/FREE dd = 0
    // calculate distances and return maximum
    dd = sqrt((wx[p] - wx[pp])^2 + (wy[p] - wy[pp])^2)
    rmax = wavemax(dd)
        
    return rmax
end
 
Function GetCircumCenter(wpx,wpy)
    wave wpx, wpy
    
    variable dlen, cx, cy, rc
    
    dlen = 2*(wpy[0]*wpx[2] + wpy[1]*wpx[0] - wpy[1]*wpx[2] - wpy[0]*wpx[1] - wpy[2]*wpx[0] + wpy[2]*wpx[1])
    
    cx = wpy[1]*wpx[0]^2 - wpy[2]*wpx[0]^2 - (wpy[1]^2)*wpy[0] + (wpy[2]^2)*wpy[0] 
    cx += (wpx[1]^2)*wpy[2] + (wpy[0]^2)*wpy[1] + wpx[2]^2*wpy[0] - (wpy[2]^2)*wpy[1] 
    cx += - (wpx[2]^2)*wpy[1] - (wpx[1]^2)*wpy[0] + (wpy[1]^2)*wpy[2] - (wpy[0]^2)*wpy[2]
    cx /= dlen
    
    cy = (wpx[0]^2)*wpx[2] + (wpy[0]^2)*wpx[2] + (wpx[1]^2)*wpx[0] - (wpx[1]^2)*wpx[2]
    cy += + (wpy[1]^2)*wpx[0] - (wpy[1]^2)*wpx[2] - (wpx[0]^2)*wpx[1] - (wpy[0]^2)*wpx[1]
    cy += - (wpx[2]^2)*wpx[0] + (wpx[2]^2)*wpx[1] - (wpy[2]^2)*wpx[0] + (wpy[2]^2)*wpx[1]
    cy /= dlen
    
    rc = sqrt((wpx[0] - cx)^2 + (wpy[0] - cy)^2)
 
    print "Values (cx, cy, rc) are: ", cx, cy, rc
    
    return 0
end

 

Forum

Support

Gallery

Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More