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
def _detect_edges(image, optocoupler, center_tck, width_tck, image_gamma, downscale, gradient_sigma, sigmoid_midpoint, sigmoid_growth_rate, edge_weight, roughness_penalty, post_smoothing): """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. (Somewhere around the 50th percentile seems generally good.) sigmoid_growth_rate: steepness of the sigmoid function. (The gradient is over an image rescaled from 0-1; such images have a max gradient in the worm region in the range 0.1-0.2. So the range of the sigmoid function is generally 0-0.2 or so; getting a steep curve requires growth rates in the 500-1000 range.) edge_weight: how much to weight image edge strength vs. distance from the average widths in the cost function. (The edge part of the cost function goes from 0 to 1, and the distance part goes from 0 to the maximum pixel distance from the average edge; typically 15 or so for a 2x downscaled image. So to have both terms equally weighted, edge_weight should be around 10-20.) roughness_penalty: how much to penalize diagonal steps vs. straight steps in the edge tracing (to penalize jagged edges). The penalty is multiplicative and scaled by the length of the step: a value of 1 doesn't penalize diagonal steps, while a value of 2 means that a 1-pixel-up diagonal step costs 2*sqrt(2) times more. post_smoothing: spline smoothing factor for re-fit centerline. Returns: (cost_image, new_center_tck, new_width_tck) cost_image: image defining the cost function for edge tracing new_center_tck: new centerline spline new_width_tck: new width spline """ cost_image = get_cost_image(image, optocoupler, image_gamma, center_tck, width_tck, downscale, gradient_sigma, sigmoid_midpoint, sigmoid_growth_rate, edge_weight) # trace edges to calculate new centerline and widths center_coordinates, widths = edge_coordinates(cost_image, roughness_penalty) lab_center_coordinates = worm_spline.coordinates_to_lab_frame( center_coordinates, cost_image.shape, center_tck, zoom=1 / downscale) new_center_tck = interpolate.fit_spline(lab_center_coordinates, smoothing=post_smoothing * len(lab_center_coordinates)) x = numpy.linspace(0, 1, len(widths)) # NB: expand widths to account for downsampling new_width_tck = interpolate.fit_nonparametric_spline( x, widths * downscale, smoothing=post_smoothing * len(widths)) return cost_image, new_center_tck, new_width_tck
def generate_width_from_pca(projection, pca_stuff): '''If you are given a projection from pca (3 components), then generate a width_tck from it ''' widths = pca.pca_reconstruct(projection, pcs[:3], mean) #make new width spline width_tck = interpolate.fit_nonparametric_spline(np.linspace(0,1, len(smoothed_widths)), smoothed_widths) return width_tck
def calculate_tck(self, widths, x=None, smoothing=None): if x is None: x = numpy.linspace(0, 1, len(widths)) if smoothing is None: smoothing = self.REFIT_SMOOTH return interpolate.fit_nonparametric_spline(x, widths, smoothing=smoothing * len(widths))
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
def fit_splines(center_path, mask, dv_coords, width_range=(50, 100), width_step=1, center_smoothing=0.1, width_smoothing=0.0001): """Find a (center_tck, width_tck) pose from the centerline path. The main challenge is that the dv coordinates are relative to that worm, so an absolute scale must be determined. This is done by trying various absolute scale factors to find the pixel width of the worm as a function of the dv coordinate value along the centerline, and choosing that which best recapitulates the mask image provided. Parameters: center_path: (n, 2)-shape array of coordinates along the centerline of a worm mask: approximate mask of worm outline dv_coords: dv coordinate image width_range: range of possible scale factors to try for the worm (though note that the width_tck values are in terms of half-widths from the centerline to the edge) width_step: step size for evaluating possible worm widths. center_smoothing: average distance the center_tck spline is allowed to deviate from the input path coordinates. width_smoothing: average distance the width_tck spline is allowed to deviate from the input dv coordinate values. Returns: (center_tck, width_tck) pose tuple """ center_smoothing *= len(center_path) center_tck = interpolate.fit_spline(center_path, smoothing=center_smoothing, force_endpoints=False) width_profile = dv_coords[tuple( center_path.T)] / 6 # scale widths in [0, 0.5] range # This range is so that when the width_profile is multiplied by the total worm width, the # resulting width_tck will produce the expected half-width distances from centerline to edge x = numpy.linspace(0, 1, len(width_profile)) width_smoothing *= len(width_profile) width_profile_tck = interpolate.fit_nonparametric_spline( x, width_profile, smoothing=width_smoothing) # do coarse / fine search for best width multiplier width_tck, max_width = _fit_widths_to_mask(center_tck, width_profile_tck, width_range, width_step * 4, mask) width_range = max_width - 8 * width_step, max_width + 8 * width_step width_tck, max_width = _fit_widths_to_mask(center_tck, width_profile_tck, width_range, width_step, mask) return center_tck, width_tck
def generate_width_spline(traceback, shape): '''From the traceback, generate a new width spline. ''' #since the centerline is at x=0, we just need the #y values to get the widths _, widths = np.where(traceback) widths = shape[1] - widths - 1 x_vals = np.linspace(0, 1, len(widths)) smoothing = 0.2 * len(widths) tck = interpolate.fit_nonparametric_spline(x_vals, widths, smoothing=smoothing) return tck
def width_spline(traceback, distances, smoothing=None): '''Generate a nonparametric spline of the widths along the worm centerline Parameters: ------------ traceback: list of 2-d tuples List of indices associated with the centerline, starting with one of the endpoints of the centerline and ending with the ending index of the centerline. distances: ndarray shape(n,m) Distance transform from the medial axis transform of the worm mask Returns: ----------- tck: nonparametric spline tuple spline tuple (see documentation for zplib.interpolate for more info) ''' widths = distances[list(np.transpose(traceback))] #print(widths[0]) #print(widths[-1]) begin_widths = np.linspace(0, widths[0], widths[0], endpoint=False) end_widths = np.linspace(widths[-1] - 1, 0, widths[-1]) new_widths = np.concatenate((begin_widths, widths, end_widths)) x_vals = np.linspace(0, 1, len(new_widths)) #print(x_vals) #print(new_widths.shape) #print(new_widths) if smoothing is None: smoothing = 0.2 * len(widths) tck = interpolate.fit_nonparametric_spline(x_vals, new_widths, smoothing=smoothing) return tck
def make_unit_worm(metadata, avg_widths, avg_length, image_file, warp_file): """Make a unit worm and save the image to the warp_file Parameters: metadata: dictionary avg_widths: array, size (n_points,) array of average widths with which to make the worm image_file: str; what file to use to subsample the textures from warp_file: str; where to store the new warp file """ image = freeimage.read(image_file) spine_tck = metadata['spine_tck'] width_tck = metadata['width_tck'] warp_width = 2 * avg_widths.max() # the worm widths above are from center to edge, so twice that is edge-to-edge avg_widths_tck=interpolate.fit_nonparametric_spline(np.linspace(0,1,100),avg_widths) warped = resample.warp_image_to_standard_width(image, spine_tck, width_tck, avg_widths_tck, warp_width, length=avg_length) #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 print("writing unit worm to :"+str(warp_file)) freeimage.write(warped, warp_file) # freeimage convention: image.shape = (W, H). So take transpose.
def _to_tck(widths): x = numpy.linspace(0, 1, len(widths)) smoothing = 0.0625 * len(widths) return interpolate.fit_nonparametric_spline(x, widths, smoothing=smoothing)
from skimage import graph from scipy import ndimage from skimage import feature import scipy.ndimage as ndimage import scipy.optimize as optimize from sklearn.metrics import make_scorer from sklearn.model_selection import GridSearchCV import width_finding mean, pcs, norm_pcs, variances, total_variance, positions, norm_positions = pickle.load( open('/mnt/lugia_array/data/human_masks/warped_splines/pca_stuff.p', 'rb')) avg_width_positions = pca.pca_reconstruct([0, 0, 0], pcs[:3], mean) avg_width_tck = interpolate.fit_nonparametric_spline( np.linspace(0, 1, len(avg_width_positions)), avg_width_positions) def widths_rmsd(image, true_width_tck, ggm_sigma=3, sig_per=75, sig_growth_rate=2, alpha=1, mcp_alpha=1): """Used to optimize the parameters! Wrapper function to generate the widths and then evaluate them for the optimization later on """ image_down, traceback = width_finding.find_edges( image, avg_width_tck,
def _generate_pca_avg(self): mean, pcs, norm_pcs, variances, total_variance, positions, norm_positions = self.pca_stuff avg_width_positions = pca.pca_reconstruct([0, 0, 0], pcs[:3], mean) avg_width_tck = interpolate.fit_nonparametric_spline( np.linspace(0, 1, len(avg_width_positions)), avg_width_positions) return avg_width_tck
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() for std in (-1, 0, 1): plt.plot(mean + std * norm_pcs[2]) plt.show() #From PCA Go back and forth #Go from PCA -> real widths and back (real widths -> PCA) #Widths -> PCA projection = pca.pca_decompose(test_width, pcs, mean) #PCA -> Widths test_proj = projection[:3] positions = pca.pca_reconstruct(test_proj, pcs[:3], mean) #make new width spline reverse_width_spline = interpolate.fit_nonparametric_spline( np.linspace(0, 1, len(positions)), positions)