示例#1
0
 def __init__(self):
     
     # Init visualization
     fig = vv.figure(102); vv.clf()
     a = vv.gca()
     
     # Init points
     pp = Pointset(2)
     pp.append(14,12)
     pp.append(12,16)
     pp.append(16,16)
     self._pp = vv.plot(pp, ls='', ms='.', mw=10, mc='g')
     
     # Init line representing the circle
     self._cc = vv.plot(pp, lc='r', lw=2, ms='.', mw=5, mew=0, mc='r')
     
     # Set limits
     a.SetLimits((0,32), (0,32))
     a.daspectAuto = False
     
     # Init object being moved
     self._movedPoint = None
     
     # Enable callbacks
     self._pp.hitTest = True
     self._pp.eventMouseDown.Bind(self.OnDown)
     self._pp.eventMouseUp.Bind(self.OnUp)
     a.eventMotion.Bind(self.OnMotion)
     a.eventDoubleClick.Bind(self.OnDD)
     
     # Start
     self.Apply()
示例#2
0
 def Apply(self):
     
     # Create big list of points
     pp = Pointset(2)
     for y in range(self._patchSize):
         for x in range(self._patchSize):            
             pp.append(x,y)
     
     # Get point locations
     c = Point( self._c._points[0].x, self._c._points[0].y )
     p1 = Point( self._p1._points[0].x, self._p1._points[0].y )
     p2 = Point( self._p2._points[0].x, self._p2._points[0].y )
     
     # Get masks
     M1, M2 = chopstick_criteria(c, p1, p2, pp)
     M1.shape = self._patchSize, self._patchSize
     M2.shape = self._patchSize, self._patchSize
     
     # Update image
     self._im[:] = 9
     self._im[M1] -= 3 
     self._im[M2] -= 3 
     self._t.Refresh()
     
     # Draw
     self._c.Draw()
示例#3
0
 def Apply(self):
     
     # Get 2D pointset
     pp = Pointset(2)
     for p in self._pp._points:
         pp.append(p.x, p.y)
     
     # Fit circle and sample and show
     c = fit_cirlce(pp)
     cc = sample_circle(c, 32)
     self._cc.SetPoints(cc)
     
     # Draw
     self._cc.Draw()
示例#4
0
def check_for_nodes(connecting_points, slice_i_plus_1):
    """
    Given a set of stent points, the algorithm checks whether there are any 
    duplicates. A duplicate would mean that that point was found by two stent 
    points and could therefore be a node. An additional check is done to check 
    whether there are no connecting points above the potential node. If this is 
    the case, than the point is not a node.
    """

    #Pointset to store 2D nodes
    point_nodes = Pointset(2)

    #Pointset to store point which need to be removed
    point_remove = Pointset(2)

    #points in slice_i_plus_1
    points_check = stentPoints2d.detect_points(slice_i_plus_1)

    #For every connecting point
    for i in range(len(connecting_points)):
        for j in range(len(connecting_points)):

            #if points are the same
            if connecting_points[i].Distance(
                    connecting_points[j]) <= 3 and i != j:

                #check if this point would find a connecting point
                point = Pointset(2)
                point.Append(connecting_points[i])
                node_check, unused = find_connecting_points(
                    point, points_check)

                #Only add node once.
                if not node_check:
                    if not point_nodes:
                        point_nodes.Append(
                            (connecting_points[i] + connecting_points[j]) / 2)
                    elif point_nodes.Contains(connecting_points[i]) == False:
                        point_nodes.Append(
                            (connecting_points[i] + connecting_points[j]) / 2)

                    #The connecting points need to be removed later
                    point_remove.append(connecting_points[i])
                    point_remove.append(connecting_points[i])

    return point_nodes, point_remove
示例#5
0
def detect_points2(slice, y_x, spacing, width=10):
    """ Alternative version of detect_points, which uses a reference point.
    Used for measurements on our phantom.
    """
    
    # create slice as double (makes a copy)
    slice = slice.astype(np.float64)
            
    # create new point set to store points
    pp = Pointset(2)
    
    th_minHU = 300
        
    refy, refx = y_x
    refy -= spacing # because we start with incrementing it
    
    while 1:
        # next
        refy += spacing
        if refy > slice.shape[0]:
            break
        
        # get patch
        y1, y2 = refy - spacing//4, refy + spacing//4
        x1, x2 = refx - width//2, refx + width//2
        if y1<0: y1=0
        patch = slice[y1:y2+1, x1:x2+1]
        
        # detect 
        Iy, Ix = np.where( (patch == patch.max()) & (patch > th_minHU) )
        try:
            Ix = Ix[0]
            Iy = Iy[0]
        except IndexError:            
            continue # if no points found...  
        y, x = y1+Iy, x1+Ix
        if y<=0 or y>=slice.shape[0]-1:
            continue
        
        # get subpixel and store
        patch2 = slice[y-1:y+2,x-1:x+2]
        dx,dy = subpixel.fitLQ2_5(patch2)
        pp.append( x+dx, y+dy ) 
        
        
    return pp
示例#6
0
def cluster_points(pp, c, pauseTime=0, showConvergeToo=True):
    """ cluster_points(pp, c, pauseTime=0) 
    
    Given a set of points, and the centreline position, this function 
    returns a set of points, which is a subset of pp. The returned pointset
    is empty on error.
    
    This algorithm uses the chopstick clustering implementation.
    
    The first step is the "stick" method. We take the closest point from the
    centre and attach one end of a stick to it. The stick has the length of
    the radius of the fitted circle. We rotate the stick counterclockwise
    untill it hits a point, or untill we rotate too far without finding a
    point, thus failing. When it fails, we try again with a slighly larger
    stick. This is to close gaps of up to almost 100 degrees. When we reach
    a point were we've already been, we stop. Afterwards, the set of points
    is sorted by angle.   
    
    In the second step we try to add points: we pick
    two subsequent points and check what other points are closer than "stick"
    to both these points, where "stick" is the distance between the points. We
    will break this stick in two and take the best point in the cluster, thus
    the name: chopstick. BUT ONLY if it is good enough! We draw two lines
    from the points under consideration to the centre. The angle that these
    two lines make is a reference for the allowed angle that the two lines
    may make that run from the two points to the new point. To be precise:
    ang > (180 - refang) - offset
    offset is a parameter to control the strictness. 
    
    The third part of this step consists of removing points. We will only
    remove points that are closer to the centre than both neighbours. We
    check each point, comparing it with its two neighbours on each side,
    applying the same criterion as  above. This will remove outliers that lie
    withing the stent, such as points found due to the contrast fluid...
    
    The latter two parts are repeated untill the set of points does not change.
    Each time the centre is recalculated by fitting a circle.
    
    """
    
    # Get better center
    if showConvergeToo:
        c, I = converge_to_centre(pp, c, pauseTime=pauseTime)
    else:
        c, I = converge_to_centre(pp, c)
    if not I:
        return Pointset(2)
    
    # Init list with vis objects (to be able to delete them)
    showObjects = []
    if pauseTime:
        fig = vv.gcf()
    
    # Short names
    pi = np.pi
    
    # Minimum and maximum angle that the stick is allowed to make with the line
    # to the circle-centre. Pretty intuitive...
    # it is a relative measure, we will multiply it with a ratio: 
    # radius/distance_current_point_to_radius. This allows ellipses to be
    # segmented, while remaining strict for circles.
    difAng1_p = 0.0*pi
    difAng2_p = 0.7*pi
    
    
    ## Step 1, stick method to find an initial set of points
    
    # Select start point (3th point returned by converge_to_centre)
    icurr = I[2]
    
    # Init list L, at the beginning only contains icurr
    L = [icurr]
    
    # Largest amount of iterations that makes sense. Probably the loop
    # exits sooner.
    maxIter = len(pp)
    
    # Enter loop
    for iter in range(maxIter):
        
        # We can think of it as fixing the stick at one end at the current
        # point and then rotating it in a direction such that a point is
        # found in the clockwise direction of the current point. We thus
        # need the angle between the next and current point to be not much
        # more than the angle between the current point and the circle
        # cenrre + 90 deg. But it must be larger than the angle between the
        # current point and the circle centre.
        
        # Calculate distances
        dists = pp.distance(pp[icurr])
        
        # Do the next bit using increasing stick length, untill success
        for stick in [c.r*1.0, c.r*1.5, c.r*2.0]:
            
            # Find subset of points that be "reached by the stick"
            Is, = np.where(dists<stick)
            
            # Calculate angle with circle centre
            refAng = c.angle2(pp[icurr])
            
            # Culcuate angles with points that are in reach of the stick
            angs = pp[Is].angle2(pp[icurr])
            
            # Select the points that are in the proper direction
            # There are TWO PARAMETERS HERE (one important) the second TH can
            # not be 0.5, because we allow an ellipse.
            # Use distance measure to make sure not to select the point itself.
            difAngs = subtract_angles(angs, refAng)
            difAng2 = difAng2_p # pp[icurr].distance(c) / c.r
            
            # Set current too really weid value
            icurr2, = np.where(Is==icurr)
            if len(icurr2):
                difAngs[icurr2] = 99999.0
            
            # Select. If a selection, we're good!
            II, = np.where( (difAngs > difAng1_p) + (difAngs < difAng2))
            if len(II):
                break
            
        else:
            # No success
            _objectClearer(showObjects)
            return Pointset(2)
        
        # Select the point with the smallest angle
        tmp = difAngs[II]
        inext, = np.where(tmp == tmp.min())
        
        # inext is index in subset. Make it apply to global set
        inext = Is[ II[ inext[0] ] ]
        inext = int(inext)
        
        # Show
        if pauseTime>0:
            # Delete
            _objectClearer(showObjects)
            # Show center
            ob1 = vv.plot(c, ls='', ms='x', mc='r', mw=10, axesAdjust=0)
            # Show all points
            ob2 = vv.plot(pp, ls='', ms='.', mc='g', mw=6, axesAdjust=0)
            # Show selected points L
            ob3 = vv.plot(pp[L], ls='', ms='.', mc='y', mw=10, axesAdjust=0)
            # Show next
            ob4 = vv.plot(pp[inext], ls='', ms='.', mc='r', mw=12, axesAdjust=0)
            # Show stick
            vec = ( pp[inext]-pp[icurr] ).normalize()
            tmp = Pointset(2)
            tmp.append(pp[icurr]); tmp.append(pp[icurr]+vec*stick)            
            ob5 = vv.plot(tmp, lw=2, lc='b')
            # Store objects and wait
            showObjects = [ob1,ob2,ob3,ob4,ob5]
            fig.DrawNow()
            time.sleep(pauseTime)
        
        
        # Check whether we completed a full round already 
        if inext in L:
            break
        else:
            L.append(inext)
        
        # Prepare for next round
        icurr = inext
    
    
    # Sort the list by the angles
    tmp = zip( pp[L].angle2(c), L )
    tmp.sort(key=lambda x:x[0])
    L = [i[1] for i in tmp]
    
    # Clear visualization
    _objectClearer(showObjects)
    
    
    ## Step 2 and 3, chopstick algorithm to find more points and discard outliers
    
    # Init
    L = [int(i) for i in L] # Make Python ints
    Lp = []
    round = 0
    
    # Iterate ...
    while Lp != L and round < 20:
        round += 1
        #print 'round', round
        
        # Clear list (but store previous)
        Lp = [i for i in L]
        L = []
        
        # We need at least three points
        if len(Lp)<3:
            _objectClearer(showObjects)
            print('oops: len(LP)<3' )
            return []
        
        # Recalculate circle
        c = fit_cirlce(pp[Lp], False)
        if c.r == 0.0:
            print('oops: c.r==0' )
            _objectClearer(showObjects)
            return []
        
        # Step2: ADD POINTS
        for iter in range(len(Lp)):
            
            # Current point
            icurr = Lp[iter]
            if iter < len(Lp)-1:
                inext = Lp[iter+1]
            else:
                inext = Lp[0]
            
            # Prepare, get p1 and p2
            p1 = pp[icurr]
            p2 = pp[inext]
            
            # Apply masks to points in pp
            M1, M2 = chopstick_criteria(c, p1, p2, pp)
            
            # Combine measures. I is now the subset (of p) of OK points
            I, = np.where(M1*M2)
            if not len(I):
                L.append(icurr)
                continue
            elif len(I)==1:
                ibetw = int(I)
            else:
                # Multiple candidates: find best match
                pptemp = pp[I]
                dists = p1.distance(pptemp) + p2.distance(pptemp)
                II, = np.where( dists==dists.min() )
                ibetw = int( I[II[0]] )
            
            # Add point            
            L.append(icurr)
            if not ibetw in L:
                L.append(ibetw)
            
            # Check
            assert ibetw not in [icurr, inext]
            
            # Draw
            if pauseTime>0:
                # Delete
                _objectClearer(showObjects)
                # Show center
                ob1 = vv.plot(c, ls='', ms='x', mc='r', mw=10, axesAdjust=0)
                # Show all points
                ob2 = vv.plot(pp, ls='', ms='.', mc='g', mw=6, axesAdjust=0)
                # Show selected points L
                ob3 = vv.plot(pp[L], ls='', ms='.', mc='y', mw=10, axesAdjust=0)
                # Show between and vectors
                ob4 = vv.plot(pp[ibetw], ls='', ms='.', mc='r', mw=12, axesAdjust=0)
                ob5 = vv.plot(pp[[icurr, ibetw, inext]], ls='-', lc='g', axesAdjust=0)
                ob6 = vv.plot(pp[[icurr, inext]], ls=':', lc='g', axesAdjust=0) 
                # Store objects and wait
                showObjects = [ob1,ob2,ob3,ob4,ob5,ob6]
                fig.DrawNow()
                time.sleep(pauseTime)
        
        # Lpp stores the set of points we have untill now, we will refill the
        # set L, maybe with less points
        Lpp = [int(i) for i in L]
        L = []
        
        # Step3: REMOVE POINTS 
        for iter in range(len(Lpp)):
            
            # Current point and neighbours
            ibetw = Lpp[iter]
            if iter<len(Lpp)-1:
                inext = Lpp[iter+1]
            else:
                inext = Lpp[0]
            if iter>0:
                icurr = Lpp[iter-1]
            else:
                icurr = Lpp[-1]
            
            # Test
#             print icurr, ibetw, inext
            assert ibetw not in [icurr, inext]
            
            # Prepare, get p1 and p2 and p3
            p1 = pp[icurr]
            p2 = pp[inext]
            p3 = pp[ibetw]
            
            # Apply masks to points in pp
            M1, M2 = chopstick_criteria(c, p1, p2, p3)
            M = M1*M2
            
            # Do we keep the point?           
            if M.sum():
                L.append(ibetw)
            
            # Draw
            if pauseTime>0 and not M.sum():
                # Delete
                _objectClearer(showObjects)
                # Show center
                ob1 = vv.plot(c, ls='', ms='x', mc='r', mw=10, axesAdjust=0)
                # Show all points
                ob2 = vv.plot(pp, ls='', ms='.', mc='g', mw=6, axesAdjust=0)
                # Show selected points L
                ob3 = vv.plot(pp[L], ls='', ms='.', mc='y', mw=10, axesAdjust=0)
                # Show between and vectors
                ob4 = vv.plot(pp[ibetw], ls='', ms='.', mc='r', mw=12, axesAdjust=0)
                ob5 = vv.plot(pp[[icurr, ibetw, inext]], ls='-', lc='r', axesAdjust=0)
                ob6 = vv.plot(pp[[icurr, inext]], ls='-', lc='g', axesAdjust=0)
                # Store objects and wait
                showObjects = [ob1,ob2,ob3,ob4,ob5,ob6]
                fig.DrawNow()
                time.sleep(pauseTime)
    
    
    # Done
    if round == 20:
        print('Warning: chopstick seemed not to converge.')
    _objectClearer(showObjects)
    #print 'cluster end', len(L)
    return pp[L]
示例#7
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
示例#8
0
def detect_points(slice, th_gc=2000, th_minHU=300, sigma=1.6):
    """ Detect points
    Detects points on a stent in the given slice. Slice 
    should be a numpy array.        
    - The Gaussian Curvature should be above a threshold 
      (needle detection) (th_gc)
    - An absolute (weak) threshold is used based on the 
      Houndsfield units (th_minHU)    
    - Streak artifacts are suppressed
    - sigma is the used scale at which the GC is calculated.    
    """
    
    # Make sure that the slice is a float
    if slice.dtype not in [np.float32, np.float64]:
        slice = slice.astype(np.float32)
    
    # Create slice to supress streak artifacts
    # Where streak artifacts are present, the image is inverted, anywhere else
    # its zero. By also calculating derivatives on this image and than adding
    # it, the threshold will never be reached where the streak artifacts are.
    sliceStreak = th_streHU - slice
    sliceStreak[sliceStreak<0] = 0
    
    # Create new point set to store points
    pp = Pointset(2)
    
    # Calculate Gaussian curvature    
    if True:
        Lxx = gaussfun.gfilter(slice, sigma, [0,2])
        Ltmp = gaussfun.gfilter(sliceStreak, sigma, [0,2])
        Lxx = Lxx+2*Ltmp
        Lxx[Lxx>0]=0;
        
        Lyy = gaussfun.gfilter(slice, sigma, [2,0])
        Ltmp = gaussfun.gfilter(sliceStreak, sigma, [2,0])
        Lyy = Lyy+2*Ltmp
        Lyy[Lyy>0]=0;
        
        Lgc = Lxx * Lyy
    
    # Make a smoothed version
    slice_smoothed = gaussfun.gfilter(slice, 0.5, 0)
    
    # Make a selection of candidate pixels
    Iy,Ix = np.where( (slice > th_minHU) & (Lgc > th_gc) )
    
    # Mask to detect clashes
    clashMask = np.zeros(slice.shape, dtype=np.bool)
    
    # Detect local maxima
    for x,y in zip(Ix,Iy):
        if x==0 or y==0 or x==slice.shape[1]-1 or y==slice.shape[0]-1:
            continue
        
        # Select patch        
        patch1 = slice[y-1:y+2,x-1:x+2]
        patch2 = slice_smoothed[y-1:y+2,x-1:x+2]
     
        if slice[y,x] == patch1.max():# and slice_smoothed[y,x] == patch2.max():
            # Found local max (allowing shared max)
            
            # Not if next to another found point
            if clashMask[y,x]:
                continue
            
            # Not a streak artifact
            if patch2.min() <= th_streHU:
                continue
            
            # Subpixel
            #dx,dy = subpixel.fitLQ2_5(patch1)
            
            # Store
            pp.append( x, y )
            clashMask[y-1:y+2,x-1:x+2] = 1
    
    # Express points in world coordinates and return
    if isinstance(slice, Aarray):
        ori = [i for i in reversed(slice.origin)]
        sam = [i for i in reversed(slice.sampling)]
        pp *= Point(sam)
        pp += Point(ori)
    return pp
示例#9
0
        # Fit circle and sample and show
        c = fit_cirlce(pp)
        cc = sample_circle(c, 32)
        self._cc.SetPoints(cc)
        
        # Draw
        self._cc.Draw()


## Tests
if __name__ == "__main__":
    import visvis as vv     
    tester1 = ChopstickCriteriaTester()
#     tester2 = FitCircleTester()

    if False:
        pp = Pointset(2)
        pp.append(1,1)
        pp.append(10,3)
        pp.append(8,8)
        pp.append(2,6)
        pp.append(1,2)
        
        fig = vv.figure(103)
        fig.Clear()
        a = vv.gca()
        a.daspectAuto = False
        fig.position = -799.00, 368.00,  544.00, 382.00
        vv.plot(pp, ls='', ms='.', mc='g')
        c2 = converge_to_centre(pp, Point(6,5), 5, pauseTime=0.3)