def filter_blend_z_membrane(a_membrane, a_raw, a_threshold, a_exterior_mask, kwargs, df_thresholds, p_out=None): """ a_membrane = the binary membrane stack a_raw = the image stack (raw) a_threshold= the thresholded stack (=the otsu cutoff) a_exterior_mask = the exterior mask """ a_peaks_flooded, d_log = locate_z_membrane(a_raw=a_raw, a_membrane_mask=np.where( a_threshold, 0, 1), a_exterior_mask=a_exterior_mask, df_thresholds=df_thresholds, **kwargs) # z-membrane gets '3' as a value, just for ease of indentification a_membrane_blend_z = np.where(a_peaks_flooded, 3, a_membrane) # keep empty slices empty a_membrane_blend_z[np.sum(a_membrane, axis=(1, 2)) == 0] = 0 if p_out: with warnings.catch_warnings(): p_out.parent.mkdir(parents=True, exist_ok=True) imsave_fiji(p_out, a_membrane_blend_z.astype('uint16')) return a_membrane_blend_z, d_log
def get_exterior_mask(a_stack, p_out=None, verbose=False): ''' This filter will build a non-convex exterior mask based on the alpha-complex approach. After Delaunay triangulation, exterior triangles are filtered out by checking if their circumcenter falls inside the convex hull. The outline of the interior triangles is then retrieved and a mask is created This approach can be an alternative for the active contour, In theory the same approach could be applied in 3D, but runtime is a bottleneck given the large amount of circumcenters""" ''' a_exterior_mask = np.zeros(a_stack.shape, dtype='uint16') prev_slice = None with warnings.catch_warnings(): warnings.simplefilter("ignore") for ix_slice, a_slice in enumerate(a_stack): if not a_slice.any(): a_exterior_mask[ix_slice] = a_slice try: a_points = _downsample_membrane_points(a_slice) a_circumcenters, a_circumradii, tri = _get_voronoi_points( a_points) a_selector_inside_hull, hull = _test_points_inside_convex_hull( a_check=a_circumcenters, a_points_hull=a_points) a_non_convex_hull_simplices = \ tri.simplices[a_selector_inside_hull] a_boundary_edges = _get_boundary_edges( a_non_convex_hull_simplices) l_polygon_loop = _get_polygon_loop(a_boundary_edges, verbose=False) # orders matters, has to be sequential outline of a polygon a_exterior_mask[ix_slice] = polygon2mask( a_slice.shape, a_points[l_polygon_loop]) prev_slice = a_exterior_mask[ix_slice] except Exception as e: # traceback.print_exc() if prev_slice is not None and prev_slice.any(): if verbose: print(f"{ix_slice}<", end="") a_exterior_mask[ix_slice] = prev_slice else: if verbose: print(f"{ix_slice}x", end="") a_exterior_mask[ix_slice] = a_slice if p_out: with warnings.catch_warnings(): p_out.parent.mkdir(parents=True, exist_ok=True) imsave_fiji(p_out, a_exterior_mask.astype('uint16')) return a_exterior_mask
def filter_rescale(stack, kwargs, p_out=None): l_out = zoom_data(stack, verbose=False, **kwargs) img_rescaled, zoom, spacing = l_out if p_out: with warnings.catch_warnings(): p_out.parent.mkdir(parents=True, exist_ok=True) imsave_fiji(p_out, img_rescaled.astype('uint16')) return img_rescaled, zoom
def filter_remove_small_objects(a_stack, kwargs, p_out=None): ''' Clean up : remove 3D blobs ''' remove_small_objects(a_stack.astype(bool), in_place=True, **kwargs) if p_out: with warnings.catch_warnings(): p_out.parent.mkdir(parents=True, exist_ok=True) imsave_fiji(p_out, a_stack.astype('uint16')) return a_stack
def filter_frangi(a_stack, kwargs, scale_max=True, p_out=None): a_frangi = np.zeros(a_stack.shape, dtype='float32') for ix_slice, a_slice in enumerate(a_stack): a_frangi[ix_slice] = frangi(a_slice, **kwargs) if scale_max: if np.max(a_frangi) > 0: a_frangi = a_frangi * (10000 / np.max(a_frangi)) if p_out: with warnings.catch_warnings(): p_out.parent.mkdir(parents=True, exist_ok=True) imsave_fiji(p_out, a_frangi.astype('float32')) return a_frangi
def filter_skeletonize(a_stack, p_out=None): ''' skeletonize a binary image ''' a_membrane = np.zeros(a_stack.shape, dtype='uint16') for ix_slice, a_slice in enumerate(a_stack): a_membrane[ix_slice] = skeletonize(a_slice) if p_out: with warnings.catch_warnings(): p_out.parent.mkdir(parents=True, exist_ok=True) imsave_fiji(p_out, a_membrane.astype('uint16')) return a_membrane
def filter_reconstruction(a_stack, df_thresholds, kwargs, p_out=None): ''' This is a downhill filter. It expects as input the frangi output ''' a_threshold = np.zeros(a_stack.shape, dtype='uint16') for ix_slice, a_slice in enumerate(a_stack): thresholds = df_thresholds.iloc[ix_slice] seed = a_slice.copy() if thresholds.has_signal: seed[seed < thresholds['abs_thresh_slice_seed']] = 0 a_threshold[ix_slice] = reconstruction( seed=seed, mask=a_slice, ** kwargs) >= thresholds['abs_thresh_slice'] else: a_threshold[ix_slice] = np.zeros_like(a_slice) if p_out: with warnings.catch_warnings(): p_out.parent.mkdir(parents=True, exist_ok=True) imsave_fiji(p_out, a_threshold.astype('uint16')) return a_threshold
def smooth_exterior_mask(a_exterior_mask, p_out=None, weight_center=3, weight_top_bottom=2, weight_left_right=1): """ smooths an exterior mask (entire time lapse), by default it will smooth over time""" # print("...Smoothing the exterior mask...", flush=True) a_ext_mask_smoothed = np.zeros_like(a_exterior_mask) single_stack = True if len(a_exterior_mask.shape) == 3 else False if not single_stack: t_dim, z_dim, _, _ = a_exterior_mask.shape else: z_dim, _, _ = a_exterior_mask.shape t_dim = 1 for t in range(t_dim): for z in range(z_dim): if single_stack: a_slice = a_exterior_mask[z, :] else: a_slice = a_exterior_mask[t, z, :] z_plus = 1 if z < z_dim - 1 else 0 t_plus = 1 if t < t_dim - 1 else 0 z_min = 1 if z > 0 else 0 t_min = 1 if t > 0 else 0 if single_stack: a_ext_mask_smoothed[z, :] \ = a_ext_mask_smoothed[z, :] + \ (a_slice * weight_center) a_ext_mask_smoothed[z - z_min, :] \ = a_ext_mask_smoothed[z - z_min, :] + \ (a_slice * weight_top_bottom) a_ext_mask_smoothed[z + z_plus, :] \ = a_ext_mask_smoothed[z + z_plus, :] +\ (a_slice * weight_top_bottom) else: a_ext_mask_smoothed[t, z, :] \ = a_ext_mask_smoothed[t, z, :] +\ (a_slice * weight_center) a_ext_mask_smoothed[t, z - z_min, :] \ = a_ext_mask_smoothed[t, z - z_min, :] +\ (a_slice * weight_top_bottom) a_ext_mask_smoothed[t, z + z_plus, :] \ = a_ext_mask_smoothed[t, z + z_plus, :] +\ (a_slice * weight_top_bottom) a_ext_mask_smoothed[t - t_min, z, :] \ = a_ext_mask_smoothed[t - t_min, z, :] +\ (a_slice * weight_left_right) a_ext_mask_smoothed[t + t_plus, z, :] \ = a_ext_mask_smoothed[t + t_plus, z, :] +\ (a_slice * weight_left_right) if single_stack: WEIGHT_THRESHOLD = (weight_center + 2 * (weight_top_bottom)) / 1.5 else: WEIGHT_THRESHOLD = (weight_center + 2 * (weight_top_bottom) + 2 * (weight_left_right)) / 1.5 a_ext_mask_smoothed_binary = a_ext_mask_smoothed > WEIGHT_THRESHOLD if p_out: with warnings.catch_warnings(): p_out.parent.mkdir(parents=True, exist_ok=True) imsave_fiji(p_out, a_ext_mask_smoothed_binary.astype('uint8')) return a_ext_mask_smoothed_binary