def close_binary(img_binary, k=5, plot=True, verbose=True): if verbose: print('\t - Closing holes with disk of radius %d' % k) opened = closing(img_binary, disk(k)) if plot: d.compare2(img_binary, opened, 'Closing: k = %d' % k) return opened
def open_binary(img_binary, k=5, plot=True, verbose=True): if verbose: print('\t - Removing artifacts with disk of radius %d' % k) opened = opening(img_binary, disk(k)) if plot: d.compare2(img_binary, opened, 'Opening: k = %d' % k) return opened
def distance_transform(img_binary, plot=True, verbose=True): if verbose: print('\t - Calculating euclidean distance transform') img_dist = ndi.distance_transform_edt(img_binary) if plot: d.compare2(img_binary, img_dist, 'Euclidean Distance Transform') return img_dist
def skeleton(img_binary, plot=True, verbose=True): if verbose: print('\t - Thinning to skeleton') img_skel = skeletonize(img_binary, method='lee') if plot: d.compare2(img_binary, dilation(img_skel), 'Skeletonization (image dilated for viewing)') img_skel = img_skel / np.amax(img_skel) return img_skel
def black_top_hat(image, k=2, plot=False, verbose=True): if verbose: print('\t - Removing black holes using disk of radius %d' % k) res = black_tophat(image, disk(k)) if plot: d.compare3(image, res, image + res, title1='Original', title2='Black Top Hat', title3='Complimentary') return image + res
def white_top_hat(image, k=2, plot=False, verbose=True): if verbose: print('\t - Removing white peaks using disk of radius %d' % k) res = white_tophat(image, disk(k)) if plot: d.compare3(image, res, image - res, title1='Original', title2='White Top Hat', title3='Complimentary') return image - res
def contrasts(img, plot=True, adpt=0.04): # Contrast stretching p2, p98 = np.percentile(img, (2, 98)) img_rescale = exposure.rescale_intensity(img, in_range=(p2, p98)) # Equalization img_eq = exposure.equalize_hist(img) # Adaptive Equalization img_adapteq = exposure.equalize_adapthist(img, clip_limit=adpt) if plot: # Display results fig = plt.figure(figsize=(15, 15)) axes = np.zeros((2, 4), dtype=np.object) axes[0, 0] = fig.add_subplot(2, 4, 1) for i in range(1, 4): axes[0, i] = fig.add_subplot(2, 4, 1 + i, sharex=axes[0, 0], sharey=axes[0, 0]) for i in range(0, 4): axes[1, i] = fig.add_subplot(2, 4, 5 + i) ax_img, ax_hist, ax_cdf = d.plot_img_and_hist(img, axes[:, 0]) ax_img.set_title('Original image') y_min, y_max = ax_hist.get_ylim() ax_hist.set_ylabel('Number of pixels') ax_hist.set_yticks(np.linspace(0, y_max, 5)) ax_img, ax_hist, ax_cdf = d.plot_img_and_hist(img_rescale, axes[:, 1]) ax_img.set_title('Contrast stretching') ax_img, ax_hist, ax_cdf = d.plot_img_and_hist(img_eq, axes[:, 2]) ax_img.set_title('Histogram equalization') ax_img, ax_hist, ax_cdf = d.plot_img_and_hist(img_adapteq, axes[:, 3]) ax_img.set_title('Adaptive equalization') ax_cdf.set_ylabel('Fraction of total intensity') ax_cdf.set_yticks(np.linspace(0, 1, 5)) # prevent overlap of y-axis labels fig.tight_layout() plt.show() return img, img_rescale, img_eq, img_adapteq
def generate_surface(img_3d, iso=0, grad='descent', plot=True, offscreen=False, connected=True, clean=True, fill_internals=False, title=''): print('\t - Generating surface mesh') verts, faces, normals, values = measure.marching_cubes_lewiner(img_3d, iso, gradient_direction=grad) mesh = pymesh.form_mesh(verts, faces) vert_list = [] if clean: mesh, vert_list = clean_mesh(mesh, connected=connected, fill_internals=fill_internals) verts = mesh.vertices faces = mesh.faces if plot: d.visualize_mesh((verts, faces), offscreen=offscreen, title=title) return mesh, vert_list
def background_dilation(image, gauss=1 / 3, plot=True, verbose=True): if verbose: print( '\t - Extracting vessels from background and filtering with sigma=%0.4f' % gauss) if not gauss: return image image = img_as_float(image) image = gaussian_filter(image, gauss) seed = np.copy(image) seed[1:-1, 1:-1] = image.min() mask = image dilated = reconstruction(seed, mask, method='dilation') if plot: d.compare2(image, dilated, 'Reconstruction via Dilation') return dilated
def get_largest_connected_region(img_binary, plot=True, verbose=True): if verbose: print(' - Retaining only the largest connected region') img_lab = measure.label(img_binary, connectivity=2) regions = measure.regionprops(img_lab) val_max = 0 label_max = 0 for props in regions: if props.area > val_max: val_max = props.area label_max = props.label img_largest_binary = img_lab == label_max if plot: d.compare2(img_lab, img_largest_binary, 'Largest Connected Region', cmap='magma') return img_largest_binary
def std_2d_segment(tif_file, scale_xy, scale_z=1, h_pct=1, contrast_method='rescale', thresh_method='entropy', rwalk_thresh=(0, 0), bth_k=3, wth_k=3, dila_gauss=0.333, open_first=False, open_k=0, close_k=5, connected2D=False, smooth=1, all_plots=True, review_plot=True, output_dir='', name='', save_mask=False, save_skel=False, save_dist=False, save_disp=False, save_review=False, generate_mesh_25=True, connected_mesh=True, connected_vol=False, plot_25d=True, save_volume_mask=True, save_surface_meshes=True, generate_volume_meshes=False): img_original = ts(tif_file, page_list=False, flat=True) img_original_flat = img_original.get_flat() img_dim = img_original_flat.shape x_micron = img_original.downsample_factor * scale_xy[0] * img_dim[0] y_micron = img_original.downsample_factor * scale_xy[1] * img_dim[1] units = np.ceil(max(x_micron, y_micron) / 750) img_original.set_units(units) scale_xy = ( img_original.downsample_factor * scale_xy[0] / units, img_original.downsample_factor * scale_xy[1] / units) expt_z = len(img_original.get_pages())*scale_z/units print('NumPages: %d' % len(img_original.get_pages())) enhance_contrasts = st2.contrasts(img_original_flat, plot=all_plots, adpt=0.04) img_enhanced = enhance_contrasts[contrasts[contrast_method]] print('============') print('2d analysis:') print('============') print(' - Filtering the flattened image') img = st2.black_top_hat(img_enhanced, plot=all_plots, k=bth_k) img = st2.white_top_hat(img, plot=all_plots, k=wth_k) dilated = st2.background_dilation(img, gauss=dila_gauss, plot=all_plots) print(' - Converting to binary mask') if thresh_method == 'random-walk': low = rwalk_thresh[0] high = rwalk_thresh[1] img_mask = st2.random_walk_thresh(dilated, low, high, plot=all_plots) else: img_mask = st2.cross_entropy_thresh(dilated, plot=all_plots, verbose=False) print(' - Cleaning the binary mask') if open_first: img_mask = st2.open_binary(img_mask, k=open_k, plot=all_plots) img_mask = st2.close_binary(img_mask, k=close_k, plot=all_plots) else: img_mask = st2.close_binary(img_mask, k=close_k, plot=all_plots) img_mask = st2.open_binary(img_mask, k=open_k, plot=all_plots) if connected2D: img_mask = st2.get_largest_connected_region(img_mask, plot=all_plots) if scale_xy[0] != 1 or scale_xy[1] != 1: print(' - Scaling to %d um / pixel' % units) current_dim = img_mask.shape new_dim = (np.round(current_dim[0] * scale_xy[0]), np.round(current_dim[1] * scale_xy[1])) img_mask = transform.resize(img_mask, new_dim) img_enhanced = transform.resize(img_enhanced, new_dim) print('\t - Smoothing mask to reduce skeleton error') img_mask = filters.gaussian(img_mask, sigma=(smooth * scale_xy[0] / 3.0, smooth * scale_xy[1] / 3.0), preserve_range=True) img_mask = img_mask > np.mean(img_mask) print('\t\t - Using smooth=' + str(smooth) + ' coresponding to a gaussian filter of sigma=' + str('(%0.4f, %0.4f)' % (smooth * scale_xy[0] / 3.0, smooth * scale_xy[0] / 3.0))) print(' - Producing computationally useful transforms') img_skel = st2.skeleton(img_mask, plot=all_plots) img_dist = st2.distance_transform(img_mask, plot=all_plots) if all_plots or review_plot: d.review_2d_results(img_enhanced, img_mask, dilation(img_skel), img_dist, units=units) if save_mask: if not os.path.isdir(output_dir + 'masks2D/'): os.mkdir(output_dir + 'masks2D/') plt.imsave(output_dir + 'masks2D/' + name + ('-%dum-pix' % units) + '.png', img_mask, cmap='gray') if save_skel: if not os.path.isdir(output_dir + 'skels2D/'): os.mkdir(output_dir + 'skels2D/') plt.imsave(output_dir + 'skels2D/' + name + ('-%dum-pix' % units) + '.png', img_skel, cmap='gray') if save_dist: if not os.path.isdir(output_dir + 'distance2D/'): os.mkdir(output_dir + 'distance2D/') plt.imsave(output_dir + 'distance2D/' + name + ('-%dum-pix' % units) + '.png', img_dist, cmap='gray') if save_disp: if not os.path.isdir(output_dir + 'display/'): os.mkdir(output_dir + 'display/') plt.imsave(output_dir + 'display/' + name + ('-%dum-pix' % units) + '.png', img_enhanced, cmap='gray') if save_review: if not os.path.isdir(output_dir + 'review-segment2D/'): os.mkdir(output_dir + 'review-segment2D/') d.review_2d_results(img_enhanced, img_mask, dilation(img_skel), img_dist, saving=True, units=units).savefig( output_dir + 'review-segment2D/' + name + ('-%dum-pix' % units) + '.png') plt.show(block=False) plt.close() if generate_mesh_25: segment_2d_to_meshes(img_dist, img_skel, units=units, h_pct=h_pct, expt_z=expt_z, connected_mesh=connected_mesh, connected_vol=connected_vol, plot_25d=plot_25d, save_volume_mask=save_volume_mask, save_surface_meshes=save_surface_meshes, generate_volume_meshes=generate_volume_meshes, output_dir=output_dir, name=name) return img_enhanced, img_mask, img_skel, img_dist, img_original