Exemplo n.º 1
0
def fit_cirlce(pp, warnIfIllDefined=True):
    """ fit_cirlce(pp, warnIfIllDefined=True)
    Calculate the circle (x - c.x)**2 + (y - x.y)**2 = c.r**2
    From the set of points pp. Returns a point instance with an added
    attribute "r" specifying the radius.
    
    In case the three points are on a line, the algorithm will fail, and
    return 0 for x,y and r. This waring can be suppressed.
    
    The solution is a Least Squares fit. The method as describes in [1] is
    called Modified Least Squares (MLS) and poses a closed form solution
    which is very robust.

    [1]
    Dale Umbach and Kerry N. Jones
    2000
    A Few Methods for Fitting Circles to Data
    IEEE Transactions on Instrumentation and Measurement
    """
    
    # Init error point
    ce = Point(0,0)
    ce.r = 0.0
    
    def cov(a, b):
        n = len(a)
        Ex = a.sum() / n
        Ey = b.sum() / n
        return ( (a-Ex)*(b-Ey) ).sum() / (n-1)
    
    # Get x and y elements
    X = pp[:,0]
    Y = pp[:,1]
    
    # In the paper there is a factor n*(n-1) in all equations below. However,
    # this factor is removed by devision in the equations in the following cell
    A = cov(X,X)
    B = cov(X,Y)
    C = cov(Y,Y)
    D = 0.5 * ( cov(X,Y**2) + cov(X,X**2) )
    E = 0.5 * ( cov(Y,X**2) + cov(Y,Y**2) )
    
    # Calculate denumerator
    denum = A*C - B*B
    if denum==0:
        if warnIfIllDefined:
            print("Warning: can not fit a circle to the given points.")
        return ce
    
    # Calculate point
    c = Point( (D*C-B*E)/denum, (A*E-B*D)/denum )
    
    # Calculate radius
    c.r = c.distance(pp).sum() / len(pp)
    
    # Done
    return c
Exemplo n.º 2
0
def get_slice(vol, sampling, center_point, global_direction,
              look_for_bifurcation, alpha):
    """
    Given two center points and the direction of the stent, the algorithm will 
    first create a slice on the second center point. A new center point is 
    calculated on this slice, which is used to find a local direction. The 
    local direction is used to update the global direction with weigthing
    factor alpha (where 0 is following the local direction and 1 the global 
    direction). Using this new direction a slice is created on the first center
    point.
    """

    vec1 = Point(1, 0, 0)
    vec2 = Point(0, 1, 0)

    #Set second center point as rotation point
    rotation_point = Point(center_point[2], center_point[1],
                           center_point[0]) + global_direction

    #Create the slice using the global direction
    slice, vec1, vec2 = slice_from_volume(vol, sampling, global_direction,
                                          rotation_point, vec1, vec2)

    #Search for points in this slice and filter these with the clustering method
    points_in_slice = stentPoints2d.detect_points(slice)

    try:
        points_in_slice_filtered = stentPoints2d.cluster_points(points_in_slice, \
        Point(128,128))
    except AssertionError:
        points_in_slice_filtered = []

    #if filtering did not succeed the unfiltered points are used
    if not points_in_slice_filtered:
        points_in_slice_filtered = points_in_slice
        succeeded = False
    else:
        succeeded = True

    #if looking for bifurcation than the radius has to be calculated
    if succeeded and look_for_bifurcation:

        center_point_with_radius = stentPoints2d.fit_cirlce( \
        points_in_slice_filtered)

        #convert 2d center point to 3d for the event that the bifurcation
        #is found
        center_point_3d_with_radius = convert_2d_point_to_3d_point( \
        Point(rotation_point[2], rotation_point[1], rotation_point[0]), vec1, vec2, center_point_with_radius)

        #Convert pointset into point
        center_point_3d_with_radius = Point(center_point_3d_with_radius[0])

        #Give the 3d center point the radius as attribute
        center_point_3d_with_radius.r = center_point_with_radius.r

    else:
        center_point_3d_with_radius = Point(0, 0, 0)
        center_point_3d_with_radius.r = []

    #Now the local direction of the stent has to be found. Note that it is not
    #done when the chopstick filtering did not succeed.
    if succeeded:
        better_center_point = stentPoints2d.converge_to_centre(points_in_slice_filtered, \
        Point(128,128))
    else:
        better_center_point = Point(0, 0), []

    #If no better center point has been found, there is no need to update global
    #direction
    if better_center_point[0] == Point(0, 0):
        updated_direction = global_direction
    else:
        better_center_point_3d = convert_2d_point_to_3d_point(\
        Point(rotation_point[2], rotation_point[1], rotation_point[0]), \
        vec1, vec2, better_center_point[0])

        #Change pointset into a point
        better_center_point_3d = Point(better_center_point_3d[0])

        #local direction (from starting center point to the better center point)
        local_direction = Point(better_center_point_3d[2]-center_point[2], \
        better_center_point_3d[1]-center_point[1], better_center_point_3d[0] \
        -center_point[0]).Normalize()

        #calculate updated direction
        updated_direction = ((1 - alpha) * local_direction +
                             alpha * global_direction).Normalize()

    #Now a new slice can be created using the first center point as rotation point.
    rotation_point = Point(center_point[2], center_point[1], center_point[0])

    slice, vec1, vec2 = slice_from_volume(vol, sampling, updated_direction,
                                          rotation_point, vec1, vec2)

    #Change order
    rotation_point = Point(center_point[0], center_point[1], center_point[2])

    #return new center point
    new_center_point = center_point + Point(updated_direction[2], \
    updated_direction[1], updated_direction[0])

    return slice, new_center_point, updated_direction, rotation_point, vec1, vec2, \
    center_point_3d_with_radius
Exemplo n.º 3
0
def converge_to_centre(pp, c, nDirections=5, maxRadius=50, pauseTime=0):
    """ converge_to_centre(pp, c)
    Given a set of points and an initial center point c, 
    will find a better estimate of the center.
    Returns (c, L), with L indices in pp that were uses to fit 
    the final circle.
    """
    
    # Shorter names
    N = nDirections
    pi = np.pi
    
    # Init point to return on error
    ce = Point(0,0)
    ce.r = 0
    
    # Are there enough points?
    if len(pp) < 3:
        return ce, []
    
    # Init a pointset of centers we've has so far
    cc = Pointset(2) 
    
    # Init list with vis objects (to be able to delete them)
    showObjects = []
    if pauseTime:
        fig = vv.gcf()
    
    
    while c not in cc:
        
        # Add previous center
        cc.append(c)
        
        # Calculate distances and angles
        dists = c.distance(pp)
        angs = c.angle2(pp)
        
        # Get index of closest points
        i, = np.where(dists==dists.min())
        i = iClosest = int(i[0])
        
        # Offset the angles with the angle relative to the closest point.
        refAng = angs[i]
        angs = subtract_angles(angs, refAng)
        
        # Init L, the indices to the closest point in each direction
        L = []
        
        # Get closest point on N directions
        for angle in [float(angnr)/N*2*pi for angnr in range(N)]:
            
            # Get indices of points that are in this direction
            dangs = subtract_angles(angs, angle)
            I, = np.where(np.abs(dangs) < pi/N )
            
            # Select closest
            if len(I):
                distSelection = dists[I]
                minDist = distSelection.min()
                J, = np.where(distSelection==minDist)
                if len(J) and minDist < maxRadius:
                    L.append( int(I[J[0]]) )
        
        # Check if ok
        if len(L) < 3:
            return ce, []
        
        # Remove spurious points (points much furter away that the 3 closest)
        distSelection = dists[L]
        tmp = [d for d in distSelection]
        d3 = sorted(tmp)[2] # Get distance of 3th closest point
        I, = np.where(distSelection < d3*2)
        L = [L[i] for i in I]
        
        # Select points
        ppSelect = Pointset(2)
        for i in L:
            ppSelect.append(pp[i])
        
        # Refit circle
        cnew = fit_cirlce(ppSelect,False)
        if cnew.r==0:
            return ce, []
        
        # Show
        if pauseTime>0:
            # Delete
            for ob in showObjects:
                ob.Destroy()
            # Plot center and new center
            ob1 = vv.plot(c, ls='', ms='x', mc='r', mw=10, axesAdjust=0)
            ob2 = vv.plot(cnew, ls='', ms='x', mc='r', mw=10, mew=0, axesAdjust=0)
            # Plot selection points            
            ob3 = vv.plot(ppSelect, ls='', ms='.', mc='y', mw=10, axesAdjust=0)
            # Plot lines dividing the directions
            tmpSet1 = Pointset(2)
            tmpSet2 = Pointset(2)            
            for angle in [float(angnr)/N*2*pi for angnr in range(N)]:
                angle = -subtract_angles(angle, refAng)
                dx, dy = np.cos(angle), np.sin(angle)
                tmpSet1.append(c.x, c.y)
                tmpSet1.append(c.x+dx*d3*2, c.y+dy*d3*2)
            for angle in [float(angnr+0.5)/N*2*pi for angnr in range(N)]:
                angle = -subtract_angles(angle, refAng)
                dx, dy = np.cos(angle), np.sin(angle)
                tmpSet2.append(c.x, c.y)
                tmpSet2.append(c.x+dx*d3*2, c.y+dy*d3*2)
            ob4 = vv.plot(tmpSet1, lc='y', ls='--', axesAdjust=0)
            ob5 = vv.plot(tmpSet2, lc='y', lw=3, axesAdjust=0)
            # Store objects and wait
            showObjects = [ob1,ob2,ob3,ob4,ob5]
            fig.DrawNow()
            time.sleep(pauseTime)
        
        # Use new
        c = cnew
    
    # Done    
    for ob in showObjects:
        ob.Destroy()
    return c, L