Ejemplo n.º 1
0
def additional_nodes(connecting_points):

    #Create pointset
    extra_nodes = Pointset(3)

    for i in range(len(connecting_points)):
        for j in range(len(connecting_points)):
            if 0 < connecting_points[i].Distance(connecting_points[j]) < 4:
                #Merge points
                extra_nodes.Append(
                    (connecting_points[i] + connecting_points[j]) / 2)

    for i in range(len(connecting_points)):

        #Create copy
        connecting_points_copy = connecting_points.Copy()

        #Remove all from copy to avoid distance = 0.
        connecting_points_copy.RemoveAll(connecting_points[i])

        if np.sum(
            (connecting_points[i].Distance(connecting_points_copy)) < 4) == 0:
            extra_nodes.Append(connecting_points[i])

    new_nodes = extra_nodes

    return new_nodes
Ejemplo n.º 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()
Ejemplo n.º 3
0
def check_for_possible_bifurcation(average_radius, center_point_3d_with_radius,\
    rotation_point ,found_bifurcation, global_direction):
    """
    This function tracks the radius of the stent. If the radius drops to less
    than 75%, the bifurcation might have been found. If so, two new starting points will be 
    calculated.
    """

    #Initially no new starting positions.
    new_starting_positions = []

    #Easier notation in rotation matrix
    gd = global_direction

    #To avoid wrong predictions on an early error in radius
    if len(average_radius) > 10:
        if 0.75*np.mean(average_radius) > center_point_3d_with_radius.r \
        and not found_bifurcation:

            if center_point_3d_with_radius.Distance(
                    rotation_point) > 0.25 * np.mean(average_radius):

                #found bifurcation
                found_bifurcation = True

                #calculate new starting points.
                new_starting_positions = Pointset(3)

                #vector of first branch
                fb_vector = np.mat(
                    [[center_point_3d_with_radius[2] - rotation_point[2]],
                     [center_point_3d_with_radius[1] - rotation_point[1]],
                     [center_point_3d_with_radius[0] - rotation_point[0]]])

                #Create rotation matrix to rotate vector
                rotation_matrix = np.mat(
                    [[2 * gd[0]**2 - 1, 2 * gd[0] * gd[1], 2 * gd[0] * gd[2]],
                     [2 * gd[1] * gd[2], 2 * gd[1]**2 - 1, 2 * gd[1] * gd[2]],
                     [2 * gd[2] * gd[0], 2 * gd[1] * gd[2], 2 * gd[2]**2 - 1]])

                #second branch
                sb = rotation_matrix * fb_vector

                sb_center_point = rotation_point + Point(sb[2], sb[1], sb[0])

                #Return new starting positions
                new_starting_positions.Append(center_point_3d_with_radius)
                new_starting_positions.Append(sb_center_point)

    #Add radius to list with radia
    if not center_point_3d_with_radius.r == []:
        average_radius.append(center_point_3d_with_radius.r)

    return average_radius, found_bifurcation, new_starting_positions
Ejemplo n.º 4
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()
Ejemplo n.º 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
Ejemplo n.º 6
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()
Ejemplo n.º 7
0
def convert_2d_point_to_3d_point(center_point, vec1, vec2, pointset_2d_points):
    """
    Given a pointset containing 2D points (y,x), a center point (z,y,x), and two vectors which
    describe the orientation of the slice inside the 3D volume, the algorithm 
    will convert the 2D points to 3D points.
    """

    if pointset_2d_points.__class__ == Point:
        temp = Pointset(2)
        temp.Append(pointset_2d_points)
        pointset_2d_points = temp

    #Pointset to store 3D points
    pointset_3d_points = Pointset(3)

    for i in range(len(pointset_2d_points)):

        #Shift from point 127.5,127.5 which is the rotation point
        y_shift = pointset_2d_points[i][1] - 127.5
        x_shift = pointset_2d_points[i][0] - 127.5

        center = Point(center_point[2], center_point[1], center_point[0])
        point_3d = center + y_shift * vec1 + x_shift * vec2
        point_3d = Point(point_3d[2], point_3d[1], point_3d[0])
        pointset_3d_points.Append(point_3d)

    return pointset_3d_points
Ejemplo n.º 8
0
def sample_circle(c, N=32):
    """ sample_circle(c, N=32)
    Sample a circle represented by point c (having attribute "r") using
    N datapoints. Returns a pointset.
    """
    
    # Get radius
    r = 1.0
    if hasattr(c, 'r'):
        r = c.r
    
    # Sample N points, but add one to close the loop
    d = 2*np.pi / N
    a = np.linspace(0,2*np.pi, N+1)
    
    # Prepare array
    pp = np.empty((len(a), 2), dtype=np.float32)
    
    # Apply polar coordinates
    pp[:,0] = np.cos(a) * r + c.x
    pp[:,1] = np.sin(a) * r + c.y
    
    # Return as a pointset
    return Pointset(pp)
Ejemplo n.º 9
0
def find_connecting_points(pointset_slice_i, pointset_slice_i_plus_1):
    """
    Given a set of points in slice i, the algorithm will calculate distances 
    between these points and the points in slice i+1. If this distance is less 
    than a certain distance, the point in slice i+1 is returned as connecting
    point. If there is no connecting point found, a virtual point is created.
    """

    #Maximum distance for which a point is seen as connecting
    max_distance = ssdf._stent_tracking_params.max_dist

    #Pointsets to store points
    connecting_points = Pointset(2)
    virtual_points = Pointset(2)

    #for each point in slice i
    for i in range(len(pointset_slice_i)):

        distances = pointset_slice_i[i, :] - pointset_slice_i_plus_1[:, :]

        #for all distances from this point
        for j in range(len(distances)):

            #if distance is smaller or equal to the max distance
            if abs(distances[j, 0]) + abs(distances[j, 1]) <= max_distance:

                #make the point a connecting point
                connecting_points.Append(pointset_slice_i_plus_1[j])

        #if the point from slice i has no connecting point
        if len(
                np.where(
                    abs(distances[:, 0]) +
                    abs(distances[:, 1]) <= max_distance)[0]) == 0:

            #change the point from slice i into a virtual point
            virtual_points.Append(pointset_slice_i[i])

    return connecting_points, virtual_points
Ejemplo n.º 10
0
def select_stent(volnr, params=None):
    """
    This functions calls the stent extration function. It contains seed points
    for each dataset
    """

    if params is None:
        params = getDefaultParams()
    ssdf._stent_tracking_params = params

    if volnr == 1:
        #vol 1
        vol, sampling, origin = load_volume(1)
        seed_points = Pointset(3)
        seed_points.Append(60, 110, 133)
        seed_points.Append(100, 75, 150)
        seed_points.Append(160, 70, 148)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)
    elif volnr == 2:
        #vol 2
        vol, sampling, origin = load_volume(2)
        seed_points = Pointset(3)
        seed_points.Append(60, 175, 155)
        seed_points.Append(100, 150, 170)
        seed_points.Append(165, 140, 167)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)
    elif volnr == 3:
        #vol 3
        vol, sampling, origin = load_volume(3)
        seed_points = Pointset(3)
        seed_points.Append(47, 160, 140)
        seed_points.Append(80, 145, 130)
        seed_points.Append(130, 130, 128)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)
    elif volnr == 4:
        #vol 4
        vol, sampling, origin = load_volume(4)
        seed_points = Pointset(3)
        seed_points.Append(40, 160, 160)
        seed_points.Append(140, 145, 135)
        seed_points.Append(150, 150, 150)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)
    elif volnr == 5:
        #vol 5
        vol, sampling, origin = load_volume(5)
        seed_points = Pointset(3)
        seed_points.Append(34, 150, 170)
        seed_points.Append(60, 135, 180)
        seed_points.Append(130, 140, 180)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)
    elif volnr == 6:
        #vol 6
        vol, sampling, origin = load_volume(6)
        seed_points = Pointset(3)
        seed_points.Append(40, 170, 175)
        seed_points.Append(70, 160, 180)
        seed_points.Append(140, 142, 168)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)
    elif volnr == 7:
        #vol 7
        vol, sampling, origin = load_volume(7)
        seed_points = Pointset(3)
        seed_points.Append(40, 180, 160)
        seed_points.Append(110, 160, 160)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)
    elif volnr == 8:
        #vol 8
        vol, sampling, origin = load_volume(8)
        seed_points = Pointset(3)
        seed_points.Append(60, 130, 190)
        seed_points.Append(80, 110, 180)
        seed_points.Append(120, 112, 140)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)

    elif volnr == 18:
        #vol 18
        vol, sampling, origin = load_volume(18)
        seed_points = Pointset(3)
        seed_points.Append(70, 170, 140)
        seed_points.Append(135, 150, 160)
        node_points_stent, center_points_stent, stent_points_stent = stent_detection(
            vol, sampling, origin, seed_points)
    else:
        raise ValueError('Invalid volnr')

    plot = True
    if plot:
        points = Pointset(3)
        for i in range(len(node_points_stent)):
            points.Append(node_points_stent[i][2], node_points_stent[i][1],
                          node_points_stent[i][0])

        points_2 = Pointset(3)
        for i in range(len(stent_points_stent)):
            points_2.Append(stent_points_stent[i][2], stent_points_stent[i][1],
                            stent_points_stent[i][0])

        vv.closeAll()
        vv.volshow(vol)
        vv.plot(points_2, ls='', ms='.', mc='g', mw=4, alpha=0.5)
        vv.plot(points, ls='', ms='.', mc='b', mw=4, alpha=0.9)

    graph = from_nodes_to_graph(node_points_stent)

    return graph
Ejemplo n.º 11
0
def stent_detection(vol, sampling, origin, seed_points):
    """
    This is the function that will be called in order to extract the stent
    from the CT data. 
    """

    #Point set where the final points will be stored. In node, the 4th number
    #indicates the ring number, the 5th indicates the direction where it is found
    node_points_stent = Pointset(5)
    center_points_stent = Pointset(3)
    stent_points_stent = Pointset(3)

    #Initially, the bifurcation is not found
    found_bifurcation = False
    average_radius = []

    #start with ring 1
    ring = 1

    #Weighting factor alpha
    alpha = ssdf._stent_tracking_params.weighting_factor
    distance = ssdf._stent_tracking_params.distance

    #From seed point to seed point except for the last seed point, where the
    #bifurcation needs to be found.
    for i in range(len(seed_points) - 2):

        round = 0

        #Don't look for the bifurcation when not connecting points in the last
        #part of the stent
        look_for_bifurcation = False

        #Get initial center point and direction using the seed points
        center_point, global_direction = initial_center_point(
            vol, seed_points[i], seed_points[i + 1], sampling, origin, alpha)

        #While the center point has not passed the seed point
        while center_point[0] < seed_points[i + 1][0] and round < 10:

            #Find stent, node and center points for a certain stent ring
            node_points_ring, stent_points_ring, center_points_ring, \
            jump_location, jump_direction, found_bifurcation, new_starting_positions, \
            ring = searching_for_ring(vol, sampling, center_point, global_direction,\
            look_for_bifurcation, average_radius, alpha, ring)

            #Set new starting center point inside the new ring
            center_point = jump_location + distance * Point(
                jump_direction[2], jump_direction[1], jump_direction[0])
            global_direction = jump_direction

            #Add points to point sets
            node_points_stent.Extend(node_points_ring)
            center_points_stent.Extend(center_points_ring)
            stent_points_stent.Extend(stent_points_ring)

            round = round + 1

    #For the last part of the stent where the bifurcation needs to be found
    for i in range(len(seed_points) - 2, len(seed_points) - 1):

        #Reset round to zero
        round = 0

        look_for_bifurcation = True

        center_point, global_direction = initial_center_point(vol, seed_points[i],\
        seed_points[i+1], sampling, origin, alpha)

        #While the bifurcation is not found
        while found_bifurcation == False and round < 10:

            node_points_ring, stent_points_ring, center_points_ring, \
            jump_location, jump_direction, found_bifurcation, new_starting_positions, \
            ring = searching_for_ring(vol, sampling, center_point, global_direction, \
            look_for_bifurcation, average_radius, alpha, ring)

            center_point = jump_location + distance * Point(
                jump_direction[2], jump_direction[1], jump_direction[0])
            global_direction = jump_direction

            #Add points to point sets
            node_points_stent.Extend(node_points_ring)
            center_points_stent.Extend(center_points_ring)
            stent_points_stent.Extend(stent_points_ring)

            round = round + 1

    #Store new starting positions in another poitset, because algorithm will
    #return [] as new_starting_positions.
    starting_positions = Pointset(3)

    #For the case where there is no bifurcation present
    try:
        starting_positions.Append(
            new_starting_positions[0]
        )  # + distance * Point(jump_direction[2],jump_direction[1],jump_direction[0]))
        starting_positions.Append(
            new_starting_positions[1]
        )  # + distance * Point(jump_direction[2],jump_direction[1],jump_direction[0]))
    except IndexError:
        []

    alpha = ssdf._stent_tracking_params.weighting_factor_bif

    #Now points after the bifurcation will be found
    for i in range(len(starting_positions)):

        center_point = starting_positions[i]

        look_for_bifurcation = False

        round = 0

        while round < 4:

            node_points_ring, stent_points_ring, center_points_ring, \
            jump_location, jump_direction, found_bifurcation, new_starting_positions, \
            ring = searching_for_ring(vol, sampling, center_point, global_direction, \
            look_for_bifurcation, average_radius, alpha, ring)

            center_point = jump_location + distance * Point(
                jump_direction[2], jump_direction[1], jump_direction[0])
            global_direction = jump_direction

            if 255 < center_point[0]:
                break

            #Add points to point sets
            node_points_stent.Extend(node_points_ring)
            center_points_stent.Extend(center_points_ring)
            stent_points_stent.Extend(stent_points_ring)

            round = round + 1

    return node_points_stent, center_points_stent, stent_points_stent
Ejemplo n.º 12
0
def searching_for_ring(vol, sampling, center_point, global_direction, \
    look_for_bifurcation, average_radius, alpha, ring):
    """
    Given a center point and a direction, the algorithm will start by searching
    for points in a certain stent ring using the global direction. By connecting 
    points it will come to a set of nodes. After a certain amount of nodes are 
    found, the algorithm will flip the direction and will search for points in 
    the other direction until the stent ring is defined. The radius is used when
    searching for the bifurcation.        
    """

    #Initially, the bifurcation is not found
    found_bifurcation = False

    #First the initial center point and direction has to be stored in order to
    #flip the direction later
    stored_center_point = center_point
    flipped_global_direction = -1 * global_direction

    #Create pointsets to store points
    node_points_ring = Pointset(5)  #(z,y,x,ring,direction)
    stent_points_ring = Pointset(3)
    center_points_ring = Pointset(3)

    #Expected amount of nodes and returns initial filtered points
    expected_amount_of_nodes, initial_points_in_slice = amount_of_nodes(vol, sampling, \
    center_point, global_direction, look_for_bifurcation)

    #set direction: 1 for along the direction of the stent, -1 for the opposite \
    #direction
    direction = 1

    #Find and connect points
    center_points, stent_points, node_points, global_direction, found_bifurcation, new_starting_positions, \
    ring = connecting_stent_points(vol, sampling, center_point, global_direction, look_for_bifurcation, \
    average_radius, direction, expected_amount_of_nodes, initial_points_in_slice, found_bifurcation, alpha, ring)

    #Store starting positions, because the direction -1 will remove otherwise.
    if found_bifurcation:
        store_starting_positions = new_starting_positions

    #Add found points to pointsets
    node_points_ring.Extend(node_points)
    stent_points_ring.Extend(stent_points)
    center_points_ring.Extend(center_points)

    #Store last center point to use as 'jumping' site
    if len(center_points_ring):
        jump_location = center_points_ring[len(center_points_ring) - 1]
    else:
        jump_location = stored_center_point
    jump_direction = global_direction

    #Flip direction
    direction = -1

    #Find and connect points for other direction
    center_points, stent_points, node_points, global_direction, found_bifurcation, new_starting_positions, \
    ring = connecting_stent_points(vol, sampling, stored_center_point, flipped_global_direction, \
    look_for_bifurcation, average_radius, direction, expected_amount_of_nodes, \
    initial_points_in_slice, found_bifurcation, alpha, ring)

    if found_bifurcation:
        new_starting_positions = store_starting_positions

    #Add found points to pointsets
    node_points_ring.Extend(node_points)
    stent_points_ring.Extend(stent_points)
    center_points_ring.Extend(center_points)

    ring = ring + 1

    return node_points_ring, stent_points_ring, center_points_ring, \
    jump_location, jump_direction, found_bifurcation, new_starting_positions, ring
Ejemplo n.º 13
0
def connecting_stent_points(vol, sampling, center_point, global_direction, look_for_bifurcation, \
    average_radius, direction, expected_amount_of_nodes, points_in_slice, found_bifurcation, alpha, ring):
    """
    This algorithm uses the earlier stated functions in order to connect points
    and define nodes. 
    """

    #Nodes that are found for the current direction
    node_points_direction = Pointset(3)

    #Other pointsets to store points
    center_points = Pointset(3)
    stent_points = Pointset(3)
    node_points = Pointset(5)

    #Set round to 0 for the case that the amount of nodes criterion is not met.
    round = 0

    #Initial
    new_starting_positions = []

    #connecting points
    while len(node_points_direction) < expected_amount_of_nodes and round < 12:

        #Get slice
        slice, center_point, global_direction, rotation_point, vec1, vec2, \
        center_point_3d_with_radius = centerline_tracking.get_slice(vol, sampling, \
        center_point, global_direction, look_for_bifurcation, alpha)

        #If looking for the bifurcation, check radius
        if look_for_bifurcation and direction == 1:
            if not found_bifurcation:
                average_radius, found_bifurcation, new_starting_positions \
                = check_for_possible_bifurcation(average_radius, center_point_3d_with_radius, \
                rotation_point, found_bifurcation, global_direction)
        else:
            new_starting_positions = []

        #Find points
        points_in_next_slice = stentPoints2d.detect_points(slice)

        #Find connecting points. Change not connecting points into virtual points
        connecting_points, virtual_points = find_connecting_points(points_in_slice, \
        points_in_next_slice)

        #Check if virtual points should be converted into connecting points
        connecting_points, temp_slice = check_virtual_points(virtual_points, \
        connecting_points, center_point, vol, sampling,  global_direction, alpha)

        #Check for nodes
        point_nodes_2d, point_remove = check_for_nodes(connecting_points,
                                                       temp_slice)

        #If nodes are found, these points should be deleted from the connecting points list
        connecting_points = delete_nodes_from_list(connecting_points,
                                                   point_remove)

        #Convert 2d points into 3d points
        connecting_points_3d = convert_2d_point_to_3d_point(center_point, vec1,\
        vec2, connecting_points)
        point_nodes_3d = convert_2d_point_to_3d_point(center_point, vec1, vec2,\
        point_nodes_2d)

        #Add 3d points to their list
        center_points.Append(rotation_point)
        stent_points.Extend(connecting_points_3d)
        node_points_direction.Extend(point_nodes_3d)
        for i in range(len(point_nodes_3d)):
            node_points.Append(
                Point(point_nodes_3d[i][0], point_nodes_3d[i][1],
                      point_nodes_3d[i][2], ring, direction))

        #Set connecting points as new base points
        points_in_slice = connecting_points

        #Next round
        round = round + 1

        #If there are three nodes found, do first one more run.
        if len(node_points_direction) > 2:
            diff = 10 - round
            if diff > 0:
                round = round + diff

        if round == 12:
            new_nodes = additional_nodes(connecting_points_3d)
            for i in range(len(new_nodes)):
                node_points.Append(
                    Point(new_nodes[i][0], new_nodes[i][1], new_nodes[i][2],
                          ring, direction))

    return center_points, stent_points, node_points, global_direction, found_bifurcation, new_starting_positions, ring
Ejemplo n.º 14
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
Ejemplo n.º 15
0
def from_nodes_to_graph(node_points_stent):
    """
    Given a set of nodes it creates a graph. The node set contains a ring number 
    (4th dimension) and direction (5th dimension)
    """

    graph = Graph()

    #Min and maximum distance when connecting nodes
    min = 10
    max = 18

    for i in range(len(node_points_stent)):

        #Take point
        point = Point(node_points_stent[i][2], node_points_stent[i][1],
                      node_points_stent[i][0])

        #Add node to graph
        graph.AppendNode(point)

        #Pointset to store possible matches
        possible_match = Pointset(3)

        for j in range(len(node_points_stent)):
            if node_points_stent[j][3] == node_points_stent[i][
                    3] and node_points_stent[j][4] != node_points_stent[i][4]:
                if min < point.Distance(
                        Point(node_points_stent[j][2], node_points_stent[j][1],
                              node_points_stent[j][0])) < max:
                    possible_match.Append(
                        Point(node_points_stent[j][2], node_points_stent[j][1],
                              node_points_stent[j][0]))

        if len(possible_match) == 0:
            continue
        elif len(possible_match) == 1:
            graph.AppendNode(possible_match[0])
            graph.CreateEdge(graph[np.size(graph) - 2],
                             graph[np.size(graph) - 1])
        elif len(possible_match) == 2:
            graph.AppendNode(possible_match[0])
            graph.AppendNode(possible_match[1])
            graph.CreateEdge(graph[np.size(graph) - 1],
                             graph[np.size(graph) - 3])
            graph.CreateEdge(graph[np.size(graph) - 2],
                             graph[np.size(graph) - 3])
        else:
            while True:
                sorted = False
                for j in range(len(possible_match) - 1):
                    if point.Distance(possible_match[j]) > point.Distance(
                            possible_match[j + 1]):
                        possible_match[j], possible_match[
                            j + 1] = possible_match[j + 1], possible_match[j]
                        sorted = True
                if not sorted:
                    break
            graph.AppendNode(possible_match[0])
            graph.AppendNode(possible_match[1])
            graph.CreateEdge(graph[np.size(graph) - 1],
                             graph[np.size(graph) - 3])
            graph.CreateEdge(graph[np.size(graph) - 2],
                             graph[np.size(graph) - 3])

    return graph
Ejemplo n.º 16
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
Ejemplo n.º 17
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)
Ejemplo n.º 18
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
Ejemplo n.º 19
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]