Exemple #1
0
def renormalize_pred_keypoints(timepoint,
                               pred_keypoints,
                               downscale=2,
                               image_size=(960, 512)):
    downscale = downscale
    center_tck, width_tck = timepoint.annotations['pose']
    image_shape = (image_size[0] / downscale, image_size[1] / downscale)
    length = spline_geometry.arc_length(center_tck)
    sample_dist = interpolate.spline_interpolate(width_tck, length).max() + 20
    width = int(round(sample_dist * 2))
    new_keypoints = {}
    for kp, points in pred_keypoints.items():
        x, y = points
        x_percent = x / image_shape[0]
        new_x = x_percent * length
        if kp is 'vulva':
            vulvax = int(new_x)
            print("vulvax: ", vulvax)

            print("x_percent: ", x_percent)
            avg_widths = interpolate.spline_interpolate(width_tck, length)
            if vulvax == len(avg_widths):
                vulvax = vulvax - 1
            vulvay = avg_widths[vulvax]
            if y < 0:
                new_y = -vulvay
            else:
                new_y = vulvay
        else:
            new_y = 0

        new_keypoints[kp] = (new_x, new_y)

    return new_keypoints
Exemple #2
0
def normalize_pred_keypoints(timepoint,
                             pred_keypoints,
                             downscale=2,
                             image_size=(960, 512)):
    downscale = downscale
    center_tck, width_tck = timepoint.annotations['pose']
    new_width_tck = (AVG_WIDTHS_TCK[0], AVG_WIDTHS_TCK[1] / downscale,
                     AVG_WIDTHS_TCK[2])
    image_shape = (image_size[0] / downscale, image_size[1] / downscale)
    length = spline_geometry.arc_length(center_tck)
    sample_dist = interpolate.spline_interpolate(width_tck, length).max() + 20
    if pred_keypoints is None:
        print("Keypoints do not exist with id: ", pred_id)
        return None
    new_keypoints = {}
    for kp, points in pred_keypoints.items():
        x, y = points
        x_percent = x / length
        new_x = x_percent * image_shape[0]
        new_y = int(image_shape[1] / 2)
        if kp == 'vulva':
            vulvax = int(new_x)
            avg_widths = interpolate.spline_interpolate(
                new_width_tck, image_shape[0])
            if vulvax == len(avg_widths):
                vulvax = vulvax - 1
            vulvay = avg_widths[vulvax]
            if y < 0:
                new_y = (image_shape[1] / 2) - vulvay
            else:
                new_y = (image_shape[1] / 2) + vulvay

        new_keypoints[kp] = (new_x, new_y)

    return new_keypoints
Exemple #3
0
    def get_keypoint_coords(self, i, image_shape):
        annotations = self.timepoint_list[i].annotations
        center_tck, width_tck = annotations['pose']
        keypoints = annotations['keypoints']

        #step 1: get the x,y positions in the new image shape
        length = spline_geometry.arc_length(center_tck)
        sample_dist = interpolate.spline_interpolate(width_tck, length).max()+20
        width = int(round(sample_dist*2))

        xs = numpy.array([keypoints[k][0] for k in ('anterior bulb', 'posterior bulb', 'vulva', 'tail')])
        x_percent = xs/length
        new_xs = x_percent*image_shape[0]

        #get y coordinates
        #put all keypoints except vulva at the midline
        ys = [int(image_shape[1]/2)]*len(new_xs)
        vulvax = int(new_xs[2])
        avg_widths = interpolate.spline_interpolate(self.AVG_WIDTHS_TCK, image_shape[0])
        vulvay = avg_widths[vulvax]
        #widths are wrt the midline, so put vulva on correct side
        if keypoints['vulva'][1] > 0:
            ys[2] = (image_shape[1]/2) + vulvay
        else:
            ys[2] = (image_shape[1]/2) - vulvay

        return new_xs, ys
def extrapolate_head(tck, width_tck, smoothing=None):
    '''Since the width/length splines don't get to the end of the worm,
    try to extrapolate the widths and such to the end of the worm mask

    NOTE: Not really used in the spline-fitting pipeline
    '''
    #get first and last points from the width_tck
    width_ends = interpolate.spline_interpolate(width_tck, 2)
    print(width_ends)
    #calculate new x's and y's that go to the end of the mask
    tmax = tck[0][-1]
    print("tmax: " + str(tmax))
    xys = interpolate.spline_evaluate(
        tck, np.linspace(-width_ends[0], tmax + width_ends[1], 600))
    #print(xys.shape)

    #interpolate the widths so that we can add on the end widths
    #NOTE: end widths will be zero since they are at the end of the mask
    widths = interpolate.spline_interpolate(width_tck, 600)
    new_widths = np.concatenate([[0], widths, [0]])
    #need to generate new x's to use to re-make the width splines with new_widths
    #new endpoint xs need to be reflective of where they are on the centerline
    new_xs = np.concatenate([[-widths[0] / tmax],
                             np.linspace(0, 1, 600), [1 + widths[-1] / tmax]])

    #re-make the splines
    if smoothing is None:
        smoothing = 0.2 * len(new_widths)

    new_tck = interpolate.fit_spline(xys, smoothing=smoothing)

    new_width_tck = interpolate.fit_nonparametric_spline(new_xs,
                                                         new_widths,
                                                         smoothing=smoothing)
    return new_tck, new_width_tck
Exemple #5
0
def training_fit(standard_mask,
                 my_metadata_file,
                 my_PCA,
                 width_PCA,
                 pcs_number=30,
                 n_points=100,
                 reverse_flag=False):
    '''
	Given a known spine of the worm, initialize a vector of parameters to input into our model.
	
	Returns the vector x0 which contains:
	pc_components
	scale_factor
	center_of_mass (normalized)
	long_axis_angle
	'''
    # Initialize x0 and load stuff.
    x0 = np.zeros(pcs_number + 5 + 4)
    my_metadata = pickle.load(open(my_metadata_file, 'rb'))
    spine_tck = my_metadata['spine_tck']
    width_tck = my_metadata['width_tck']
    my_spine = zplib_interpolate.spline_interpolate(spine_tck, n_points)
    my_width = zplib_interpolate.spline_interpolate(width_tck, n_points)

    # Compute some parameters from the spine directly.
    center_of_mass = np.mean(my_spine, axis=0)
    center_of_mass = np.divide(center_of_mass, standard_mask.shape)
    long_axis_angle = my_spine[-1, :] - my_spine[0, :]
    long_axis_angle = np.arctan2(long_axis_angle[1], long_axis_angle[0])
    spine_vectors = my_spine[1:] - my_spine[:-1]
    scale_factor = np.mean(
        np.array(
            [np.linalg.norm(spine_vector) for spine_vector in spine_vectors]))

    # Fill in some simple parameters.
    x0[-3:-1] = center_of_mass
    x0[-1] = long_axis_angle
    if reverse_flag:
        x0[-1] += np.pi
    x0[-4] = scale_factor

    # Project spine on to PCs.
    my_spine = normalize_worm(my_spine, final_angle=0, final_scale=1)
    linear_spine = np.ndarray.flatten(my_spine)
    my_components = deviation_projection(linear_spine, my_PCA)
    my_width_components = deviation_projection(my_width, width_PCA)

    # Fill in PCs and scale_factor, return x0.
    for i in range(0, pcs_number):
        x0[i] = my_components[i]
    for i in range(0, 5):
        x0[pcs_number + i] = my_width_components[i]
    return x0
def training_fit(standard_mask, my_metadata_file, my_PCA, width_PCA, pcs_number = 30, n_points = 100, reverse_flag = False):
	'''
	Given a known spine of the worm, initialize a vector of parameters to input into our model.
	
	Returns the vector x0 which contains:
	pc_components
	scale_factor
	center_of_mass (normalized)
	long_axis_angle
	'''	
	# Initialize x0 and load stuff.
	x0 = np.zeros(pcs_number + 5 + 4)
	my_metadata = pickle.load(open(my_metadata_file, 'rb'))
	spine_tck = my_metadata['spine_tck']
	width_tck = my_metadata['width_tck']
	my_spine = zplib_interpolate.spline_interpolate(spine_tck, n_points)
	my_width = zplib_interpolate.spline_interpolate(width_tck, n_points)

	# Compute some parameters from the spine directly.
	center_of_mass = np.mean(my_spine, axis = 0)
	center_of_mass = np.divide(center_of_mass, standard_mask.shape)
	long_axis_angle = my_spine[-1, :] - my_spine[0, :]
	long_axis_angle = np.arctan2(long_axis_angle[1], long_axis_angle[0])
	spine_vectors = my_spine[1:] - my_spine[:-1]
	scale_factor = np.mean(np.array([np.linalg.norm(spine_vector) for spine_vector in spine_vectors]))

	# Fill in some simple parameters.
	x0[-3:-1] = center_of_mass
	x0[-1] = long_axis_angle 
	if reverse_flag:
		x0[-1] += np.pi
	x0[-4] = scale_factor

	# Project spine on to PCs.
	my_spine = normalize_worm(my_spine, final_angle = 0, final_scale = 1)
	linear_spine = np.ndarray.flatten(my_spine)
	my_components = deviation_projection(linear_spine, my_PCA)
	my_width_components = deviation_projection(my_width, width_PCA)
	
	# Fill in PCs and scale_factor, return x0.
	for i in range(0, pcs_number):
		x0[i] = my_components[i]		
	for i in range(0, 5):
		x0[pcs_number + i] = my_width_components[i]
	return x0
def train_PCs(training_data_dir, age_range = None, n_points = 100):
	'''
	Takes worm masks and metadata from subdirectories in training_data_dir and generates principal components from the set of 99 angles tangent to the worms' outlines.
	'''	
	training_subdirs = [os.path.join(training_data_dir, subdir) for subdir in os.listdir(training_data_dir) if os.path.isdir(os.path.join(training_data_dir, subdir))]
	endings = ['bf.png', 'mask.png', 'metadata.pickle']	
	
	all_shapes = []
	scale_factors = []
	width_list = []
	for subdir in training_subdirs:
		total_files = os.listdir(subdir)
		data_points = [' '.join(a_file.split('.')[0].split(' ')[0:-1]) for a_file in total_files if a_file.split('.')[-1] == 'pickle']
		for a_point in data_points:
			my_metadata = pickle.load(open(subdir + os.path.sep + a_point + ' ' + endings[2], 'rb'))
			if age_range == None or age_range[0] <= my_metadata['age_days'] <= age_range[1]:
				spine_tck = my_metadata['spine_tck']
				width_tck = my_metadata['width_tck']
				my_spine = zplib_interpolate.spline_interpolate(spine_tck, n_points)
				widths = zplib_interpolate.spline_interpolate(width_tck, n_points)
				(my_spine, scale_factor) = normalize_worm(my_spine, final_scale = 1, final_angle = 0, return_scale_factor = True)
				scale_factors.append(scale_factor)
				width_list.append(widths)
				all_shapes.append(np.ndarray.flatten(my_spine))
				
	class a_PCA():
		def __init__(self, mean, pcs, norm_pcs, variances, positions, norm_positions, scale_factors):
			self.mean = mean
			self.pcs = pcs
			self.norm_pcs = norm_pcs
			self.variances = variances
			self.positions = positions
			self.norm_positions = norm_positions
			self.components_ = norm_pcs
			self.mean_scale = np.mean(scale_factors)
			
	mean, pcs, norm_pcs, variances, positions, norm_positions = zplib_pca.pca(all_shapes)			
	width_mean, width_pcs, width_norm_pcs, width_variances, width_positions, width_norm_positions = zplib_pca.pca(width_list)			
	my_PCA = a_PCA(mean, pcs, norm_pcs, variances, positions, norm_positions, scale_factors)
	width_PCA = a_PCA(width_mean, width_pcs, width_norm_pcs, width_variances, width_positions, width_norm_positions, scale_factors)
	print('Finished training spine points PCs.')
	return (my_PCA, width_PCA)
Exemple #8
0
 def _smooth_width_from_pca(self, width_tck):
     '''Given a width_tck, use the pca to smooth out the edges
     '''
     #Go from PCA -> real widths and back (real widths -> PCA)
     #Widths -> PCA
     mean, pcs, norm_pcs, variances, total_variance,positions, norm_positions = self.pca_stuff
     widths = interpolate.spline_interpolate(width_tck, 100) 
     projection = pca.pca_decompose(widths, pcs, mean)[:3]
     #PCA -> Widths
     smoothed_widths = pca.pca_reconstruct(projection, pcs[:3], mean)
     #make new width spline
     smoothed_width_tck = interpolate.fit_nonparametric_spline(np.linspace(0,1, len(smoothed_widths)), smoothed_widths)
     return smoothed_width_tck
Exemple #9
0
def get_cost_image(image, optocoupler, image_gamma, center_tck, width_tck,
                   downscale, gradient_sigma, sigmoid_midpoint,
                   sigmoid_growth_rate, edge_weight):
    """Trace the edges of a worm and return a new center_tck and width_tck.

    Parameters:
        image: ndarray of the brightfield image
        optocoupler: optocoupler magnification (to correctly calculate the image
            vignette)
        center_tck: spline defining the pose of the worm.
        width_tck: spline defining the distance from centerline to worm edges.
        image_gamma: gamma value for intensity transform to highlight worm edges
        downscale: factor by which to downsample the image
        gradient_sigma: sigma for gaussian gradient to find worm edges
        sigmoid_midpoint: midpoint of edge_highlighting sigmoid function for
            gradient values, expressed as a percentile of the gradient value
            over the whole image.
        sigmoid_growth_rate: steepness of the sigmoid function.
        edge_weight: how much to weight image edge strength vs. distance from
            the average widths in the cost function.

    Returns: image defining the cost function for edge tracing
    """
    # normalize, warp, and downsample image
    image = process_images.pin_image_mode(image, optocoupler=optocoupler)
    image = colorize.scale(image,
                           min=600,
                           max=26000,
                           gamma=image_gamma,
                           output_max=1)
    warped = worm_spline.to_worm_frame(image,
                                       center_tck,
                                       width_tck,
                                       width_margin=40)
    warped = pyramid.pyr_down(warped, downscale=downscale)

    # calculate the edge costs
    gradient = ndimage.gaussian_gradient_magnitude(warped, gradient_sigma)
    gradient = sigmoid(gradient, numpy.percentile(gradient, sigmoid_midpoint),
                       sigmoid_growth_rate)
    gradient = gradient.max() - abs(gradient)

    # penalize finding edges away from the width along the worm
    widths = (interpolate.spline_interpolate(width_tck,
                                             warped.shape[0])) / downscale
    centerline_index = (warped.shape[1] - 1) / 2
    distance_from_centerline = abs(
        numpy.arange(0, warped.shape[1]) - centerline_index)
    distance_from_average = abs(
        numpy.subtract.outer(widths, distance_from_centerline))
    return edge_weight * gradient + distance_from_average
def get_avg_widths(metadata_list):
    """Get the average widths of worms 3-7 days old to 
    to make a unit worm from. 
    """
    #average the widths at 100 points along the spline
    widths=[]
    for m in metadata_list.values():
        width_tck=m['width_tck']
        widths.append(interpolate.spline_interpolate(width_tck, 100))

    widths=np.array(widths)
    widths_avg=np.mean(widths, axis=0)

    return widths_avg
Exemple #11
0
def evaluate_widths(true_width_tck, traceback, shape):
    """with the found widths evaluate how good they are
    compared to the true widths via RMSD
    """
    widths = interpolate.spline_interpolate(true_width_tck, len(traceback))
    #since we are looking at the top part of the image, we need to get the widths
    #to reflect that
    true_widths = widths / 2
    #true_widths = shape[1]-widths-1
    #true_width_image = visualize_widths(widths, width_image.shape)
    x, y = np.transpose(traceback)
    diff = np.sqrt(np.sum((true_widths - y)**2) * (1 / len(true_widths)))
    #diff = np.linalg.norm(true_widths-widths, ord=None)
    return diff
Exemple #12
0
def make_warp(metadata, image_file, warp_file):
    image = freeimage.read(image_file)
    spine_tck = metadata['spine_tck']
    width_tck = metadata['width_tck']
    widths = interpolate.spline_interpolate(width_tck, 100)
    warp_width = 2 * widths.max(
    )  # the worm widths above are from center to edge, so twice that is edge-to-edge
    warped = resample.sample_image_along_spline(image, spine_tck, warp_width)
    mask = resample.make_mask_for_sampled_spline(warped.shape[0],
                                                 warped.shape[1], width_tck)
    warped[~mask] = 0
    freeimage.write(
        warped, warp_file
    )  # freeimage convention: image.shape = (W, H). So take transpose.
Exemple #13
0
def find_widths(image,
                true_width_tck,
                ggm_sigma=3,
                sig_per=75,
                sig_growth_rate=2,
                alpha=1,
                mcp_alpha=1):
    """Find the top and bottom widths from the image
    """

    top_image = image[:, :int(image.shape[1] / 2)]
    top_image_down, top_traceback, top_width_image, top_new_costs, top_y_grad, top_sig = width_finding(
        top_image,
        ggm_sigma=ggm_sigma,
        sig_per=sig_per,
        sig_growth_rate=sig_growth_rate,
        alpha=alpha,
        mcp_alpha=mcp_alpha)
    widths = interpolate.spline_interpolate(true_width_tck,
                                            top_image_down.shape[0])
    true_widths = widths / 2
    top_true_widths = visualize_widths(true_widths, top_image_down.shape)

    bottom_image = np.flip(image[:, int(image.shape[1] / 2):], axis=1)
    bottom_image_down, bottom_traceback, bottom_width_image, bottom_new_costs, bottom_y_grad, bottom_sig = width_finding(
        bottom_image,
        ggm_sigma=ggm_sigma,
        sig_per=sig_per,
        sig_growth_rate=sig_growth_rate,
        alpha=alpha)

    #put them together!
    full_image_down = np.hstack(
        (top_image_down, np.flip(bottom_image_down, axis=1)))
    full_traceback = np.hstack(
        (top_width_image, np.flip(bottom_width_image, axis=1)))
    full_true_width_image = np.hstack(
        (top_true_widths, np.flip(top_true_widths, axis=1)))
    full_new_costs = np.hstack((top_new_costs, np.flip(bottom_new_costs,
                                                       axis=1)))
    full_y_grad = np.hstack((top_y_grad, np.flip(bottom_y_grad, axis=1)))
    full_sig = np.hstack((top_sig, np.flip(bottom_sig, axis=1)))

    return (full_image_down, full_traceback, full_true_width_image,
            full_new_costs, full_y_grad, full_sig)
Exemple #14
0
def train_PCs(training_data_dir, age_range=None, n_points=100):
    '''
	Takes worm masks and metadata from subdirectories in training_data_dir and generates principal components from the set of 99 angles tangent to the worms' outlines.
	'''
    training_subdirs = [
        os.path.join(training_data_dir, subdir)
        for subdir in os.listdir(training_data_dir)
        if os.path.isdir(os.path.join(training_data_dir, subdir))
    ]
    endings = ['bf.png', 'mask.png', 'metadata.pickle']

    all_shapes = []
    scale_factors = []
    width_list = []
    for subdir in training_subdirs:
        total_files = os.listdir(subdir)
        data_points = [
            ' '.join(a_file.split('.')[0].split(' ')[0:-1])
            for a_file in total_files if a_file.split('.')[-1] == 'pickle'
        ]
        for a_point in data_points:
            my_metadata = pickle.load(
                open(subdir + os.path.sep + a_point + ' ' + endings[2], 'rb'))
            if age_range == None or age_range[0] <= my_metadata[
                    'age_days'] <= age_range[1]:
                spine_tck = my_metadata['spine_tck']
                width_tck = my_metadata['width_tck']
                my_spine = zplib_interpolate.spline_interpolate(
                    spine_tck, n_points)
                widths = zplib_interpolate.spline_interpolate(
                    width_tck, n_points)
                (my_spine,
                 scale_factor) = normalize_worm(my_spine,
                                                final_scale=1,
                                                final_angle=0,
                                                return_scale_factor=True)
                scale_factors.append(scale_factor)
                width_list.append(widths)
                all_shapes.append(np.ndarray.flatten(my_spine))

    class a_PCA():
        def __init__(self, mean, pcs, norm_pcs, variances, positions,
                     norm_positions, scale_factors):
            self.mean = mean
            self.pcs = pcs
            self.norm_pcs = norm_pcs
            self.variances = variances
            self.positions = positions
            self.norm_positions = norm_positions
            self.components_ = norm_pcs
            self.mean_scale = np.mean(scale_factors)

    mean, pcs, norm_pcs, variances, positions, norm_positions = zplib_pca.pca(
        all_shapes)
    width_mean, width_pcs, width_norm_pcs, width_variances, width_positions, width_norm_positions = zplib_pca.pca(
        width_list)
    my_PCA = a_PCA(mean, pcs, norm_pcs, variances, positions, norm_positions,
                   scale_factors)
    width_PCA = a_PCA(width_mean, width_pcs, width_norm_pcs, width_variances,
                      width_positions, width_norm_positions, scale_factors)
    print('Finished training spine points PCs.')
    return (my_PCA, width_PCA)
Exemple #15
0
def initialize_fit(standard_mask,
                   my_PCA,
                   width_PCA,
                   pcs_number=20,
                   n_points=100,
                   reverse_flag=False,
                   verbose_mode=False,
                   spine_mode=False):
    '''
	Given a rough mask of the worm, initialize a vector of parameters to input into our model.
	
	Returns the vector x0 which contains:
	pc_components
	scale_factor (relative to mean scale factor in my_PCA)
	center_of_mass (normalized)
	long_axis_angle
	'''
    def initialize_outline(standard_mask, verbose_mode, reverse_flag=False):
        '''
		Given a mask of a worm, this function will guess at the outline of the worm, returning a spline fit to a pruned skeleton of the mask.
		'''
        def prune_skeleton(skeleton_graph, verbose_mode):
            '''
			Prune the graph of the skeleton so that only the single linear longest path remains.
			'''
            if verbose_mode:
                print('Pruning skeleton graph.')

            def farthest_node(my_graph, a_node, verbose_mode):
                '''
				Find the farthest node from a_node.
				'''
                reached_nodes = [a_node]
                distance_series = pd.Series(
                    index=[str(a_node) for a_node in skeleton_graph.node_list])
                distance_series.loc[str(a_node)] = 0
                steps = 1
                current_circle = [a_node]
                next_circle = []

                while len(reached_nodes) < len(my_graph.node_list):
                    if verbose_mode:
                        print('Reached nodes: ' + str(len(reached_nodes)))
                    for current_node in current_circle:
                        next_steps = my_graph.edges(current_node)
                        if verbose_mode:
                            print('Current circle')
                            print(current_circle)
                            print('next_steps')
                            print(next_steps)
                        for one_step in next_steps:
                            other_node = [
                                the_node for the_node in one_step
                                if the_node != current_node
                            ][0]
                            if other_node not in reached_nodes:
                                distance_series.loc[str(other_node)] = steps
                                next_circle.append(other_node)
                                reached_nodes.append(other_node)
                    steps += 1
                    current_circle = next_circle
                    next_circle = []
                my_node = distance_series.argmax()
                my_node = (int(my_node[1:-1].split(',')[0]),
                           int(my_node[1:-1].split(',')[1]))
                return my_node

            def find_minimal_path(my_graph, node_a, node_b, verbose_mode):
                '''
				Find the minimal path between node_a and node_b using my_graph.
				'''
                reached_nodes = [node_a]
                steps = 1
                current_circle = [[node_a]]
                next_circle = []
                got_to_b = False
                while not got_to_b:
                    if verbose_mode:
                        print(len(reached_nodes))
                        print([
                            the_node for the_node in reached_nodes
                            if the_node not in my_graph.node_list
                        ])
                    for current_path in current_circle:
                        current_node = current_path[-1]
                        next_steps = my_graph.edges(current_node)
                        for one_step in next_steps:
                            other_node = [
                                the_node for the_node in one_step
                                if the_node != current_node
                            ][0]
                            if other_node == node_b:
                                final_path = list(current_path)
                                final_path.append(other_node)
                                return (final_path, steps)

                            elif other_node not in reached_nodes:
                                next_path = list(current_path)
                                next_path.append(other_node)
                                next_circle.append(next_path)
                                reached_nodes.append(other_node)
                    steps += 1
                    current_circle = next_circle
                    next_circle = []
                return

            one_end = farthest_node(skeleton_graph,
                                    skeleton_graph.node_list[0],
                                    verbose_mode=verbose_mode)
            if verbose_mode:
                print('First end is: ' + str(one_end))
            other_end = farthest_node(skeleton_graph,
                                      one_end,
                                      verbose_mode=verbose_mode)
            if verbose_mode:
                print('Second end is: ' + str(other_end))

            (my_path,
             path_length) = find_minimal_path(skeleton_graph,
                                              one_end,
                                              other_end,
                                              verbose_mode=verbose_mode)
            my_path = np.array(my_path)
            return my_path

        def skeletonize_mask(raster_worm, verbose_mode):
            '''
			Given a masked worm in raster format, return a skeletonized version of it.
			'''
            if verbose_mode:
                print('Skeletonizing mask.')
            zero_one_mask = np.zeros(raster_worm.shape)
            zero_one_mask[raster_worm > 0] = 1
            zero_one_mask = zplib_image_mask.get_largest_object(zero_one_mask)
            my_skeleton = skimage.morphology.skeletonize(zero_one_mask)
            skeleton_mask = np.zeros(raster_worm.shape).astype('uint8')
            skeleton_mask[my_skeleton] = -1
            return skeleton_mask

        def skeleton_to_graph(skeleton_mask, verbose_mode):
            '''
			Converts a skeleton to a graph, which consists of a dictionary with a list of nodes (tuples containing the coordinates of each node) in 'nodes' and a list of edges (lists of two tuples containing coordinates of the nodes connected by the edge; all edges have length 1).
			'''
            if verbose_mode:
                print('Converting skeleton to graph.')
            node_list = [
                tuple(a_point) for a_point in np.transpose(
                    np.array(np.where(skeleton_mask > 0)))
            ]
            edge_list = []
            for point_a in node_list:
                for point_b in node_list:
                    distance_vector = np.array(point_a) - np.array(point_b)
                    check_distance = np.max(np.abs(distance_vector))
                    my_edge = sorted([point_a, point_b])
                    if check_distance == 1:
                        if my_edge not in edge_list:
                            edge_list.append(my_edge)

            class a_graph():
                def __init__(self, node_list, edge_list):
                    self.node_list = node_list
                    self.edge_list = edge_list
                    return

                def edges(self, a_node):
                    return [
                        an_edge for an_edge in edge_list if a_node in an_edge
                    ]

            my_graph = a_graph(node_list, edge_list)
            return my_graph

        messy_skeleton = skeletonize_mask(standard_mask,
                                          verbose_mode=verbose_mode)
        skeleton_graph = skeleton_to_graph(messy_skeleton,
                                           verbose_mode=verbose_mode)
        pruned_graph = prune_skeleton(skeleton_graph,
                                      verbose_mode=verbose_mode)
        if reverse_flag:
            pruned_graph = np.flipud(pruned_graph)
        spine_tck = zplib_interpolate.fit_spline(pruned_graph)
        return spine_tck

    def get_center_and_longaxis(raster_worm, my_spine):
        '''
		Given a masked worm in raster format and my_spine, find the normalized center of mass and the angle of the long axis.
		'''
        # Get normalized center of mass.
        standard_worm = np.array(np.where(raster_worm > 0))
        standard_center = np.mean(standard_worm, axis=1)
        center_of_mass = np.divide(standard_center, raster_worm.shape)

        # Get long axis angle.
        long_axis = my_spine[-1, :] - my_spine[0, :]
        long_axis_angle = np.arctan2(long_axis[1], long_axis[0])
        visual_angle = np.array(np.arctan2(-long_axis[1], long_axis[0]))
        return (center_of_mass, long_axis_angle, visual_angle)

    # Initialize x0.
    x0 = np.zeros(pcs_number + 5 + 4)

    # Guess the spine and project it on to our PCA basis.
    if verbose_mode:
        print('Getting spine.')
    spine_tck = initialize_outline(standard_mask,
                                   reverse_flag=reverse_flag,
                                   verbose_mode=verbose_mode)
    my_spine = zplib_interpolate.spline_interpolate(spine_tck, n_points)

    # Fit a width profile to my mask.
    my_perpendiculars = zplib_geometry.find_polyline_perpendiculars(my_spine)
    distance_map = scipy.ndimage.morphology.distance_transform_edt(
        standard_mask)
    my_widths = np.zeros((my_spine.shape[0], 2))
    for i in range(0, len(my_perpendiculars)):
        a_test_point = my_spine[i]
        b_test_point = my_spine[i]
        a_vector = my_perpendiculars[i]
        b_vector = -my_perpendiculars[i]
        found_edge_a = False
        found_edge_b = False
        a_side_distance = 0
        b_side_distance = 0
        while not (found_edge_a) or not (found_edge_b):
            a_side_distance += 1
            a_test_point = np.round(my_spine[i] + a_vector * a_side_distance)
            a_to_edge = distance_map[a_test_point[0], a_test_point[1]]
            if a_to_edge == 0 and not (found_edge_a):
                found_edge_a = True
                my_widths[i, 0] = a_side_distance
            b_side_distance += 1
            b_test_point = np.round(my_spine[i] + b_vector * b_side_distance)
            b_to_edge = distance_map[b_test_point[0], b_test_point[1]]
            if b_to_edge == 0 and not (found_edge_b):
                found_edge_b = True
                my_widths[i, 1] = b_side_distance
    my_widths = np.mean(my_widths, axis=1)
    width_tck = fit_nspline(my_widths)
    if spine_mode:
        return (spine_tck, width_tck)

    # Get scale factor, based on length, for this worm.
    spine_vectors = my_spine[1:] - my_spine[:-1]
    scale_factor = np.mean(
        np.array(
            [np.linalg.norm(spine_vector) for spine_vector in spine_vectors]))
    x0[-4] = scale_factor

    # Project spine on to PCs.
    normalized_spine = normalize_worm(my_spine, final_angle=0, final_scale=1)
    linear_spine = np.ndarray.flatten(normalized_spine)
    my_components = deviation_projection(linear_spine, my_PCA)
    for i in range(0, pcs_number):
        x0[i] = my_components[i]

    # Project widths on to PCs.
    my_width_components = deviation_projection(my_widths, width_PCA)
    for i in range(0, 5):
        x0[pcs_number + i] = my_width_components[i]

    # Find center of mass and long axis angle.
    if verbose_mode:
        print('Getting center and long axis.')
    (center_of_mass, long_axis_angle,
     visual_angle) = get_center_and_longaxis(standard_mask, my_spine)
    x0[-3:-1] = center_of_mass
    x0[-1] = long_axis_angle
    return x0
Exemple #16
0
def find_edges(image,
               avg_width_tck,
               ggm_sigma=1,
               sig_per=61,
               sig_growth_rate=2,
               alpha=1,
               mcp_alpha=1):
    """Find the edges of one side of the worm and return the x,y positions of the new widths
    NOTE: This function assumes that the image is only half of the worm (ie. from the centerline
    to the edges of the worm)

    Parameters:
        image: ndarray of the straightened worm image (typically either top or bottom half)
        avg_width_tck: width spline defining the average distance from the centerline
            to the worm edges (This is taken from the pca things we did earlier)
        ggm_sigma, sig_per, sig_growth_rate, alpha, mcp_alpha: hyperparameters for 
            the edge-detection scheme
    
    Returns:
        route: tuple of x,y positions of the identfied edges
    """

    #down sample the image
    image_down = pyramid.pyr_down(image, downscale=2)

    #get the gradient
    gradient = ndimage.filters.gaussian_gradient_magnitude(
        image_down, ggm_sigma)
    print(sig_per)
    top_ten = np.percentile(gradient, sig_per)
    gradient = sigmoid(gradient, gradient.min(), top_ten, gradient.max(),
                       sig_growth_rate)
    gradient = gradient.max() - abs(gradient)

    #penalize finding edges near the centerline or outside of the avg_width_tck
    #since the typical worm is fatter than the centerline and not huge
    #Need to divide by 2 because of the downsampling
    pen_widths = (interpolate.spline_interpolate(avg_width_tck,
                                                 image_down.shape[0]))
    #pen_widths = pen_widths/2
    distance_matrix = abs(
        np.subtract.outer(pen_widths, np.arange(0, image_down.shape[1])))
    #distance_matrix = np.flip(abs(np.subtract.outer(pen_widths, np.arange(0, image_down.shape[1]))), 1)
    penalty = alpha * (distance_matrix)
    new_costs = gradient + penalty

    #set start and end points for the traceback
    start = (0, int(pen_widths[0]))
    end = (len(pen_widths) - 1, int(pen_widths[-1]))
    #start = (0, int((image_down.shape[1]-1)-pen_widths[0]))
    #end = (len(pen_widths)-1, int((image_down.shape[1]-1)-pen_widths[-1]))
    #start = (0,0)
    #end = (len(pen_widths)-1, 0)

    #begin edge detection
    offsets = [(1, -1), (1, 0), (1, 1)]
    mcp = Smooth_MCP(new_costs, mcp_alpha, offsets=offsets)
    mcp.find_costs([start], [end])
    route = mcp.traceback(end)

    return image_down, route
Exemple #17
0
def width_finding(image,
                  ggm_sigma=1.03907545,
                  sig_per=61.3435119,
                  sig_growth_rate=2.42541565,
                  alpha=1.00167702,
                  mcp_alpha=1.02251872):
    """From the image, find the widths
    NOTE: assume the image is the warped image
    with the width of the image = int(center_tck[0][-1]//5)
    This is the same width as the spline view of the pose annotator

    Parameters:
        image: image of a straightened worm to get the widths from
        width_tck: tcks that give the widths for the worm
        params: list of the parameter values in the order [ggm sigma, sigmoid percentile, 
                sigmoid growth rate, alpha for the penalties]
    """
    #normalize the image based on mode
    #print(ggm_sigma,sig_per,sig_growth_rate,alpha)
    #down sample the image
    #image_down = image
    #image_down = scale_image(image)
    #the centerline is half of the width
    image_down = pyramid.pyr_down(image, downscale=2)
    #image_down = image.astype(np.float32)

    #get the gradient
    gradient = ndimage.filters.gaussian_gradient_magnitude(
        image_down, ggm_sigma)
    y_grad = ndimage.filters.gaussian_gradient_magnitude(image_down, ggm_sigma)
    top_ten = np.percentile(gradient, sig_per)
    gradient = sigmoid(gradient, gradient.min(), top_ten, gradient.max(),
                       sig_growth_rate)
    sig = gradient
    gradient = gradient.max() - abs(gradient)

    #get the widths from the width_tck and then get the distance matrix of the
    #widths to the centerline of the worm
    #NOTE: widths are the avg widths from the pca
    widths = interpolate.spline_interpolate(avg_width_tck, image_down.shape[0])
    widths = widths / 2
    #widths = interpolate.spline_interpolate(width_tck, image_down.shape[0])
    #widths = widths/2 #need to divide by the downscale factor to get the right pixel values

    #penalizing the costs for being too far from the widths
    #half_distance_matrix = abs(np.subtract.outer(widths, np.arange(0, image_down.shape[1]/2)))

    #calculate the penalty
    #we want to penalize things that are farther from the average widths, so we square the distance
    distance_matrix = np.flip(
        abs(np.subtract.outer(widths, np.arange(0, image_down.shape[1]))), 1)
    penalty = alpha * (distance_matrix)
    new_costs = gradient + penalty
    #new_costs = gradient
    #set start and end points for the traceback
    start = (0, int((image_down.shape[1] - 1) - widths[0]))
    end = (len(widths) - 1, int((image_down.shape[1] - 1) - widths[-1]))

    #start = (0, int((image_down.shape[1]/2)-widths[0]))
    #end = (len(widths)-1, int((image_down.shape[1]/2)-widths[-1]))
    #print(start, end)
    #print(new_costs.shape)
    offsets = [(1, -1), (1, 0), (1, 1)]
    #mcp = graph.MCP(new_costs, offsets=offsets, fully_connected=True)
    mcp = Smooth_MCP(new_costs, mcp_alpha, offsets=offsets)
    costs, _ = mcp.find_costs([start], [end])
    #print(costs.shape)
    route = mcp.traceback(end)
    #visualize things
    new_widths_image = make_traceback_image(route, image_down.shape)
    #width_image = visualize_widths(widths, image_down.shape)
    return (image_down, route, new_widths_image, new_costs, y_grad, sig)
def fit_simple_skeleton(image_masks, save_dir='', reverse_spine=np.array([])):
    def prune_skeleton(skeleton_graph, verbose_mode):
        '''
        Prune the graph of the skeleton so that only the single linear longest path remains.
        '''
        if verbose_mode:
            print('Pruning skeleton graph.')

        def farthest_node(my_graph, a_node, verbose_mode):
            '''
            Find the farthest node from a_node.
            '''
            reached_nodes = [a_node]
            distance_series = pd.Series(
                index=[str(a_node) for a_node in skeleton_graph.node_list])
            distance_series.loc[str(a_node)] = 0
            steps = 1
            current_circle = [a_node]
            next_circle = []

            while len(reached_nodes) < len(my_graph.node_list):
                if verbose_mode:
                    print('Reached nodes: ' + str(len(reached_nodes)))
                for current_node in current_circle:
                    next_steps = my_graph.edges(current_node)
                    if verbose_mode:
                        print('Current circle')
                        print(current_circle)
                        print('next_steps')
                        print(next_steps)
                    for one_step in next_steps:
                        other_node = [
                            the_node for the_node in one_step
                            if the_node != current_node
                        ][0]
                        if other_node not in reached_nodes:
                            distance_series.loc[str(other_node)] = steps
                            next_circle.append(other_node)
                            reached_nodes.append(other_node)
                steps += 1
                current_circle = next_circle
                next_circle = []
            my_node = distance_series.argmax()
            my_node = (int(my_node[1:-1].split(',')[0]),
                       int(my_node[1:-1].split(',')[1]))
            return my_node

        def find_minimal_path(my_graph, node_a, node_b, verbose_mode):
            '''
            Find the minimal path between node_a and node_b using my_graph.
            '''
            reached_nodes = [node_a]
            steps = 1
            current_circle = [[node_a]]
            next_circle = []
            got_to_b = False
            while not got_to_b:
                if verbose_mode:
                    print(len(reached_nodes))
                    print([
                        the_node for the_node in reached_nodes
                        if the_node not in my_graph.node_list
                    ])
                for current_path in current_circle:
                    current_node = current_path[-1]
                    next_steps = my_graph.edges(current_node)
                    for one_step in next_steps:
                        other_node = [
                            the_node for the_node in one_step
                            if the_node != current_node
                        ][0]
                        if other_node == node_b:
                            final_path = list(current_path)
                            final_path.append(other_node)
                            return (final_path, steps)

                        elif other_node not in reached_nodes:
                            next_path = list(current_path)
                            next_path.append(other_node)
                            next_circle.append(next_path)
                            reached_nodes.append(other_node)
                steps += 1
                current_circle = next_circle
                next_circle = []
            return

        one_end = farthest_node(skeleton_graph,
                                skeleton_graph.node_list[0],
                                verbose_mode=verbose_mode)
        if verbose_mode:
            print('First end is: ' + str(one_end))
        other_end = farthest_node(skeleton_graph,
                                  one_end,
                                  verbose_mode=verbose_mode)
        if verbose_mode:
            print('Second end is: ' + str(other_end))

        (my_path, path_length) = find_minimal_path(skeleton_graph,
                                                   one_end,
                                                   other_end,
                                                   verbose_mode=verbose_mode)
        my_path = np.array(my_path)
        return my_path

    def skeletonize_mask(raster_worm, verbose_mode):
        '''
        Given a masked worm in raster format, return a skeletonized version of it.
        '''
        if verbose_mode:
            print('Skeletonizing mask.')
        zero_one_mask = np.zeros(raster_worm.shape)
        zero_one_mask[raster_worm > 0] = 1
        zero_one_mask = zplib.image.mask.get_largest_object(zero_one_mask)
        my_skeleton = skimage.morphology.skeletonize(zero_one_mask)
        skeleton_mask = np.zeros(raster_worm.shape).astype('uint8')
        skeleton_mask[my_skeleton] = -1
        return skeleton_mask

    def skeleton_to_graph(skeleton_mask, verbose_mode):
        '''
        Converts a skeleton to a graph, which consists of a dictionary with a list of nodes (tuples containing the coordinates of each node) in 'nodes' and a list of edges (lists of two tuples containing coordinates of the nodes connected by the edge; all edges have length 1).
        '''
        if verbose_mode:
            print('Converting skeleton to graph.')
        node_list = [
            tuple(a_point)
            for a_point in np.transpose(np.array(np.where(skeleton_mask > 0)))
        ]
        edge_list = []
        for point_a in node_list:
            for point_b in node_list:
                distance_vector = np.array(point_a) - np.array(point_b)
                check_distance = np.max(np.abs(distance_vector))
                my_edge = sorted([point_a, point_b])
                if check_distance == 1:
                    if my_edge not in edge_list:
                        edge_list.append(my_edge)

        class a_graph():
            def __init__(self, node_list, edge_list):
                self.node_list = node_list
                self.edge_list = edge_list
                return

            def edges(self, a_node):
                return [an_edge for an_edge in edge_list if a_node in an_edge]

        my_graph = a_graph(node_list, edge_list)
        return my_graph

    n_points = 10
    spine_out = np.zeros([(mask_imgs.shape)[0], n_points, 2])

    if (reverse_spine.size == 0):
        print('No orientation for spine found')
        reverse_spine = np.zeros([(mask_imgs.shape)[0]])
    else:
        print('Using supplied orientation')

    for (mask_idx,
         mask_img), reverse_this_spine in zip(enumerate(mask_imgs),
                                              reverse_spine):
        print('processing simple spine for mask img {:03}'.format(mask_idx))
        pruned_graph = prune_skeleton(
            skeleton_to_graph(skeletonize_mask(mask_img, True), True), True)
        spine_tck = zplib_interpolate.fit_spline(pruned_graph)
        spine_out[mask_idx, :, :] = zplib_interpolate.spline_interpolate(
            spine_tck, n_points)
        if reverse_this_spine:
            spine_out[mask_idx, :, :] = np.flipud(spine_out[mask_idx, :, :])
        if save_dir != '':
            plt.figure(0)
            plt.gcf().clf()
            plt.imshow(mask_img.T)
            plt.scatter(spine_out[mask_idx, :, 0],
                        spine_out[mask_idx, :, 1],
                        c='b')
            plt.scatter(spine_out[mask_idx, 0, 0],
                        spine_out[mask_idx, 0, 1],
                        c='r')
            plt.figure(0).savefig(save_dir + os.path.sep +
                                  'mask_spine_{:03}.png'.format(mask_idx))

    return spine_out
            tck_egg[worm][timepoint] = (spl, tp_egg_age[worm][timepoint])

#Get width_tcks for adult worms
width_tcks = []
for timepoint in tck_egg.values():
    for age_tck in timepoint.values():
        if age_tck[1] > 0.0:
            width_tcks.append(age_tck[0][1])

#Interpolate widths to 100 points
from zplib.curve import interpolate
width_points = []
import numpy as np

for tck in width_tcks:
    width_points.append(interpolate.spline_interpolate(tck, 100))
width_points
width_points = np.array(width_points)

#PCAAAA
from zplib import pca
mean, pcs, norm_pcs, variances, total_variance, positions, norm_positions = pca.pca_dimensionality_reduce(
    width_points, 0.95)
variances / total_variance
norm_pcs.shape
for std in (-1, 0, 1):
    plt.plot(mean + std * norm_pcs[0])
plt.show()
for std in (-1, 0, 1):
    plt.plot(mean + std * norm_pcs[1])
plt.show()
Exemple #20
0
 def evaluate_tck(self, derivative=0):
     return interpolate.spline_interpolate(self._tck,
                                           num_points=int(self._tck[0][-1]),
                                           derivative=derivative)
def initialize_fit(standard_mask, my_PCA, width_PCA, pcs_number = 20, n_points = 100, reverse_flag = False, verbose_mode = False, spine_mode = False):
	'''
	Given a rough mask of the worm, initialize a vector of parameters to input into our model.
	
	Returns the vector x0 which contains:
	pc_components
	scale_factor (relative to mean scale factor in my_PCA)
	center_of_mass (normalized)
	long_axis_angle
	'''	
	def initialize_outline(standard_mask, verbose_mode, reverse_flag = False):
		'''
		Given a mask of a worm, this function will guess at the outline of the worm, returning a spline fit to a pruned skeleton of the mask.
		'''
		def prune_skeleton(skeleton_graph, verbose_mode):
			'''
			Prune the graph of the skeleton so that only the single linear longest path remains.
			'''
			if verbose_mode:
				print('Pruning skeleton graph.')

			def farthest_node(my_graph, a_node, verbose_mode):
				'''
				Find the farthest node from a_node.
				'''
				reached_nodes = [a_node]
				distance_series = pd.Series(index = [str(a_node) for a_node in skeleton_graph.node_list])
				distance_series.loc[str(a_node)] = 0
				steps = 1
				current_circle = [a_node]
				next_circle = []
								
				while len(reached_nodes) < len(my_graph.node_list):
					if verbose_mode:		
						print('Reached nodes: ' + str(len(reached_nodes)))
					for current_node in current_circle:
						next_steps = my_graph.edges(current_node)
						if verbose_mode:
							print('Current circle')
							print(current_circle)
							print('next_steps')
							print(next_steps)
						for one_step in next_steps:
							other_node = [the_node for the_node in one_step if the_node != current_node][0]
							if other_node not in reached_nodes:
								distance_series.loc[str(other_node)] = steps 
								next_circle.append(other_node)
								reached_nodes.append(other_node)
					steps += 1
					current_circle = next_circle
					next_circle = []
				my_node = distance_series.argmax()
				my_node = (int(my_node[1:-1].split(',')[0]), int(my_node[1:-1].split(',')[1]))
				return my_node
			
			def find_minimal_path(my_graph, node_a, node_b, verbose_mode):
				'''
				Find the minimal path between node_a and node_b using my_graph.
				'''
				reached_nodes = [node_a]
				steps = 1
				current_circle = [[node_a]]
				next_circle = []
				got_to_b = False
				while not got_to_b:
					if verbose_mode:
						print(len(reached_nodes))		
						print([the_node for the_node in reached_nodes if the_node not in my_graph.node_list])		
					for current_path in current_circle:
						current_node = current_path[-1]
						next_steps = my_graph.edges(current_node)
						for one_step in next_steps:
							other_node = [the_node for the_node in one_step if the_node != current_node][0]
							if other_node == node_b:
								final_path = list(current_path)
								final_path.append(other_node)
								return (final_path, steps)
								
							elif other_node not in reached_nodes:
								next_path = list(current_path)
								next_path.append(other_node)
								next_circle.append(next_path)
								reached_nodes.append(other_node)
					steps += 1
					current_circle = next_circle
					next_circle = []	
				return
								
			one_end = farthest_node(skeleton_graph, skeleton_graph.node_list[0], verbose_mode = verbose_mode)
			if verbose_mode:
				print('First end is: ' + str(one_end))
			other_end = farthest_node(skeleton_graph, one_end, verbose_mode = verbose_mode)
			if verbose_mode:
				print('Second end is: ' + str(other_end))
				
			(my_path, path_length) = find_minimal_path(skeleton_graph, one_end, other_end, verbose_mode = verbose_mode)
			my_path = np.array(my_path)
			return my_path

		def skeletonize_mask(raster_worm, verbose_mode):
			'''
			Given a masked worm in raster format, return a skeletonized version of it.
			'''
			if verbose_mode:
				print('Skeletonizing mask.')
			zero_one_mask = np.zeros(raster_worm.shape)
			zero_one_mask[raster_worm > 0] = 1
			zero_one_mask = zplib_image_mask.get_largest_object(zero_one_mask)
			my_skeleton = skimage.morphology.skeletonize(zero_one_mask)
			skeleton_mask = np.zeros(raster_worm.shape).astype('uint8')
			skeleton_mask[my_skeleton] = -1
			return skeleton_mask
		
		def skeleton_to_graph(skeleton_mask, verbose_mode):
			'''
			Converts a skeleton to a graph, which consists of a dictionary with a list of nodes (tuples containing the coordinates of each node) in 'nodes' and a list of edges (lists of two tuples containing coordinates of the nodes connected by the edge; all edges have length 1).
			'''
			if verbose_mode:
				print('Converting skeleton to graph.')
			node_list = [tuple(a_point) for a_point in np.transpose(np.array(np.where(skeleton_mask > 0)))]
			edge_list = []
			for point_a in node_list:
				for point_b in node_list:
					distance_vector = np.array(point_a) - np.array(point_b)
					check_distance = np.max(np.abs(distance_vector))
					my_edge = sorted([point_a, point_b])
					if check_distance == 1:
						if my_edge not in edge_list:
							edge_list.append(my_edge)
			
			class a_graph():
				def __init__(self, node_list, edge_list):
					self.node_list = node_list
					self.edge_list = edge_list
					return
				def edges(self, a_node):
					return [an_edge for an_edge in edge_list if a_node in an_edge]
		
			my_graph = a_graph(node_list, edge_list)
			return my_graph
		
		messy_skeleton = skeletonize_mask(standard_mask, verbose_mode = verbose_mode)
		skeleton_graph = skeleton_to_graph(messy_skeleton, verbose_mode = verbose_mode)	
		pruned_graph = prune_skeleton(skeleton_graph, verbose_mode = verbose_mode)	
		if reverse_flag:
			pruned_graph = np.flipud(pruned_graph)
		spine_tck = zplib_interpolate.fit_spline(pruned_graph)
		return spine_tck
		
	def get_center_and_longaxis(raster_worm, my_spine):
		'''
		Given a masked worm in raster format and my_spine, find the normalized center of mass and the angle of the long axis.
		'''
		# Get normalized center of mass.
		standard_worm = np.array(np.where(raster_worm > 0))
		standard_center = np.mean(standard_worm, axis = 1)
		center_of_mass = np.divide(standard_center, raster_worm.shape)
		
		# Get long axis angle.
		long_axis = my_spine[-1, :] - my_spine[0, :]
		long_axis_angle = np.arctan2(long_axis[1], long_axis[0])
		visual_angle = np.array(np.arctan2(-long_axis[1], long_axis[0]))
		return (center_of_mass, long_axis_angle, visual_angle)

	# Initialize x0.
	x0 = np.zeros(pcs_number + 5 + 4)

	# Guess the spine and project it on to our PCA basis.
	if verbose_mode:
		print('Getting spine.')
	spine_tck = initialize_outline(standard_mask, reverse_flag = reverse_flag, verbose_mode = verbose_mode)
	my_spine = zplib_interpolate.spline_interpolate(spine_tck, n_points)

	# Fit a width profile to my mask.
	my_perpendiculars = zplib_geometry.find_polyline_perpendiculars(my_spine)
	distance_map = scipy.ndimage.morphology.distance_transform_edt(standard_mask)
	my_widths = np.zeros((my_spine.shape[0], 2))
	for i in range(0, len(my_perpendiculars)):		
		a_test_point = my_spine[i]
		b_test_point = my_spine[i]
		a_vector = my_perpendiculars[i]
		b_vector = -my_perpendiculars[i]
		found_edge_a = False
		found_edge_b = False
		a_side_distance = 0
		b_side_distance = 0
		while not(found_edge_a) or not(found_edge_b):
			a_side_distance += 1
			a_test_point = np.round(my_spine[i] + a_vector*a_side_distance)
			a_to_edge = distance_map[a_test_point[0], a_test_point[1]]
			if a_to_edge == 0 and not(found_edge_a):
				found_edge_a = True
				my_widths[i, 0] = a_side_distance
			b_side_distance += 1
			b_test_point = np.round(my_spine[i] + b_vector*b_side_distance)
			b_to_edge = distance_map[b_test_point[0], b_test_point[1]]
			if b_to_edge == 0 and not(found_edge_b):
				found_edge_b = True
				my_widths[i, 1] = b_side_distance
	my_widths = np.mean(my_widths, axis = 1)
	width_tck = fit_nspline(my_widths)
	if spine_mode:
		return (spine_tck, width_tck)

	# Get scale factor, based on length, for this worm.
	spine_vectors = my_spine[1:] - my_spine[:-1]
	scale_factor = np.mean(np.array([np.linalg.norm(spine_vector) for spine_vector in spine_vectors]))
	x0[-4] = scale_factor

	# Project spine on to PCs.
	normalized_spine = normalize_worm(my_spine, final_angle = 0, final_scale = 1)
	linear_spine = np.ndarray.flatten(normalized_spine)
	my_components = deviation_projection(linear_spine, my_PCA)
	for i in range(0, pcs_number):
		x0[i] = my_components[i]		

	# Project widths on to PCs.
	my_width_components = deviation_projection(my_widths, width_PCA)
	for i in range(0, 5):
		x0[pcs_number + i] = my_width_components[i]

	# Find center of mass and long axis angle.
	if verbose_mode:
		print('Getting center and long axis.')
	(center_of_mass, long_axis_angle, visual_angle) = get_center_and_longaxis(standard_mask, my_spine)	
	x0[-3:-1] = center_of_mass
	x0[-1] = long_axis_angle 
	return x0
Exemple #22
0
def save_centerline(metadata, centerline_file):
    spine_tck = metadata['spine_tck']
    positions = interpolate.spline_interpolate(spine_tck, 50)
    write_xy_positions(centerline_file, positions)