def CTNNB1_HiPSC_Pipeline(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [4, 27] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 dot_2d_sigma = 1.5 dot_2d_cutoff = 0.01 minArea = 10 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio # smoothing structure_img_smooth = image_smoothing_gaussian_3d( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### response = dot_slice_by_slice(structure_img_smooth, log_sigma=dot_2d_sigma) bw = response > dot_2d_cutoff ################### # POST-PROCESSING ################### seg = remove_small_objects(bw, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = CTNNB1_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list
def Workflow_myh10(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [2.5, 17] vesselness_sigma_1 = [2] vesselness_cutoff_1 = 0.2 vesselness_sigma_2 = [1] vesselness_cutoff_2 = 0.015 minArea = 16 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) # smoothing structure_img_smooth = edge_preserving_smoothing_3d(struct_img) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # vesselness 3d response_1 = vesselness3D(structure_img_smooth, sigmas=vesselness_sigma_1, tau=1, whiteonblack=True) response_2 = vesselness3D(structure_img_smooth, sigmas=vesselness_sigma_2, tau=1, whiteonblack=True) bw = np.logical_or(response_1 > vesselness_cutoff_1, response_2 > vesselness_cutoff_2) ################### # POST-PROCESSING ################### seg = remove_small_objects(bw, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) elif output_type == 'array': return seg elif output_type == 'array_with_contour': return (seg, generate_segmentation_contour(seg)) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = MYH10_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list
def Workflow_fbl(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [0.5, 18] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 dot_2d_sigma = 1 dot_2d_cutoff = 0.01 minArea = 5 low_level_min_size = 700 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio # smoothing with gaussian filter structure_img_smooth = image_smoothing_gaussian_3d( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # step 1: low level thresholding #global_otsu = threshold_otsu(structure_img_smooth) global_tri = threshold_triangle(structure_img_smooth) global_median = np.percentile(structure_img_smooth, 50) th_low_level = (global_tri + global_median) / 2 bw_low_level = structure_img_smooth > th_low_level bw_low_level = remove_small_objects(bw_low_level, min_size=low_level_min_size, connectivity=1, in_place=True) # step 2: high level thresholding bw_high_level = np.zeros_like(bw_low_level) lab_low, num_obj = label(bw_low_level, return_num=True, connectivity=1) for idx in range(num_obj): single_obj = (lab_low == (idx + 1)) local_otsu = threshold_otsu(structure_img_smooth[single_obj]) bw_high_level[np.logical_and(structure_img_smooth > local_otsu, single_obj)] = 1 out_img_list.append(bw_high_level.copy()) out_name_list.append('interm_high') # step 3: finer segmentation response2d = dot_slice_by_slice(structure_img_smooth, log_sigma=dot_2d_sigma) bw_finer = remove_small_objects(response2d > dot_2d_cutoff, min_size=minArea, connectivity=1, in_place=True) out_img_list.append(bw_finer.copy()) out_name_list.append('bw_fine') # merge finer level detection into high level coarse segmentation to include outside dim parts bw_high_level[bw_finer > 0] = 1 ################### # POST-PROCESSING ################### seg = remove_small_objects(bw_high_level > 0, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_coarse') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = FBL_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list
def Workflow_dsp(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [8000] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 dot_3d_sigma = 1 dot_3d_cutoff = 0.012 minArea = 4 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio # smoothing with gaussian filter structure_img_smooth = image_smoothing_gaussian_slice_by_slice( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # step 1: LOG 3d response = dot_3d(structure_img_smooth, log_sigma=dot_3d_sigma) bw = response > dot_3d_cutoff bw = remove_small_objects(bw > 0, min_size=minArea, connectivity=1, in_place=False) out_img_list.append(bw.copy()) out_name_list.append('interm_mask') # step 2: 'local_maxi + watershed' for cell cutting local_maxi = peak_local_max(struct_img, labels=label(bw), min_distance=2, indices=False) out_img_list.append(local_maxi.copy()) out_name_list.append('interm_local_max') distance = distance_transform_edt(bw) im_watershed = watershed(-distance, label(dilation(local_maxi, selem=ball(1))), mask=bw, watershed_line=True) ################### # POST-PROCESSING ################### seg = remove_small_objects(im_watershed, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = DSP_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list
def Workflow_fbl_bright_v3(struct_img,mitotic_stage,rescale_ratio,output_type, output_path, fn, output_func=None): ''' no high level thresholindg is used - step2 ''' ########################################################################## # Basic PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [2, 8] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 dot_2d_sigma = 2 dot_2d_sigma_extra = 3 minArea = 8 low_level_min_size = 300 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio>0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8)/(struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio structure_img_smooth = edge_preserving_smoothing_3d(struct_img, numberOfIterations=10, conductance=1.2, timeStep=0.0625) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # # mitotic stage should align to folder name mito_seed_path_root = "/allen/aics/assay-dev/computational/data/Nucleus_structure_segmentation/trainset/FBL_norm1/mem/" mito_seed_path = mito_seed_path_root + fn.replace('.tiff', '.mem_seg.tiff') # mito_seed_path = '/allen/aics/assay-dev/computational/data/Nucleus_structure_segmentation/trainset/mem/mem.ome.tif' # Generate seed for mitotic cell mito_3d = imread(mito_seed_path) if np.ndim(mito_3d) == 4: mito_3d = mito_3d[:,:,:,0] bw_high_level = np.zeros_like(mito_3d) # lab_low, num_obj = label(bw_low_level, return_num=True, connectivity=1) object_img = structure_img_smooth[mito_3d>0] local_cutoff = 0.8* threshold_otsu(structure_img_smooth) otsu_mito = threshold_otsu(structure_img_smooth[mito_3d>0]) # pdb.set_trace() local_diff = (local_cutoff - otsu_mito) adaptive_factor = 0 local_otsu = 0 vessel_cutoff = 0.105 slice_cutoff = 0.04 # this is when FBL seg is very dim compared to rest if local_diff >= 0.15: vessel_cutoff = 0.04 slice_cutoff = 0.03 # When FBL seg is very brgiht elif local_diff < 0.05: vessel_cutoff = 0.105 slice_cutoff = 0.04 local_otsu = 1.7 * otsu_mito bw_high_level[np.logical_and(structure_img_smooth> local_otsu, mito_3d>0)]=1 res3 = vesselnessSliceBySlice(structure_img_smooth, [1], tau=0.5, whiteonblack=True) res1 = dot_slice_by_slice(structure_img_smooth, 2) response_bright = np.logical_or(res1>slice_cutoff,res3>vessel_cutoff) total_bright = np.logical_or(response_bright,bw_high_level) bw_final = total_bright ################### # POST-PROCESSING ################### seg = remove_small_objects(bw_final, min_size=minArea, connectivity=1, in_place=True) seg = seg>0 seg = seg.astype(np.uint8) seg[seg>0]=255 out_img_list.append(seg.copy()) out_name_list.append('bw_fine') fn = fn.replace('.tiff', '') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) elif output_type == 'return': return seg elif output_type == 'return_both': return (seg, mito_3d) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = NPM1_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list # pdb.set_trace()
def Workflow_lmnb1_mitotic(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [4000] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 f2_param = [[0.5, 0.01]] minArea = 5 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) # smoothing with boundary preserving smoothing structure_img_smooth = image_smoothing_gaussian_3d( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # 2d filament filter on the middle frame bw = filament_2d_wrapper(structure_img_smooth, f2_param) ################### # POST-PROCESSING ################### bw = remove_small_objects(bw > 0, min_size=minArea, connectivity=1, in_place=False) # output seg = bw > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) else: print('your can implement your output hook here, but not yet') quit()
def Workflow_lamp1(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_scaling_param = [3, 19] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 minArea = 15 ves_th_2d = 0.1 vesselness_sigma = [1] vesselness_cutoff = 0.15 #hole_min = 60 hole_max = 1600 log_sigma_1 = 5 log_cutoff_1 = 0.09 log_sigma_2 = 2.5 log_cutoff_2 = 0.07 log_sigma_3 = 1 log_cutoff_3 = 0.01 ########################################################################## out_img_list = [] out_name_list = [] # intenisty normalization struct_img = intensity_normalization(struct_img, scaling_param=intensity_scaling_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio structure_img_smooth = image_smoothing_gaussian_slice_by_slice( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') # spot detection response1 = dot_slice_by_slice(structure_img_smooth, log_sigma=log_sigma_1) bw1 = response1 > log_cutoff_1 response2 = dot_slice_by_slice(structure_img_smooth, log_sigma=log_sigma_2) bw2 = response2 > log_cutoff_2 bw_spot = np.logical_or(bw1, bw2) response3 = dot_slice_by_slice(structure_img_smooth, log_sigma=log_sigma_3) bw3 = response3 > log_cutoff_3 bw_spot = np.logical_or(bw_spot, bw3) # ring/filament detection ves = vesselnessSliceBySlice(structure_img_smooth, sigmas=vesselness_sigma, tau=1, whiteonblack=True) bw_ves = ves > vesselness_cutoff # fill holes partial_fill = np.logical_or(bw_spot, bw_ves) out_img_list.append(partial_fill.copy()) out_name_list.append('interm_before_hole') holes = np.zeros_like(partial_fill) for zz in range(partial_fill.shape[0]): background_lab = label(~partial_fill[zz, :, :], connectivity=1) out = np.copy(background_lab) component_sizes = np.bincount(background_lab.ravel()) too_big = component_sizes > hole_max too_big_mask = too_big[background_lab] out[too_big_mask] = 0 #too_small = component_sizes <hole_min #too_small_mask = too_small[background_lab] #out[too_small_mask] = 0 holes[zz, :, :] = out full_fill = np.logical_or(partial_fill, holes) seg = remove_small_objects(full_fill, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) elif output_type == 'array': return seg elif output_type == 'array_with_contour': return (seg, generate_segmentation_contour(seg)) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = LAMP1_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list
def Workflow_atp2a2(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [2.5, 9.0] vesselness_sigma = [1] vesselness_cutoff = 0.25 minArea = 15 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) # smoothing with boundary preserving smoothing structure_img_smooth = edge_preserving_smoothing_3d(struct_img) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # 2d vesselness slice by slice response = vesselnessSliceBySlice(structure_img_smooth, sigmas=vesselness_sigma, tau=1, whiteonblack=True) bw = response > vesselness_cutoff ################### # POST-PROCESSING ################### bw = remove_small_objects(bw > 0, min_size=minArea, connectivity=1, in_place=False) for zz in range(bw.shape[0]): bw[zz, :, :] = remove_small_objects(bw[zz, :, :], min_size=3, connectivity=1, in_place=False) seg = remove_small_objects(bw > 0, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = SEC61B_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list
def ST6GAL1_HiPSC_Pipeline(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [9, 19] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 cell_wise_min_area = 1200 dot_3d_sigma = 1.6 dot_3d_cutoff = 0.02 minArea = 10 thin_dist = 1 thin_dist_preserve = 1.6 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio # smoothing with gaussian filter structure_img_smooth = image_smoothing_gaussian_3d( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # cell-wise local adaptive thresholding th_low_level = threshold_triangle(structure_img_smooth) bw_low_level = structure_img_smooth > th_low_level bw_low_level = remove_small_objects(bw_low_level, min_size=cell_wise_min_area, connectivity=1, in_place=True) bw_low_level = dilation(bw_low_level, selem=ball(2)) bw_high_level = np.zeros_like(bw_low_level) lab_low, num_obj = label(bw_low_level, return_num=True, connectivity=1) for idx in range(num_obj): single_obj = lab_low == (idx + 1) local_otsu = threshold_otsu(structure_img_smooth[single_obj > 0]) bw_high_level[np.logical_and(structure_img_smooth > local_otsu * 0.98, single_obj)] = 1 # LOG 3d to capture spots response = dot_3d(structure_img_smooth, log_sigma=dot_3d_sigma) bw_extra = response > dot_3d_cutoff # thinning bw_high_level = topology_preserving_thinning(bw_high_level, thin_dist_preserve, thin_dist) # combine the two parts bw = np.logical_or(bw_high_level, bw_extra) ################### # POST-PROCESSING ################### seg = remove_small_objects(bw > 0, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = ST6GAL1_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list
def NPM1_HiPSC_Pipeline(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [0.5, 15] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 dot_2d_sigma = 2 dot_2d_sigma_extra = 1 dot_2d_cutoff = 0.025 minArea = 5 low_level_min_size = 700 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio # smoothing with gaussian filter structure_img_smooth = image_smoothing_gaussian_3d( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # step 1: low level thresholding #global_otsu = threshold_otsu(structure_img_smooth) global_tri = threshold_triangle(structure_img_smooth) global_median = np.percentile(structure_img_smooth, 50) th_low_level = (global_tri + global_median) / 2 bw_low_level = structure_img_smooth > th_low_level bw_low_level = remove_small_objects(bw_low_level, min_size=low_level_min_size, connectivity=1, in_place=True) bw_low_level = dilation(bw_low_level, selem=ball(2)) # step 2: high level thresholding local_cutoff = 0.333 * threshold_otsu(structure_img_smooth) bw_high_level = np.zeros_like(bw_low_level) lab_low, num_obj = label(bw_low_level, return_num=True, connectivity=1) for idx in range(num_obj): single_obj = (lab_low == (idx + 1)) local_otsu = threshold_otsu(structure_img_smooth[single_obj]) if local_otsu > local_cutoff: bw_high_level[np.logical_and( structure_img_smooth > 0.98 * local_otsu, single_obj)] = 1 out_img_list.append(bw_high_level.copy()) out_name_list.append('bw_coarse') response_bright = dot_slice_by_slice(structure_img_smooth, log_sigma=dot_2d_sigma) response_dark = dot_slice_by_slice(1 - structure_img_smooth, log_sigma=dot_2d_sigma) response_dark_extra = dot_slice_by_slice(1 - structure_img_smooth, log_sigma=dot_2d_sigma_extra) #inner_mask = bw_high_level.copy() #for zz in range(inner_mask.shape[0]): # inner_mask[zz,:,:] = binary_fill_holes(inner_mask[zz,:,:]) holes = np.logical_or(response_dark > dot_2d_cutoff, response_dark_extra > dot_2d_cutoff) #holes[~inner_mask] = 0 bw_extra = response_bright > dot_2d_cutoff #bw_extra[~bw_high_level]=0 bw_extra[~bw_low_level] = 0 bw_final = np.logical_or(bw_extra, bw_high_level) bw_final[holes] = 0 ################### # POST-PROCESSING ################### seg = remove_small_objects(bw_final, min_size=minArea, connectivity=1, in_place=True) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_fine') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = NPM1_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list
def Workflow_lmnb1_interphase(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [4000] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 f2_param = [[1, 0.01], [2, 0.01], [3, 0.01]] hole_max = 40000 hole_min = 400 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) # smoothing with boundary preserving smoothing structure_img_smooth = image_smoothing_gaussian_3d( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # get the mid frame mid_z = get_middle_frame(structure_img_smooth, method='intensity') # 2d filament filter on the middle frame bw_mid_z = filament_2d_wrapper(structure_img_smooth[mid_z, :, :], f2_param) # hole filling bw_fill_mid_z = hole_filling(bw_mid_z, hole_min, hole_max) seed = get_3dseed_from_mid_frame(np.logical_xor(bw_fill_mid_z, bw_mid_z), struct_img.shape, mid_z, hole_min, bg_seed=True) seg_filled = watershed( struct_img, seed.astype(int), watershed_line=True) > 1 # in watershed result, 1 is for background # get the actual shell seg = find_boundaries(seg_filled, connectivity=1, mode='thick') # output seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'array': return seg elif output_type == 'array_with_contour': return (seg, generate_segmentation_contour(seg)) else: print('your can implement your output hook here, but not yet') quit()
def Workflow_nup153(struct_img,rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [1, 13.5] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 s3_param = [[1, 0.07]] #s2_param = [[1, 0.04]] minArea = 7 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio>0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8)/(struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio # smoothing with edge_preserving_smoothing filter structure_img_smooth = edge_preserving_smoothing_3d(struct_img) #structure_img_smooth = image_smoothing_gaussian_slice_by_slice(struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # step 1: LOG 3d bw = dot_3d_wrapper(structure_img_smooth, s3_param) #bw = dot_2d_slice_by_slice_wrapper(structure_img_smooth, s2_param) ################### # POST-PROCESSING ################### seg = remove_small_objects(bw>0, min_size=minArea, connectivity=1, in_place=False) # output seg = seg>0 seg = seg.astype(np.uint16) seg[seg>0]=65535 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) elif output_type == 'array': return seg elif output_type == 'array_with_contour': return (seg, generate_segmentation_contour(seg)) else: pass
def FABP3_Cardio_Pipeline(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets # ADD you parameters here intensity_norm_param = [1, 18] minArea = 0 gaussian_smoothing_sigma = 1 # lower_bound = 685 # upper_b = 18 # ADD-HERE ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) # upper_bound = np.mean(struct_img) + 18 * np.std(struct_img) # struct_img[struct_img < lower_bound] = lower_bound # struct_img[struct_img > upper_bound] = upper_bound # struct_img = (struct_img - lower_bound).astype(float)/(upper_bound - lower_bound) out_img_list.append(struct_img.copy()) out_name_list.append("im_norm") # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) # smoothing with gaussian filter structure_img_smooth = image_smoothing_gaussian_slice_by_slice( struct_img, sigma=gaussian_smoothing_sigma) # ADD-HERE out_img_list.append(structure_img_smooth.copy()) out_name_list.append("im_smooth") # core algorithm # th_li = threshold_li(structure_img_smooth) # PARAMETERS for this step ## s2_param = [[1, 0.02]] bw = dot_2d_slice_by_slice_wrapper(structure_img_smooth, s2_param) # POST-PROCESSING seg = remove_small_objects(bw, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append("bw_final") if output_type == "default": # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == "TEMPLATE": # the hook for pre-defined output functions template_output(out_img_list, out_name_list, output_type, output_path, fn)
def evaluate(args, model): model.eval() softmax = nn.Softmax(dim=1) softmax.cuda() # check validity of parameters assert args.nchannel == len( args.InputCh ), f'number of input channel does not match input channel indices' if args.mode == 'eval': filenames = glob.glob(args.InputDir + '/*' + args.DataType) filenames.sort() for fi, fn in enumerate(filenames): print(fn) # load data struct_img = load_single_image(args, fn, time_flag=False) print(struct_img.shape) # apply the model output_img = apply_on_image(model, struct_img, softmax, args) #output_img = model_inference(model, struct_img, softmax, args) #print(len(output_img)) for ch_idx in range(len(args.OutputCh) // 2): write = omeTifWriter.OmeTifWriter( args.OutputDir + pathlib.PurePosixPath(fn).stem + '_seg_' + str(args.OutputCh[2 * ch_idx]) + '.ome.tif') if args.Threshold < 0: write.save(output_img[ch_idx].astype(float)) else: out = output_img[ch_idx] > args.Threshold out = out.astype(np.uint8) out[out > 0] = 255 write.save(out) print(f'Image {fn} has been segmented') elif args.mode == 'eval_file': fn = args.InputFile print(fn) data_reader = AICSImage(fn) img0 = data_reader.data if args.timelapse: assert data_reader.shape[0] > 1 for tt in range(data_reader.shape[0]): # Assume: TCZYX img = img0[tt, args.InputCh, :, :, :].astype(float) img = input_normalization(img, args) if len(args.ResizeRatio) > 0: img = resize(img, (1, args.ResizeRatio[0], args.ResizeRatio[1], args.ResizeRatio[2]), method='cubic') for ch_idx in range(img.shape[0]): struct_img = img[ ch_idx, :, :, :] # note that struct_img is only a view of img, so changes made on struct_img also affects img struct_img = (struct_img - struct_img.min()) / ( struct_img.max() - struct_img.min()) img[ch_idx, :, :, :] = struct_img # apply the model output_img = model_inference(model, img, softmax, args) for ch_idx in range(len(args.OutputCh) // 2): writer = omeTifWriter.OmeTifWriter( args.OutputDir + pathlib.PurePosixPath(fn).stem + '_T_' + f'{tt:03}' + '_seg_' + str(args.OutputCh[2 * ch_idx]) + '.ome.tif') if args.Threshold < 0: out = output_img[ch_idx].astype(float) out = resize( out, (1.0, 1 / args.ResizeRatio[0], 1 / args.ResizeRatio[1], 1 / args.ResizeRatio[2]), method='cubic') writer.save(out) else: out = output_img[ch_idx] > args.Threshold out = resize( out, (1.0, 1 / args.ResizeRatio[0], 1 / args.ResizeRatio[1], 1 / args.ResizeRatio[2]), method='nearest') out = out.astype(np.uint8) out[out > 0] = 255 writer.save(out) else: img = img0[0, :, :, :].astype(float) if img.shape[1] < img.shape[0]: img = np.transpose(img, (1, 0, 2, 3)) img = img[args.InputCh, :, :, :] img = input_normalization(img, args) if len(args.ResizeRatio) > 0: img = resize(img, (1, args.ResizeRatio[0], args.ResizeRatio[1], args.ResizeRatio[2]), method='cubic') for ch_idx in range(img.shape[0]): struct_img = img[ ch_idx, :, :, :] # note that struct_img is only a view of img, so changes made on struct_img also affects img struct_img = (struct_img - struct_img.min()) / ( struct_img.max() - struct_img.min()) img[ch_idx, :, :, :] = struct_img # apply the model output_img = model_inference(model, img, softmax, args) for ch_idx in range(len(args.OutputCh) // 2): writer = omeTifWriter.OmeTifWriter( args.OutputDir + pathlib.PurePosixPath(fn).stem + '_seg_' + str(args.OutputCh[2 * ch_idx]) + '.ome.tif') if args.Threshold < 0: writer.save(output_img[ch_idx].astype(float)) else: out = output_img[ch_idx] > args.Threshold out = out.astype(np.uint8) out[out > 0] = 255 writer.save(out) print(f'Image {fn} has been segmented')
def get_normed_image_array( raw_image: types.ImageLike, nucleus_seg_image: types.ImageLike, membrane_seg_image: types.ImageLike, dna_channel_index: int, membrane_channel_index: int, structure_channel_index: int, brightfield_channel_index: int, nucleus_seg_channel_index: int, membrane_seg_channel_index: int, current_pixel_sizes: Optional[Tuple[float]] = None, desired_pixel_sizes: Optional[Tuple[float]] = None, ) -> Tuple[np.ndarray, List[str], Tuple[float]]: """ Provided the original raw image, and a nucleus and membrane segmentation, construct a standardized, ordered, and normalized array of the images. Parameters ---------- raw_image: types.ImageLike A filepath to the raw imaging data. The image should be 4D and include channels for DNA, Membrane, Structure, and Transmitted Light. nucleus_seg_image: types.ImageLike A filepath to the nucleus segmentation for the provided raw image. membrane_seg_image: types.ImageLike A filepath to the membrane segmentation for the provided raw image. dna_channel_index: int The index in channel dimension in the raw image that stores DNA data. membrane_channel_index: int The index in the channel dimension in the raw image that stores membrane data. structure_channel_index: int The index in the channel dimension in the raw image that stores structure data. brightfield_channel_index: int The index in the channel dimension in the raw image that stores the brightfield data. nucleus_seg_channel_index: int The index in the channel dimension in the nucleus segmentation image that stores the segmentation. membrane_seg_channel_index: int The index in the channel dimension in the membrane segmentation image that stores the segmentation. current_pixel_sizes: Optioal[Tuple[float]] The current physical pixel sizes as a tuple of the raw image. Default: None (`aicsimageio.AICSImage.get_physical_pixel_size` on the raw image) desired_pixel_sizes: Optional[Tuple[float]] The desired physical pixel sizes as a tuple to scale all images to. Default: None (scale all images to current_pixel_sizes if different) Returns ------- normed: np.ndarray The normalized images stacked into a single CYXZ numpy ndarray. channels: List[str] The standardized channel names for the returned array. pixel_sizes: Tuple[float] The physical pixel sizes of the returned image in XYZ order. Notes ----- The original version of this function can be found at: https://aicsbitbucket.corp.alleninstitute.org/projects/MODEL/repos/image_processing_pipeline/browse/aics_single_cell_pipeline/utils.py#9 """ # Construct image objects raw = AICSImage(raw_image) nuc_seg = AICSImage(nucleus_seg_image) memb_seg = AICSImage(membrane_seg_image) # Preload image data raw.data nuc_seg.data memb_seg.data # Get default current and desired pixel sizes if current_pixel_sizes is None: current_pixel_sizes = raw.get_physical_pixel_size() # Default desired to be the same pixel size if desired_pixel_sizes is None: desired_pixel_sizes = current_pixel_sizes # Select the channels channel_indices = [ dna_channel_index, membrane_channel_index, structure_channel_index, brightfield_channel_index, ] selected_channels = [ raw.get_image_dask_data("YXZ", S=0, T=0, C=index) for index in channel_indices ] # Combine selections and get numpy array raw = da.stack(selected_channels).compute() # Convert pixel sizes to numpy arrays current_pixel_sizes = np.array(current_pixel_sizes) desired_pixel_sizes = np.array(desired_pixel_sizes) # Only resize raw image if desired pixel sizes is different from current if not np.array_equal(current_pixel_sizes, desired_pixel_sizes): scale_raw = current_pixel_sizes / desired_pixel_sizes raw = np.stack( [proc.resize(channel, scale_raw, "bilinear") for channel in raw]) # Prep segmentations nuc_seg = nuc_seg.get_image_data("YXZ", S=0, T=0, C=nucleus_seg_channel_index) memb_seg = memb_seg.get_image_data("YXZ", S=0, T=0, C=membrane_seg_channel_index) # We do not assume that the segmentations are the same size as the raw # Resize the segmentations to match the raw # We drop the channel dimension from the raw size retrieval raw_size = np.array(raw.shape[1:]).astype(float) nuc_size = np.array(nuc_seg.shape).astype(float) memb_size = np.array(memb_seg.shape).astype(float) scale_nuc = raw_size / nuc_size scale_memb = raw_size / memb_size # Actual resize nuc_seg = proc.resize(nuc_seg, scale_nuc, method="nearest") memb_seg = proc.resize(memb_seg, scale_memb, method="nearest") # Normalize images normalized_images = [] for i, index in enumerate(channel_indices): if index == brightfield_channel_index: norm_method = "trans" else: norm_method = "img_bg_sub" # Normalize and append normalized_images.append(proc.normalize_img(raw[i], method=norm_method)) # Stack all together img = np.stack([nuc_seg, memb_seg, *normalized_images]) channel_names = Channels.DefaultOrderList return img, channel_names, tuple(desired_pixel_sizes)
def Workflow_tjp1(struct_img, rescale_ratio, output_type, output_path, fn, output_func=None): ########################################################################## # PARAMETERS: # note that these parameters are supposed to be fixed for the structure # and work well accross different datasets intensity_norm_param = [3, 17] gaussian_smoothing_sigma = 1 gaussian_smoothing_truncate_range = 3.0 vesselness_sigma = [1.5] vesselness_cutoff = 0.2 minArea = 15 ########################################################################## out_img_list = [] out_name_list = [] ################### # PRE_PROCESSING ################### # intenisty normalization (min/max) struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) out_img_list.append(struct_img.copy()) out_name_list.append('im_norm') # rescale if needed if rescale_ratio > 0: struct_img = resize(struct_img, [1, rescale_ratio, rescale_ratio], method="cubic") struct_img = (struct_img - struct_img.min() + 1e-8) / (struct_img.max() - struct_img.min() + 1e-8) gaussian_smoothing_truncate_range = gaussian_smoothing_truncate_range * rescale_ratio # smoothing with gaussian filter structure_img_smooth = image_smoothing_gaussian_3d( struct_img, sigma=gaussian_smoothing_sigma, truncate_range=gaussian_smoothing_truncate_range) out_img_list.append(structure_img_smooth.copy()) out_name_list.append('im_smooth') ################### # core algorithm ################### # vesselness 3d response = vesselness3D(structure_img_smooth, sigmas=vesselness_sigma, tau=1, whiteonblack=True) bw = response > vesselness_cutoff ################### # POST-PROCESSING ################### seg = remove_small_objects(bw > 0, min_size=minArea, connectivity=1, in_place=False) # output seg = seg > 0 seg = seg.astype(np.uint8) seg[seg > 0] = 255 out_img_list.append(seg.copy()) out_name_list.append('bw_final') if output_type == 'default': # the default final output save_segmentation(seg, False, output_path, fn) elif output_type == 'AICS_pipeline': # pre-defined output function for pipeline data save_segmentation(seg, True, output_path, fn) elif output_type == 'customize': # the hook for passing in a customized output function output_fun(out_img_list, out_name_list, output_path, fn) elif output_type == 'array': return seg elif output_type == 'array_with_contour': return (seg, generate_segmentation_contour(seg)) else: # the hook for pre-defined RnD output functions (AICS internal) img_list, name_list = TJP1_output(out_img_list, out_name_list, output_type, output_path, fn) if output_type == 'QCB': return img_list, name_list