Exemplo n.º 1
0
def lawn_maker(bf_files, super_vignette):
	'''
	Find the bacterial lawn in one worm image.
	'''
	lawn_masks = []
	for a_bf_file in bf_files:
		# Prepare a worm image for use in lawn-finding.
		renormalized_image = freeimage.read(a_bf_file)
		renormalized_image = cv2.medianBlur(renormalized_image, 3)
		renormalized_image = imageOperations.renormalize_image(renormalized_image)
		
		# Remove extraneous edges and out-of-lawn junk by finding the lawn and also applying an "ultra-vignette" mask.
		ultra_vignette = scipy.ndimage.morphology.binary_erosion(super_vignette, iterations = 10)
		my_edges = skimage.feature.canny(renormalized_image, sigma = 0.02)
		my_edges[np.invert(ultra_vignette)] = False 
		my_edges = scipy.ndimage.morphology.binary_dilation(my_edges, iterations = 10)
		my_lawn = scipy.ndimage.morphology.binary_fill_holes(my_edges)
		try:
			my_lawn = zplib_image_mask.get_largest_object(my_lawn).astype('bool')
			my_lawn = scipy.ndimage.morphology.binary_erosion(my_lawn, iterations = 10)
			my_lawn = zplib_image_mask.get_largest_object(my_lawn).astype('bool')
		except:
			my_lawn = np.zeros(my_lawn.shape).astype('bool')
		lawn_masks.append(my_lawn)
	my_lawn = np.max(np.array(lawn_masks), axis = 0)
	return my_lawn
Exemplo n.º 2
0
    def stop_editing(self, save_work=True):
        # Convert outline to mask
        outline = zplib_image_mask.get_largest_object(
            self.rw.layers[2].image.data > 0)
        new_mask = zplib_image_mask.fill_small_area_holes(
            outline, 300000).astype('uint8')
        new_mask = new_mask > 0
        #new_mask[new_mask>0] = -1
        self.rw.layers[2].image.set(data=(new_mask > 0).astype('bool'))
        self.rw.layers[2].tint = (1.0, 1.0, 1.0, 1.0)

        #update spline data
        m, skel, centerline, center_dist, med_axis, tb = skeleton.skel_and_centerline(
            new_mask)
        current_page_idx = self.rw.flipbook.current_page_idx
        self.rw.layers[1:] = [skel, centerline, center_dist]
        self.rw.flipbook.pages[current_page_idx].spline_data = tb
        self.rw.flipbook.pages[current_page_idx].dist_data = center_dist
        self.rw.flipbook.pages[current_page_idx].med_axis = med_axis

        self.rw.qt_object.layer_stack_painter_dock_widget.hide()
        """if self.current_page[1].data.any():
                                    if not pathlib.Path(str(self.working_file).replace('mask.png','mask_oldwf.png')).exists():
                                        self.working_file.rename(str(self.working_file).replace('mask.png','mask_oldwf.png'))
                                    freeimage.write(new_mask, self.working_file)"""

        self.editing = False
        #self.working_file = None    # Do this after saving out since need the working file above
        self.edit.setText('Edit Mask')
Exemplo n.º 3
0
def pose_from_mask(mask, smoothing=2):
    """Calculate worm pose splines from mask image.

    Parameter:
        mask: mask image (the largest object in the mask will be used)
        smoothing: smoothing factor to apply to splines produced (see docstring
            for zplib.interpolate.smooth_spline). If 0, no smoothing will be applied.
    Returns: center_tck, width_tck
        splines defining the (x, y) position of the centerline and the distance
        from the centerline to the edge (called "widths" but more like "half-
        widths" more accurately) as a function of position along the centerline.
        If there was no object in the mask, returns None for each.
    """
    mask = mask > 0
    # get largest object allowing diagonal connectivity
    mask = zpmask.get_largest_object(mask, structure=numpy.ones((3,3)))
    # crop image for faster medial axis transform
    slices = ndimage.find_objects(mask)
    if len(slices) == 0: # mask is completely empty
        return None, None
    sx, sy = slices[0]
    cropped = mask[sx, sy]
    centerline, widths = _get_centerline(cropped)
    if len(centerline) < 10:
        return None, None
    center_tck, width_tck = _get_splines(centerline, widths)
    # adjust x, y coords to account for the cropping
    c = center_tck[1]
    c += sx.start, sy.start
    if smoothing > 0:
        center_tck = interpolate.smooth_spline(center_tck,
            num_points=int(center_tck[0][-1]), smoothing=smoothing)
        width_tck = interpolate.smooth_spline(width_tck, num_points=100,
            smoothing=smoothing)
    return center_tck, width_tck
Exemplo n.º 4
0
def find_initial_worm(small_image, well_mask):
    # plan here is to find known good worm edges with Canny using a stringent threshold, then
    # relax the threshold in the vicinity of the good edges.
    # back off another pixel from the well edge to avoid gradient from the edge
    shrunk_mask = ndimage.binary_erosion(well_mask, structure=S)
    smoothed, gradient, sobel = canny.prepare_canny(small_image, 2, shrunk_mask)
    local_maxima = canny.canny_local_maxima(gradient, sobel)
    # Calculate stringent and medium-stringent thresholds. The stringent threshold
    # is the 200th-brightest edge pixel, and the medium is the 450th-brightest pixel
    highp = 100 * (1-200/local_maxima.sum())
    highp = max(highp, 94)
    mediump = 100 * (1-450/local_maxima.sum())
    mediump = max(mediump, 94)
    low_worm, medium_worm, high_worm = numpy.percentile(gradient[local_maxima], [94, mediump, highp])
    stringent_worm = canny.canny_hysteresis(local_maxima, gradient, low_worm, high_worm)
    # Expand out 20 pixels from the stringent worm edges to make our search space
    stringent_area = ndimage.binary_dilation(stringent_worm, mask=well_mask, iterations=20)
    # now use the relaxed threshold but only in the stringent area
    relaxed_worm = canny.canny_hysteresis(local_maxima, gradient, low_worm, medium_worm) & stringent_area
    # join very close-by objects, and remove remaining small objects
    candidate_worm = ndimage.binary_dilation(relaxed_worm, structure=S)
    candidate_worm = ndimage.binary_erosion(candidate_worm)
    candidate_worm = mask.remove_small_area_objects(candidate_worm, 30, structure=S)
    # Now figure out the biggest blob of nearby edges, and call that the worm region
    glommed_candidate = ndimage.binary_dilation(candidate_worm, structure=S, iterations=2)
    glommed_candidate = ndimage.binary_erosion(glommed_candidate, iterations=2)
    # get just outline, not any regions filled-in due to closing
    glommed_candidate ^= ndimage.binary_erosion(glommed_candidate)
    glommed_candidate = mask.get_largest_object(glommed_candidate, structure=S)
    worm_area = ndimage.binary_dilation(glommed_candidate, mask=well_mask, structure=S, iterations=12)
    worm_area = mask.fill_small_radius_holes(worm_area, max_radius=15)
    candidate_edges = relaxed_worm & candidate_worm & worm_area
    return candidate_edges, worm_area
Exemplo n.º 5
0
def save_mask_lcc(experiment_root):
    experiment_root = pathlib.Path(experiment_root)
    mask_root = experiment_root / 'derived_data' / 'mask'

    for position_mask_root in sorted(mask_root.iterdir()):
        for mask_file in sorted(position_mask_root.iterdir()):
            mask_image = freeimage.read(str(mask_file)) > 0
            new_mask = mask.get_largest_object(mask_image).astype(numpy.uint8)
            freeimage.write(new_mask*255, str(mask_file))
Exemplo n.º 6
0
def refine_worm(image, initial_area, candidate_edges):
    # find strong worm edges (roughly equivalent to the edges found by find_initial_worm,
    # which are in candidate_edges): smooth the image, do canny edge-finding, and
    # then keep only those edges near candidate_edges
    smooth_image = restoration.denoise_tv_bregman(image, 140).astype(numpy.float32)
    smoothed, gradient, sobel = canny.prepare_canny(smooth_image, 8, initial_area)
    local_maxima = canny.canny_local_maxima(gradient, sobel)
    candidate_edge_region = ndimage.binary_dilation(candidate_edges, iterations=4)
    strong_edges = local_maxima & candidate_edge_region

    # Now threshold the image to find dark blobs as our initial worm region
    # First, find areas in the initial region unlikely to be worm pixels
    mean, std = mcd.robust_mean_std(smooth_image[initial_area][::4], 0.85)
    non_worm = (smooth_image > mean - std) & initial_area
    # now fit a smoothly varying polynomial to the non-worm pixels in the initial
    # region of interest, and subtract that from the actual image to generate
    # an image with a flat illumination field
    background = polyfit.fit_polynomial(smooth_image, mask=non_worm, degree=2)
    minus_bg = smooth_image - background
    # now recalculate a threshold from the background-subtracted pixels
    mean, std = mcd.robust_mean_std(minus_bg[initial_area][::4], 0.85)
    initial_worm = (minus_bg < mean - std) & initial_area
    # Add any pixels near the strong edges to our candidate worm position
    initial_worm |= ndimage.binary_dilation(strong_edges, iterations=3)
    initial_worm = mask.fill_small_radius_holes(initial_worm, 5)

    # Now grow/shrink the initial_worm region so that as many of the strong
    # edges from the canny filter are in contact with the region edges as possible.
    ac = active_contour.EdgeClaimingAdvection(initial_worm, strong_edges,
        max_region_mask=initial_area)
    stopper = active_contour.StoppingCondition(ac, max_iterations=100)
    while stopper.should_continue():
        ac.advect(iters=1)
        ac.smooth(iters=1, depth=2)
    worm_mask = mask.fill_small_radius_holes(ac.mask, 7)

    # Now, get edges from the image at a finer scale
    smoothed, gradient, sobel = canny.prepare_canny(smooth_image, 0.3, initial_area)
    local_maxima = canny.canny_local_maxima(gradient, sobel)
    strong_sum = strong_edges.sum()
    highp = 100 * (1 - 1.5*strong_sum/local_maxima.sum())
    lowp = max(100 * (1 - 3*strong_sum/local_maxima.sum()), 0)
    low_worm, high_worm = numpy.percentile(gradient[local_maxima], [lowp, highp])
    fine_edges = canny.canny_hysteresis(local_maxima, gradient, low_worm, high_worm)

    # Expand out the identified worm area to include any of these finer edges
    closed_edges = ndimage.binary_closing(fine_edges, structure=S)
    worm = ndimage.binary_propagation(worm_mask, mask=worm_mask|closed_edges, structure=S)
    worm = ndimage.binary_closing(worm, structure=S, iterations=2)
    worm = mask.fill_small_radius_holes(worm, 5)
    worm = ndimage.binary_opening(worm)
    worm = mask.get_largest_object(worm)
    # Last, smooth the shape a bit to reduce sharp corners, but not too much to
    # sand off the tail
    ac = active_contour.CurvatureMorphology(worm, max_region_mask=initial_area)
    ac.smooth(depth=2, iters=2)
    return strong_edges, ac.mask
def clean_dust_and_holes(dusty_pic):
    '''
    Picks out the largest object in dusty_mask and fills in its holes, returning cleaned_mask.
    '''
    my_dtype = dusty_pic.dtype
    dust_mask = np.invert(zplib_image_mask.get_largest_object(dusty_pic))       
    dusty_pic[dust_mask] = 0
    cleaned_mask = simple_floor(zplib_image_mask.fill_small_area_holes(dusty_pic, 90000).astype(my_dtype), 1)
    return cleaned_mask
Exemplo n.º 8
0
def parse_aggregate_centerlines(aggregate_mask):
    centerlines = []
    temp_mask = aggregate_mask.copy()
    for layer in numpy.moveaxis(temp_mask, -1, 0):
        while layer.any():
            new_centerline = zplib_image_mask.get_largest_object(layer>0,structure=numpy.ones((3,3)))
            new_centerline[new_centerline>0] = -1
            layer[new_centerline>0] = 0
            centerlines.append(new_centerline)
    return centerlines
Exemplo n.º 9
0
def calculate_iou(prediction, ground_truth, plot_val=False, save_val=False, save_dir=None, pyr=False):
    """Find intersection over union for 2 images
    Prediction and ground_truth are boolean arrays
    """
    pred_orig = freeimage.read(prediction)
    gt_orig = freeimage.read(ground_truth)

    folder, worm_id = ground_truth.parts[-2:]
    worm_id = worm_id.split(' ')[0]

    #get rid of stuff touching the edges
    if pyr:
        pred = mask.remove_edge_objects(pred_orig)
        gt = mask.remove_edge_objects(gt_orig)

        #find the worm in the mask (largest object presumably)
        pred_image = mask.get_largest_object(pred)
        ground_truth = mask.get_largest_object(gt
            )
    else:
        #find the worm in the mask (largest object presumably)
        pred_image = mask.get_largest_object(pred_orig)
        ground_truth = mask.get_largest_object(gt_orig)
    

    #find intersect and union
    intersect = (pred_image & ground_truth)
    union = (pred_image|ground_truth)

    #plot for validation
    if save_val:
        #maybe change this to not be this
        save_file = save_dir+"/"+folder+"_"+worm_id+"_val.png"
        #if willie:
        #    save_file = '/home/nicolette/Documents/lab_stuff/worm_segmentation_validation/Willie_iou/'+folder+"_"+worm_id+"_val.png"
        #else:
        #    save_file = '/home/nicolette/Documents/lab_stuff/MATLAB_scripts/binarySeg_v2/figFolder/background_sub_pyr/iou/'+prediction.stem+"_val.png"
        print("saving: "+save_file)
        plot_validation(pred_orig, gt_orig, intersect, union, save_val=True, save_file=save_file)
    if plot_val:
        plot_validation(pred_orig, gt_orig, intersect, union)

    return intersect.sum()/union.sum()
Exemplo n.º 10
0
def alternate_lawn_maker(bf_files, super_vignette):
	'''
	Make a lawn just by intensity when for some reason the normal lawn maker fails...
	'''
	lawn_masks = []
	for a_bf_file in bf_files:
		renormalized_image = read_corrected_bf(a_bf_file)
		lawn_cutoff = np.percentile(renormalized_image, 5)
		lawn_mask = np.zeros(renormalized_image.shape).astype('bool')
		lawn_mask[renormalized_image < lawn_cutoff] = True
		ultra_vignette = scipy.ndimage.morphology.binary_erosion(super_vignette, iterations = 10)
		lawn_mask[np.invert(ultra_vignette)] = False 
		lawn_mask = scipy.ndimage.morphology.binary_dilation(lawn_mask, iterations = 3)
		lawn_mask = scipy.ndimage.morphology.binary_fill_holes(lawn_mask)
		lawn_mask = zplib_image_mask.get_largest_object(lawn_mask).astype('bool')
		lawn_mask = scipy.ndimage.morphology.binary_erosion(lawn_mask, iterations = 3)
		lawn_mask = zplib_image_mask.get_largest_object(lawn_mask).astype('bool')
		lawn_masks.append(lawn_mask)
	lawn_mask = np.max(np.array(lawn_masks), axis = 0)
	return lawn_mask
Exemplo n.º 11
0
 def queryModelMask(self, image, delta=None):
     if self.model is None:
         return
     delta = self.queryModelDelta(image) if delta is None else delta.astype(numpy.float32)
     if self.input_antimask is not None:
         delta[self.input_antimask] = 0
     threshold = numpy.percentile(numpy.abs(delta), 97.5).astype(numpy.float32)
     mask = delta >= threshold
     mask = zplib_image_mask.get_largest_object(mask)
     #       mask[~zplib_image_mask.get_largest_object(mask)] = 0 # Remove dust from mask
     return mask
Exemplo n.º 12
0
def clean_dust_and_holes(dusty_pic):
    '''
	Picks out the largest object in dusty_mask and fills in its holes, returning cleaned_mask.
	'''
    my_dtype = dusty_pic.dtype
    dust_mask = np.invert(zplib_image_mask.get_largest_object(dusty_pic))
    dusty_pic[dust_mask] = 0
    cleaned_mask = simple_floor(
        zplib_image_mask.fill_small_area_holes(dusty_pic,
                                               90000).astype(my_dtype), 1)
    return cleaned_mask
Exemplo n.º 13
0
	def worm_candidate(my_edges, center_pixel, iterations):
		'''
		Find a candidate worm.
		'''
		harder_eggs = scipy.ndimage.morphology.binary_dilation(my_edges, iterations = iterations)
		harder_eggs = scipy.ndimage.morphology.binary_fill_holes(harder_eggs)
		harder_eggs = scipy.ndimage.morphology.binary_erosion(harder_eggs, iterations = iterations)
		if np.bincount(np.ndarray.flatten(harder_eggs)).shape[0] == 1:
			harder_eggs[center_pixel[0], center_pixel[1]] = True
		the_worm = zplib_image_mask.get_largest_object(harder_eggs).astype('bool')
		return the_worm
Exemplo n.º 14
0
		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
Exemplo n.º 15
0
        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
Exemplo n.º 16
0
def make_mega_lawn(worm_subdirectory, super_vignette):
	'''
	Make a mega lawn mask for use with all images of a worm. This avoids problems with detecting the relatively faint edge of the lawn, which depends on the exact focus plane and the brightness of the lamp.
	'''
	# Parallelized edge detection.
	my_bf_files = [worm_subdirectory + os.path.sep + a_bf for a_bf in os.listdir(worm_subdirectory) if a_bf[-6:] == 'bf.png']
	my_workers = min(multiprocessing.cpu_count() - 1, 60)
	chunk_size = int(np.ceil(len(my_bf_files)/my_workers))
	bf_chunks = [my_bf_files[x:x + chunk_size] for x in range(0, len(my_bf_files), chunk_size)]
	with concurrent.futures.ProcessPoolExecutor(max_workers = my_workers) as executor:
		chunk_masks = [executor.submit(lawn_maker, bf_chunks[i], super_vignette.copy()) for i in range(0, len(bf_chunks))]
	concurrent.futures.wait(chunk_masks)
	chunk_masks = [a_job.result() for a_job in chunk_masks]
	
	# Make mega lawn from edge detection.
	mega_lawn = np.max(np.array(chunk_masks), axis = 0)
	mega_lawn = scipy.ndimage.morphology.binary_fill_holes(mega_lawn).astype('bool')
	mega_lawn = zplib_image_mask.get_largest_object(mega_lawn).astype('uint8')
	mega_lawn[mega_lawn > 0] = -1	
	
	# Parallelized thresholding.
	with concurrent.futures.ProcessPoolExecutor(max_workers = my_workers) as executor:
		chunk_masks = [executor.submit(alternate_lawn_maker, bf_chunks[i], super_vignette.copy()) for i in range(0, len(bf_chunks))]
	concurrent.futures.wait(chunk_masks)
	chunk_masks = [a_job.result() for a_job in chunk_masks]			
		
	# Make alternative mega lawn from thresholding intensity.
	alt_mega_lawn = np.max(np.array(chunk_masks), axis = 0)
	alt_mega_lawn = scipy.ndimage.morphology.binary_fill_holes(alt_mega_lawn).astype('bool')
	alt_mega_lawn = zplib_image_mask.get_largest_object(alt_mega_lawn).astype('uint8')
	alt_mega_lawn[alt_mega_lawn > 0] = -1
	
	# Select proper mega lawn.
	if np.bincount(np.ndarray.flatten(mega_lawn))[-1] < 0.8*np.bincount(np.ndarray.flatten(alt_mega_lawn))[-1]:
		mega_lawn = alt_mega_lawn
	freeimage.write(mega_lawn, worm_subdirectory + os.path.sep + 'great_lawn.png')
	return mega_lawn
 def get_mask(self, position_root, derived_root, timepoint, annotations):
     mask_file = derived_root / 'mask' / position_root.name / f'{timepoint} {self.mask_name}.png'
     if not mask_file.exists():
         print(
             f'No mask file found for {position_root.name} at {timepoint}.')
         return None
     else:
         mask = freeimage.read(mask_file)
         if mask.sum() == 0:
             print(
                 f'No worm region defined for {position_root.name} at {timepoint}'
             )
             return None
         else:
             mask = zpl_mask.get_largest_object(mask,
                                                structure=numpy.ones(
                                                    (3, 3)))
             return mask
Exemplo n.º 18
0
def fill_colored_outline(an_image, outline_only = False, egg_mode = False):
	'''
	Fill out a colored outline and return a mask.
	'''
	# Get rid of the alpha channel.
	an_image = an_image.copy()
	an_image[:, :, 3] = 0
	
	# Get pixels with disproportionately more red.	
	my_mask = np.abs(np.max(an_image[:, :, 1:], axis = 2).astype('float64') - an_image[:, :, 0].astype('float64')).astype('uint16') > 0
	if not egg_mode:
		my_mask = zplib_image_mask.get_largest_object(my_mask)	
	
	# Fill holes.
	if not outline_only:		
		my_mask = zplib_image_mask.fill_small_area_holes(my_mask, 300000).astype('uint8')
	my_mask = my_mask.astype('uint8')
	my_mask[my_mask >= 1] = -1 
	return my_mask
Exemplo n.º 19
0
def find_lawn_in_image(image, optocoupler, return_model=False):
    """Find a lawn in an image use Gaussian mixture modeling (GMM)

    This lawn maker models an image (i.e. its pixel intensities) as as mixture
        of two Gaussian densities. Each corresponds to either the background & lawn.

    Parameters:
        image: numpy ndarray of the image to find the lawn from
        optocoupler: optocoupler magnification (as a float) used for the specified image
        return model: if True, return the GMM fit to the images.

    Returns: lawn_mask or (lawn_mask, gmm_model)
        lawn mask: bool ndarray
        gmm_model: if return_model is True, also return the fitted GMM model
    """
    filtered_image = ndimage.filters.median_filter(image,
                                                   size=(3, 3),
                                                   mode='constant')
    vignette_mask = process_images.vignette_mask(optocoupler, image.shape)

    img_data = filtered_image[vignette_mask]
    gmm = mixture.GaussianMixture(n_components=2)
    gmm.fit(numpy.expand_dims(img_data, 1))

    # Calculate boundary point for label classification as intensity threshold
    gmm_support = numpy.linspace(0, 2**16 - 1, 2**16)

    labels = gmm.predict(numpy.reshape(gmm_support, (-1, 1)))
    thr = numpy.argmax(numpy.abs(numpy.diff(labels)))
    lawn_mask = (filtered_image < thr) & vignette_mask

    # Smooth the lawn mask by eroding, grabbing the largest object, and dilating back
    lawn_mask = ndimage.morphology.binary_erosion(lawn_mask, iterations=10)
    lawn_mask = zpl_mask.get_largest_object(lawn_mask)
    lawn_mask = ndimage.morphology.binary_fill_holes(lawn_mask)
    lawn_mask = ndimage.morphology.binary_dilation(lawn_mask, iterations=10)

    if return_model:
        return lawn_mask, gmm
    else:
        return lawn_mask
Exemplo n.º 20
0
def lawn_distribution(lawn_folder):
	'''
	Find the distribution of lawn sizes in a folder.
	'''
	def size_object(a_mask):
		'''
		Find the two points farthest apart in a mask and return their distance from each other.
		'''
		locations = np.array(np.ma.nonzero(a_mask)).transpose()
		random_point = locations[0]
		point_a = locations[np.linalg.norm(locations - random_point, axis = 1).argmax()]
		point_b = locations[np.linalg.norm(locations - point_a, axis = 1).argmax()]
		my_distance = np.linalg.norm(point_a - point_b)
		return my_distance
	
	my_lawns = [freeimage.read(lawn_folder + os.path.sep + an_image).astype('bool') for an_image in os.listdir(lawn_folder) if an_image != 'vignette_mask.png']
	my_lawns = [zplib_image_mask.get_largest_object(my_lawn).astype('bool') for my_lawn in my_lawns]
	my_vignette = freeimage.read(lawn_folder + os.path.sep + 'vignette_mask.png').astype('bool')

	lawn_sizes = [size_object(my_lawn) for my_lawn in my_lawns]
	field_size = size_object(my_vignette)
	return (lawn_sizes, field_size)
Exemplo n.º 21
0
def clean_mask(img):
    '''Clean spurious edges/unwanted things from the masks 
    
    Parameters:
    ------------
    img: array_like (cast to booleans) shape (n,m) 
        Binary image of the worm mask

    Returns:
    -----------
    mask: array_like (cast to booleans) shape (n,m) 
        Binary image of the worm mask without spurious edges
    '''
    #clean up holes in the mask
    img = mask.fill_small_radius_holes(img, 2)
    #dilate/erode to get rid of spurious edges for the mask
    curve_morph = active_contour.CurvatureMorphology(mask=img)
    #TODO: multiple iterations of erode
    curve_morph.erode()
    curve_morph.dilate()
    curve_morph.smooth(iters=2)
    return mask.get_largest_object(curve_morph.mask)
Exemplo n.º 22
0
def backup_worm_find(my_edges, bg_center):
	'''
	If my edge detection doesn't find something close enough to the background mask, take more drastic action.
	'''
	def worm_candidate(my_edges, center_pixel, iterations):
		'''
		Find a candidate worm.
		'''
		harder_eggs = scipy.ndimage.morphology.binary_dilation(my_edges, iterations = iterations)
		harder_eggs = scipy.ndimage.morphology.binary_fill_holes(harder_eggs)
		harder_eggs = scipy.ndimage.morphology.binary_erosion(harder_eggs, iterations = iterations)
		if np.bincount(np.ndarray.flatten(harder_eggs)).shape[0] == 1:
			harder_eggs[center_pixel[0], center_pixel[1]] = True
		the_worm = zplib_image_mask.get_largest_object(harder_eggs).astype('bool')
		return the_worm
	
	# Get the eggs that have been edge-detected as closed shapes.
	center_pixel = (my_edges.shape[0]//2, my_edges.shape[1]//2)
	easy_eggs = scipy.ndimage.morphology.binary_fill_holes(my_edges)
	if np.bincount(np.ndarray.flatten(easy_eggs)).shape[0] == 1:
		easy_eggs[center_pixel[0], center_pixel[1]] = True
	easy_worm = zplib_image_mask.get_largest_object(easy_eggs).astype('bool')

	# Get the more difficult eggs and the worm itself.
	worm_candidates = [easy_worm]
	worm_candidates.extend([worm_candidate(my_edges, center_pixel, i) for i in range(3, 11)])
	worm_centers = np.array([np.mean(np.array(np.where(worm_candidate > 0)), axis = 1) for worm_candidate in worm_candidates])
	worm_distances = [np.linalg.norm(worm_center - bg_center) for worm_center in worm_centers]

	the_worm = None
	done_yet = False	
	for i in range(0, len(worm_candidates)):
		if not done_yet:
			if worm_distances[i] < 20:
				done_yet = True
				the_worm = worm_candidates[i]
				the_worm = scipy.ndimage.morphology.binary_fill_holes(the_worm)	
	return the_worm
    def stop_editing(self, save_work=True):
        # Convert outline to mask
        outline = zplib_image_mask.get_largest_object(
            self.rw.layers[1].image.data > 0)
        new_mask = zplib_image_mask.fill_small_area_holes(
            outline, 300000).astype('uint8')
        new_mask[new_mask > 0] = -1
        self.rw.layers[1].image.set(data=(new_mask > 0).astype('bool'))
        self.rw.layers[1].tint = (1.0, 1.0, 1.0, 1.0)

        self.rw.qt_object.layer_stack_painter_dock_widget.hide()
        if self.current_page[1].data.any():
            if not pathlib.Path(
                    str(self.working_file).replace('mask.png',
                                                   'mask_oldwf.png')).exists():
                self.working_file.rename(
                    str(self.working_file).replace('mask.png',
                                                   'mask_oldwf.png'))
            freeimage.write(new_mask, self.working_file)

        self.editing = False
        self.working_file = None  # Do this after saving out since need the working file above
        self.edit.setText('Edit Mask')
Exemplo n.º 24
0
def find_eggs_worm(worm_image, super_vignette, mega_lawn, worm_sigma):
	'''
	Solve the segmentation problem that has been giving me hives for months in a weekend...
	'''
	# Prepare for edge detection by renormalizing and denoising image.
	worm_image = worm_image.copy()
	worm_image = cv2.medianBlur(worm_image, 3)
	worm_image = imageOperations.renormalize_image(worm_image)
	renormalized_image = worm_image

	# Find non-lawn and vignetting artifacts, and prepare to remove lawn and vignette edges.
	ultra_vignette = scipy.ndimage.morphology.binary_erosion(super_vignette, iterations = 10)
	
	# Do the actual edge detection in search of the worm.
	my_edges = skimage.feature.canny(renormalized_image, sigma = worm_sigma)
	my_edges[np.invert(ultra_vignette)] = False 
	my_edges[np.invert(mega_lawn)] = False
	
	# Get the eggs that have been edge-detected as closed shapes.
	center_pixel = (worm_image.shape[0]//2, worm_image.shape[1]//2)
	easy_eggs = scipy.ndimage.morphology.binary_fill_holes(my_edges)
	(labels, region_indices, areas) = zplib_image_mask.get_areas(easy_eggs)
	keep_labels = areas > (1/(0.7**2))*270
	keep_labels = np.concatenate(([0], keep_labels))
	easy_eggs = keep_labels[labels].astype('bool')
	if np.bincount(np.ndarray.flatten(easy_eggs)).shape[0] == 1:
		easy_eggs[center_pixel[0], center_pixel[1]] = True	
	easy_worm = zplib_image_mask.get_largest_object(easy_eggs).astype('bool')

	# Get the more difficult eggs and the worm itself.
	harder_eggs = scipy.ndimage.morphology.binary_dilation(my_edges, iterations = 3)
	harder_eggs = scipy.ndimage.morphology.binary_fill_holes(harder_eggs)
	harder_eggs = scipy.ndimage.morphology.binary_erosion(harder_eggs, iterations = 3)
	harder_eggs[easy_eggs] = False
	(labels, region_indices, areas) = zplib_image_mask.get_areas(harder_eggs)
	keep_labels = areas > (1/(0.7**2))*270
	keep_labels = np.concatenate(([0], keep_labels))
	harder_eggs = keep_labels[labels].astype('bool')
	if np.bincount(np.ndarray.flatten(harder_eggs)).shape[0] == 1:
		harder_eggs[center_pixel[0], center_pixel[1]] = True
	the_worm = zplib_image_mask.get_largest_object(harder_eggs).astype('bool')
	if the_worm[the_worm].shape[0] < easy_worm[easy_worm].shape[0]:
		the_worm = easy_worm

	if the_worm[the_worm].shape[0] > 200000:
		lawn_edges = skimage.feature.canny(renormalized_image, sigma = 0.05)
		lawn_edges[np.invert(ultra_vignette)] = False 
		lawn_edges = scipy.ndimage.morphology.binary_dilation(lawn_edges, iterations = 10)
		my_lawn = scipy.ndimage.morphology.binary_fill_holes(lawn_edges)
		my_lawn = zplib_image_mask.get_largest_object(my_lawn).astype('bool')
		my_lawn = scipy.ndimage.morphology.binary_erosion(my_lawn, iterations = 10)
		lawn_transform = scipy.ndimage.morphology.distance_transform_edt(my_lawn)
		my_lawn_edge = np.zeros(my_lawn.shape).astype('bool')
		my_lawn_edge[lawn_transform > 0] = True 	
		my_lawn_edge[lawn_transform > 6] = False 	
		
		# Do the actual edge detection in search of the worm.
		my_edges = skimage.feature.canny(renormalized_image, sigma = 2.0)
		my_edges[np.invert(ultra_vignette)] = False 
		my_edges[np.invert(mega_lawn)] = False
		my_edges[my_lawn_edge] = False
		
		# Get the eggs that have been edge-detected as closed shapes.
		center_pixel = (worm_image.shape[0]//2, worm_image.shape[1]//2)
		easy_eggs = scipy.ndimage.morphology.binary_fill_holes(my_edges)
		(labels, region_indices, areas) = zplib_image_mask.get_areas(easy_eggs)
		keep_labels = areas > (1/(0.7**2))*270
		keep_labels = np.concatenate(([0], keep_labels))
		easy_eggs = keep_labels[labels].astype('bool')
		if np.bincount(np.ndarray.flatten(easy_eggs)).shape[0] == 1:
			easy_eggs[center_pixel[0], center_pixel[1]] = True	
		easy_worm = zplib_image_mask.get_largest_object(easy_eggs).astype('bool')
		
		# Get the more difficult eggs and the worm itself.
		harder_eggs = scipy.ndimage.morphology.binary_dilation(my_edges, iterations = 3)
		harder_eggs = scipy.ndimage.morphology.binary_fill_holes(harder_eggs)
		harder_eggs = scipy.ndimage.morphology.binary_erosion(harder_eggs, iterations = 3)
		harder_eggs[easy_eggs] = False
		(labels, region_indices, areas) = zplib_image_mask.get_areas(harder_eggs)
		keep_labels = areas > (1/(0.7**2))*270
		keep_labels = np.concatenate(([0], keep_labels))
		harder_eggs = keep_labels[labels].astype('bool')
		if np.bincount(np.ndarray.flatten(harder_eggs)).shape[0] == 1:
			harder_eggs[center_pixel[0], center_pixel[1]] = True
		the_worm = zplib_image_mask.get_largest_object(harder_eggs).astype('bool')
		if the_worm[the_worm].shape[0] < easy_worm[easy_worm].shape[0]:
			the_worm = easy_worm		

	# Clean up worm and eggs.
	the_worm = scipy.ndimage.morphology.binary_fill_holes(the_worm)	
	harder_eggs[the_worm] = False
	easy_eggs[the_worm] = False
	
	# Combine the two groups of eggs.
	all_eggs = np.zeros(harder_eggs.shape).astype('bool')
	all_eggs[harder_eggs] = True
	all_eggs[easy_eggs] = True	
	return (all_eggs, the_worm, my_edges)
def ensure_human(human_dir, work_dir, data_dir):
	'''
	Make sure that the human data directory, human_dir, has everything it needs from the working directory (namely properly corrected bf images and rough background subtraction masks).
	'''
	def test_and_copy(test_file, found_file):
		'''
		Check for test_file file in human_dir, then copy them over from found_file in work_dir if needed.
		'''
		if not os.path.isfile(test_file):
			print('Missing ' + test_file.split(' ')[-1] + ' at ' + test_file + '.')
			if os.path.isfile(found_file):
				print('\tFound corresponding ' + found_file.split(' ')[-1] + ' at ' + found_file + '.')
				print('\tCopying file...')
				shutil.copyfile(found_file, test_file)
				if os.path.isfile(test_file):
					print('\tSuccess!')
				else:
					raise BaseException('\tCOPYING FAILED.')
			else:
				raise BaseException('\tCouldn\'t find corresponding file.')
		return
		
	points_list = []
	for a_subdir in os.listdir(human_dir):
		human_subdir = human_dir + os.path.sep + a_subdir
		for a_file in os.listdir(human_subdir):
			if a_file.split('.')[-1] == 'png':
				file_split = a_file.split(' ')
				points_list.append(a_subdir + os.path.sep + file_split[0])
	points_list = sorted(list(set(points_list)))

	for a_point in points_list:
		# Set up some variables and copy metadata.
		(a_subdir, the_point) = a_point.split(os.path.sep)
		human_subdir = human_dir + os.path.sep + a_subdir
		working_subdir = work_dir + os.path.sep + a_subdir.split(' ')[-1]
		data_subdir = data_dir + os.path.sep + a_subdir.split(' ')[-1]
		base_metadata = human_subdir + os.path.sep + 'position_metadata.json'
		found_metadata = data_subdir + os.path.sep + 'position_metadata.json'
		test_and_copy(base_metadata, found_metadata)

		# Clean up human mask.
		base_test = human_subdir + os.path.sep + the_point
		base_found = working_subdir + os.path.sep + the_point
		test_and_copy(base_test + ' ' + 'hmask.png', base_test + ' ' + 'outline.png')
		print('Cleaning up ' + base_test + ' ' + 'hmask.png' + '.')
		old_mask = freeimage.read(base_test + ' ' + 'hmask.png')
		my_mask = np.zeros(old_mask.shape[:2]).astype('uint8')
		if len(old_mask.shape) == 3:
			my_mask[np.max(old_mask[:, :, :3], axis = 2).astype('float64') > 0] = -1
		elif len(old_mask.shape) == 2:
			my_mask[old_mask > 0] = -1
		else:
			raise ValueError(base_test + ' ' + 'hmask.png' + 'does not have proper dimensions.')
		my_mask[np.invert(zplib_image_mask.get_largest_object(my_mask) > 0)] = 0
		freeimage.write(my_mask, base_test + ' ' + 'hmask.png')

		# Clean up old stuff.
		if os.path.isfile(base_test + ' ' + 'bf.png'):
			os.remove(base_test + ' ' + 'bf.png')
		if os.path.isfile(base_test + ' ' + 'outline.png'):
			os.remove(base_test + ' ' + 'outline.png')

		# Copy over other test masks.
		test_and_copy(base_test + ' ' + 'bf.png', base_found + ' ' + 'bf.png')
		test_and_copy(base_test + ' ' + 'mask.png', base_found + ' ' + 'mask.png')
	return
Exemplo n.º 26
0
def process_position_directory(position_directory,
                               channels_to_process,
                               save_directory=None,
                               remake_masks=False,
                               enable_gpu=False,
                               model_path=None):
    """Process a position directory by starting a server for the segmenter
        and feeding it images to process on the fly.
        
        Parameters
            position_directory - str/pathlib.Path to position directory
            channels_to_process - list of str image identifiers to process 
                into masks;
            save_directory - optional str/pathlib.Path where masks will be
                saved
            remake_masks - optional bool flag to denote whether the segmenter
                should remake masks for images that have already been processed
            enable_gpu - optional bool flag to turn on GPU compatibility;
                as of matconvnet-1.0-beta25, there's a bug in matconvnet
                such that mex code compiled with gpu support doesn't work
                when the computer doesn't have a gpu; thus, for cluster computing
                and working on other computers, set this to False to use
                the alternate build of the segmentation code
        
        TODO: 
            Refactor to use load_data.scan_experiment_dir??
            Clean up save_directory business - should this even be exposed?
    """

    position_directory = pathlib.Path(position_directory)

    if save_directory is None:
        experiment_directory = position_directory.parent
        position = position_directory.name

        save_directory = experiment_directory / 'derived_data' / 'mask' / position
    else:
        save_directory = pathlib.Path(save_directory)

    # Make sure that the save directory exists
    try:
        save_directory.mkdir()
    except FileExistsError:
        pass

    if model_path is None:
        model_path = base_dir / DEFAULT_MODEL

    if not enable_gpu:
        # TODO force no gpu #if 'centos' in platform.platform()?
        build_name = 'processImageBatch_nogpu'
    else:
        build_name = 'processImageBatch'
    exe_path = (
        base_dir /
        f'matlab_compiled/{build_name}/for_redistribution_files_only/{build_name}'
    )

    try:
        position_annotations = load_data.read_annotation_file(
            position_directory.parent / 'annotations' /
            (position_directory.stem + '.pickle'))
    except:
        print(position_directory.stem, ' does not have annotation')
        return

    # Enumerate files to process
    files_to_process = []
    for image_file in sorted(list(position_directory.iterdir())):
        if image_file.suffix[1:] in ['png', 'tiff']:
            MASK_FILE_EXISTS = (save_directory / image_file.name).exists()
            IS_GOOD_CHANNEL = image_file.stem.split(
                ' ')[-1] in channels_to_process
            #IS_ALIVE = position_annotations[1][image_file.stem.split(' ')[0]]['stage'] != 'dead'
            #IS_ADULT = position_annotations[1][image_file.stem.split(' ')[0]]['stage'] == 'adult'

            #if (remake_masks or not MASK_FILE_EXISTS) and IS_GOOD_CHANNEL and IS_ADULT:
            if (remake_masks or not MASK_FILE_EXISTS) and IS_GOOD_CHANNEL:
                files_to_process.append(image_file)
    print("Files to process: ", files_to_process[0])
    if len(files_to_process) == 0:
        print(f'No files to process for position {position_directory.name}')
        return

    # Write out tempfile
    with (position_directory /
          'image_manifest.txt').open('w') as manifest_file:
        for my_file in files_to_process:
            manifest_file.write(str(my_file) + '\n')
            manifest_file.write(str(save_directory / my_file.name) + '\n')

    print('Starting batch segmentation')
    subprocess.run([
        str(exe_path),
        str(position_directory / 'image_manifest.txt'),
        str(int(enable_gpu)),
        str(model_path)
    ],
                   env=exe_env)

    # Post-process written images to get just the largest component
    with (position_directory / 'image_manifest.txt').open('r') as mf_stream:
        mask_files = map(str.rstrip, mf_stream.readlines()[1::2])
    for mask_file in mask_files:
        if pathlib.Path(mask_file).exists():
            mask_image = freeimage.read(mask_file) > 0
            new_mask = mask.get_largest_object(mask_image).astype(np.uint8)
            freeimage.write(new_mask * 255, mask_file)
        else:
            print(f'No mask region found for {mask_file}')
Exemplo n.º 27
0
def find_worm_from_fluorescence(image, low_pct=99.2, high_pct=99.99, max_hole_radius=12):
    low_thresh, high_thresh = numpy.percentile(image, [low_pct, high_pct])
    worm_mask = mask.hysteresis_threshold(image, low_thresh, high_thresh)
    worm_mask = mask.fill_small_radius_holes(worm_mask, max_hole_radius)
    worm_mask = mask.get_largest_object(worm_mask)
    return worm_mask
Exemplo n.º 28
0
def ensure_human(human_dir, work_dir, data_dir):
    '''
	Make sure that the human data directory, human_dir, has everything it needs from the working directory (namely properly corrected bf images and rough background subtraction masks).
	'''
    def test_and_copy(test_file, found_file):
        '''
		Check for test_file file in human_dir, then copy them over from found_file in work_dir if needed.
		'''
        if not os.path.isfile(test_file):
            print('Missing ' + test_file.split(' ')[-1] + ' at ' + test_file +
                  '.')
            if os.path.isfile(found_file):
                print('\tFound corresponding ' + found_file.split(' ')[-1] +
                      ' at ' + found_file + '.')
                print('\tCopying file...')
                shutil.copyfile(found_file, test_file)
                if os.path.isfile(test_file):
                    print('\tSuccess!')
                else:
                    raise BaseException('\tCOPYING FAILED.')
            else:
                raise BaseException('\tCouldn\'t find corresponding file.')
        return

    points_list = []
    for a_subdir in os.listdir(human_dir):
        human_subdir = human_dir + os.path.sep + a_subdir
        for a_file in os.listdir(human_subdir):
            if a_file.split('.')[-1] == 'png':
                file_split = a_file.split(' ')
                points_list.append(a_subdir + os.path.sep + file_split[0])
    points_list = sorted(list(set(points_list)))

    for a_point in points_list:
        # Set up some variables and copy metadata.
        (a_subdir, the_point) = a_point.split(os.path.sep)
        human_subdir = human_dir + os.path.sep + a_subdir
        working_subdir = work_dir + os.path.sep + a_subdir.split(' ')[-1]
        data_subdir = data_dir + os.path.sep + a_subdir.split(' ')[-1]
        base_metadata = human_subdir + os.path.sep + 'position_metadata.json'
        found_metadata = data_subdir + os.path.sep + 'position_metadata.json'
        test_and_copy(base_metadata, found_metadata)

        # Clean up human mask.
        base_test = human_subdir + os.path.sep + the_point
        base_found = working_subdir + os.path.sep + the_point
        test_and_copy(base_test + ' ' + 'hmask.png',
                      base_test + ' ' + 'outline.png')
        print('Cleaning up ' + base_test + ' ' + 'hmask.png' + '.')
        old_mask = freeimage.read(base_test + ' ' + 'hmask.png')
        my_mask = np.zeros(old_mask.shape[:2]).astype('uint8')
        if len(old_mask.shape) == 3:
            my_mask[
                np.max(old_mask[:, :, :3], axis=2).astype('float64') > 0] = -1
        elif len(old_mask.shape) == 2:
            my_mask[old_mask > 0] = -1
        else:
            raise ValueError(base_test + ' ' + 'hmask.png' +
                             'does not have proper dimensions.')
        my_mask[np.invert(
            zplib_image_mask.get_largest_object(my_mask) > 0)] = 0
        freeimage.write(my_mask, base_test + ' ' + 'hmask.png')

        # Clean up old stuff.
        if os.path.isfile(base_test + ' ' + 'bf.png'):
            os.remove(base_test + ' ' + 'bf.png')
        if os.path.isfile(base_test + ' ' + 'outline.png'):
            os.remove(base_test + ' ' + 'outline.png')

        # Copy over other test masks.
        test_and_copy(base_test + ' ' + 'bf.png', base_found + ' ' + 'bf.png')
        test_and_copy(base_test + ' ' + 'mask.png',
                      base_found + ' ' + 'mask.png')
    return