示例#1
0
def Workflow_template(struct_img,
                      rescale_ratio,
                      output_type,
                      output_path,
                      fn,
                      output_func=None):
    ##########################################################################
    # PARAMETERS:

    ##########################################################################

    ###################
    # PRE_PROCESSING
    # make sure the variable name of original image is 'struct_img'
    ###################
    # intenisty normalization

    # smoothing

    ###################
    # core algorithm
    ###################

    ###################
    # POST-PROCESSING
    # make sure the variable name of final segmentation is 'seg'
    ###################

    ##########################################################################
    # ## no need to change below
    ##########################################################################
    # output
    seg = seg > 0
    seg = seg.astype(np.uint8)
    seg[seg > 0] = 255

    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_lmnb1_interphase(
    struct_img: np.ndarray,
    rescale_ratio: float = -1,
    output_type: str = "default",
    output_path: Union[str, Path] = None,
    fn: Union[str, Path] = None,
    output_func=None,
):
    """
    classic segmentation workflow wrapper for structure LMNB1 interphase

    Parameter:
    -----------
    struct_img: np.ndarray
        the 3D image to be segmented
    rescale_ratio: float
        an optional parameter to allow rescale the image before running the
        segmentation functions, default is no rescaling
    output_type: str
        select how to handle output. Currently, four types are supported:
        1. default: the result will be saved at output_path whose filename is
            original name without extention + "_struct_segmentaiton.tiff"
        2. array: the segmentation result will be simply returned as a numpy array
        3. array_with_contour: segmentation result will be returned together with
            the contour of the segmentation
        4. customize: pass in an extra output_func to do a special save. All the
            intermediate results, names of these results, the output_path, and the
            original filename (without extension) will be passed in to output_func.
    """
    ##########################################################################
    # 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 = zoom(struct_img, (1, rescale_ratio, rescale_ratio),
                          order=2)

        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, simply save it to the output path
        save_segmentation(seg, False, Path(output_path), fn)
    elif output_type == "customize":
        # the hook for passing in a customized output function
        # use "out_img_list" and "out_name_list" in your hook to
        # customize your output functions
        output_func(out_img_list, out_name_list, Path(output_path), fn)
    elif output_type == "array":
        return seg
    elif output_type == "array_with_contour":
        return (seg, generate_segmentation_contour(seg))
    else:
        raise NotImplementedError("invalid output type: {output_type}")
示例#3
0
def RAB5A_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 = [6000]
    gaussian_smoothing_sigma = 1
    gaussian_smoothing_truncate_range = 3.0
    dot_3d_sigma = 1
    dot_3d_cutoff = 0.02
    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 = processing.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 other pre-defined RnD output functions (AICS internal)
        RAB5A_output(out_img_list, out_name_list, output_type, output_path, fn)
示例#4
0
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)
    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 = SEC61B_output(out_img_list, out_name_list,
                                            output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
def Workflow_cardio_npm1_100x(
    struct_img: np.ndarray,
    rescale_ratio: float = -1,
    output_type: str = "default",
    output_path: Union[str, Path] = None,
    fn: Union[str, Path] = None,
    output_func=None,
):
    """
    classic segmentation workflow wrapper for structure Cardio NPM1 100x

    Parameter:
    -----------
    struct_img: np.ndarray
        the 3D image to be segmented
    rescale_ratio: float
        an optional parameter to allow rescale the image before running the
        segmentation functions, default is no rescaling
    output_type: str
        select how to handle output. Currently, four types are supported:
        1. default: the result will be saved at output_path whose filename is
            original name without extention + "_struct_segmentaiton.tiff"
        2. array: the segmentation result will be simply returned as a numpy array
        3. array_with_contour: segmentation result will be returned together with
            the contour of the segmentation
        4. customize: pass in an extra output_func to do a special save. All the
            intermediate results, names of these results, the output_path, and the
            original filename (without extension) will be passed in to output_func.
    """
    ##########################################################################
    # PARAMETERS:
    #   note that these parameters are supposed to be fixed for the structure
    #   and work well accross different datasets

    intensity_norm_param = [0.5, 2.5]
    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 = 1
    low_level_min_size = 1000
    ##########################################################################

    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 = zoom(struct_img, (1, rescale_ratio, rescale_ratio),
                          order=2)

        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

    # print(global_median)
    # print(global_tri)
    # print(th_low_level)
    # imsave('img_smooth.tiff', structure_img_smooth)

    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 > 1.2 * local_otsu, single_obj)] = 1

    # imsave('seg_coarse.tiff', bw_high_level.astype(np.uint8))

    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)

    bw_extra = response_bright > 0.03  # dot_2d_cutoff
    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_final")

    if output_type == "default":
        # the default final output, simply save it to the output path
        save_segmentation(seg, False, Path(output_path), fn)
    elif output_type == "customize":
        # the hook for passing in a customized output function
        # use "out_img_list" and "out_name_list" in your hook to
        # customize your output functions
        output_func(out_img_list, out_name_list, Path(output_path), fn)
    elif output_type == "array":
        return seg
    elif output_type == "array_with_contour":
        return (seg, generate_segmentation_contour(seg))
    else:
        raise NotImplementedError("invalid output type: {output_type}")
示例#6
0
def Workflow_drug_npm1(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, 25]
    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)
    bw_finer = dot_3d_wrapper(structure_img_smooth, s3_param = [[1, 0.015]])

    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)
    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 = FBL_output(out_img_list, out_name_list, output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
示例#7
0
def Workflow_npm1(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
示例#8
0
def Workflow_pxn(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 = [11, 8]
    vesselness_sigma = [1]
    vesselness_cutoff = 0.35
    minArea3D = 15
    minArea2D = 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)

    # 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
    ###################

    # vesselness 3d
    response = vesselness3D(structure_img_smooth,
                            sigmas=vesselness_sigma,
                            tau=1,
                            whiteonblack=True)
    bw = response > vesselness_cutoff

    ###################
    # POST-PROCESSING
    ###################

    seg = np.zeros_like(bw)
    for zz in range(bw.shape[0]):
        seg[zz, :, :] = remove_small_objects(bw[zz, :, :] > 0,
                                             min_size=minArea2D,
                                             connectivity=1,
                                             in_place=False)

    seg = remove_small_objects(seg > 0,
                               min_size=minArea3D,
                               connectivity=1,
                               in_place=False)

    # determine z-range
    bw_z = np.zeros(bw.shape[0], dtype=np.uint16)
    for zz in range(bw.shape[0]):
        bw_z[zz] = np.count_nonzero(seg[zz, :, :] > 0)

    mid_z = np.argmax(bw_z)
    low_z = 0
    high_z = seg.shape[0] - 2
    for ii in np.arange(mid_z - 1, 0, -1):
        if bw_z[ii] < 100:
            low_z = ii
            break
    for ii in range(mid_z + 1, bw.shape[0] - 1, 1):
        if bw_z[ii] < 100:
            high_z = ii
            break

    seg[:low_z, :, :] = 0
    seg[high_z + 1:, :, :] = 0

    # 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 = PXN_output(out_img_list, out_name_list,
                                         output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
示例#9
0
def Workflow_lamp1(
    struct_img: np.ndarray,
    rescale_ratio: float = -1,
    output_type: str = "default",
    output_path: Union[str, Path] = None,
    fn: Union[str, Path] = None,
    output_func=None,
):
    """
    classic segmentation workflow wrapper for structure LAMP1

    Parameter:
    -----------
    struct_img: np.ndarray
        the 3D image to be segmented
    rescale_ratio: float
        an optional parameter to allow rescale the image before running the
        segmentation functions, default is no rescaling
    output_type: str
        select how to handle output. Currently, four types are supported:
        1. default: the result will be saved at output_path whose filename is
            original name without extention + "_struct_segmentaiton.tiff"
        2. array: the segmentation result will be simply returned as a numpy array
        3. array_with_contour: segmentation result will be returned together with
            the contour of the segmentation
        4. customize: pass in an extra output_func to do a special save. All the
            intermediate results, names of these results, the output_path, and the
            original filename (without extension) will be passed in to output_func.
    """

    ##########################################################################
    # 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 = zoom(struct_img, (1, rescale_ratio, rescale_ratio), order=2)

        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, simply save it to the output path
        save_segmentation(seg, False, Path(output_path), fn)
    elif output_type == "customize":
        # the hook for passing in a customized output function
        # use "out_img_list" and "out_name_list" in your hook to
        # customize your output functions
        output_func(out_img_list, out_name_list, Path(output_path), fn)
    elif output_type == "array":
        return seg
    elif output_type == "array_with_contour":
        return (seg, generate_segmentation_contour(seg))
    else:
        raise NotImplementedError("invalid output type: {output_type}")
示例#10
0
def Workflow_npm1_bright_v3_single(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 = [15, 5]
    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/NPM1_norm1/mem/"
    mito_seed_path = mito_seed_path_root + fn.replace('.tiff', '.mem_seg.tiff')
    # # mito_seed_path_root = "/allen/aics/assay-dev/computational/data/Nucleus_structure_segmentation/fibrillarin_segmentation_improvement/" + mitotic_stage + "/mito_seg/"
    # # mito_seed_path = mito_seed_path_root + fn + "_mem_segmentation.tif"

    # # Generate seed for mitotic cell
    mito_3d = imread(mito_seed_path)
    if np.ndim(mito_3d) == 4:
        mito_3d = mito_3d[:, :, :, 0]

    # specific case for presentation
    # mito_seed_path_root = '/allen/aics/assay-dev/computational/data/Nucleus_structure_segmentation/presentation/mem_seg/FBL_NPM1/'
    # mito_seed_path = mito_seed_path_root + fn.replace('.czi', '_mem_segmentation.tiff')
    # mito_3d = imread(mito_seed_path)
    # mito_3d = (mito_3d == 2).astype(np.uint8)
    ###############################

    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 = 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.95
    # slice_cutoff = 0.03
    # local_otsu = 1.9 * otsu_mito # It was 0.13
    # bw_high_level[np.logical_and(structure_img_smooth> local_otsu, mito_3d>0)]=1
    # bw_high_level = dilation(bw_high_level, selem=ball(1.5))

    if local_diff >= 0.33:
        vessel_cutoff = 0.045
        slice_cutoff = 0.03

    elif local_diff >= 0.10 and local_diff < 0.33:
        vessel_cutoff = 0.105
        slice_cutoff = 0.04
        local_otsu = 2.1 * otsu_mito
        bw_high_level[np.logical_and(structure_img_smooth > local_otsu,
                                     mito_3d > 0)] = 1

    # When FBL seg is very brgiht
    elif local_diff < 0.05:
        vessel_cutoff = 0.15
        slice_cutoff = 0.06
        local_otsu = 2.5 * otsu_mito
        bw_high_level[np.logical_and(structure_img_smooth > local_otsu,
                                     mito_3d > 0)] = 1

    # if local_diff >= 0.15:
    #     vessel_cutoff = 0.04
    #     slice_cutoff = 0.02

    # # When FBL seg is very brgiht
    # elif local_diff < 0.05:
    #     vessel_cutoff = 0.105
    #     slice_cutoff = 0.03
    #     local_otsu = 1.7 * otsu_mito
    #     bw_high_level[np.logical_and(structure_img_smooth> local_otsu, mito_3d>0)]=1

    # print(local_diff, local_otsu, np.percentile(structure_img_smooth[mito_3d>0],25))

    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
    # pdb.set_trace()

    ###################
    # 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 + "_npm_bright"

    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
示例#11
0
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)
    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
示例#12
0
def Workflow_npm1_comb(struct_img,
                       mitotic_stage,
                       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 = [20, 25]
    gaussian_smoothing_sigma = 0.25
    gaussian_smoothing_truncate_range = 4.0
    dot_2d_sigma = 1
    dot_2d_sigma_extra = 3
    dot_2d_cutoff = 0.035
    dot_2d_cutoff_extra = 0.01
    minArea = 2
    low_level_min_size = 700
    ##########################################################################

    out_img_list = []
    out_name_list = []

    ###################
    # PRE_PROCESSING
    ###################
    # intenisty normalization (min/max)
    struct_img = np.reciprocal(struct_img)  # inverting to detect dark spot
    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_median_1 = np.percentile(structure_img_smooth,35)
    global_median_2 = np.percentile(structure_img_smooth,
                                    30)  # 70 for M6M7, 30 for rest

    # th_low_level_1 = global_median_1
    th_low_level_2 = global_median_2
    # bw_low_level = (structure_img_smooth > th_low_level_1) + (structure_img_smooth > th_low_level_2)
    bw_low_level = structure_img_smooth > th_low_level_2
    bw_low_level = remove_small_objects(bw_low_level,
                                        min_size=low_level_min_size,
                                        connectivity=1,
                                        in_place=True)
    seg = dilation(bw_low_level, selem=ball(2))

    seg = np.invert(seg)
    seg = seg.astype(np.uint8)
    seg[seg > 0] = 255

    ####################
    # POST-Processing using other segmentations structures
    ####################

    other_segs_path = "/allen/aics/assay-dev/computational/data/dna_cell_seg_on_production_data/NPM1/new_dna_mem_segmentation/"
    mem_segs_path = other_segs_path + fn + "_mem_segmentation.tiff"
    dna_segs_path = other_segs_path + fn + "_dna_segmentation.tiff"

    if not os.path.exists(mem_segs_path):
        mem_segs_path = other_segs_path + fn + ".ome_mem_segmentation.tiff"
        dna_segs_path = other_segs_path + fn + ".ome_dna_segmentation.tiff"

    mito_seed_path_root = "/allen/aics/assay-dev/computational/data/NPM1_segmentation_improvement/images_with_mitosis/M67/mito_seg/"
    mito_seed_path = mito_seed_path_root + fn + ".tiff"

    # Generate seed for mitotic cell
    if not os.path.exists(mito_seed_path):
        mito_seed_path = mito_seed_path_root + fn + ".ome.tiff"
    mito_seed_3d = imread(mito_seed_path)

    mito_seed_img = np.amax(mito_seed_3d, axis=0)
    mito_seed = com(mito_seed_img)

    # label the segmentations
    # mem_label, num_feat_mem = labeling(imread(mem_segs_path)) # not labeling correctly
    dna_label, num_feat_dna = labeling(imread(dna_segs_path))

    # label
    # label_mito = mem_label[int(np.floor(mem_label.shape[0]/2)),int(mito_seed[0]),int(mito_seed[1])]

    # seg = seg * ((mem_label == label_mito)*1)
    seg[mito_seed_3d == 0] = 0
    seg[dna_label > 0] = 0

    out_img_list.append(seg.copy())
    out_name_list.append('bw_fine')

    fn += "_combined"

    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
示例#13
0
def Workflow_son(
    struct_img: np.ndarray,
    rescale_ratio: float = -1,
    output_type: str = "default",
    output_path: Union[str, Path] = None,
    fn: Union[str, Path] = None,
    output_func=None,
):
    """
    classic segmentation workflow wrapper for structure SON

    Parameter:
    -----------
    struct_img: np.ndarray
        the 3D image to be segmented
    rescale_ratio: float
        an optional parameter to allow rescale the image before running the
        segmentation functions, default is no rescaling
    output_type: str
        select how to handle output. Currently, four types are supported:
        1. default: the result will be saved at output_path whose filename is
            original name without extention + "_struct_segmentaiton.tiff"
        2. array: the segmentation result will be simply returned as a numpy array
        3. array_with_contour: segmentation result will be returned together with
            the contour of the segmentation
        4. customize: pass in an extra output_func to do a special save. All the
            intermediate results, names of these results, the output_path, and the
            original filename (without extension) will be passed in to output_func.
    """
    ##########################################################################
    # PARAMETERS:
    #   note that these parameters are supposed to be fixed for the structure
    #   and work well accross different datasets
    ##########################################################################

    intensity_norm_param = [2, 30]
    vesselness_sigma = [1.2]
    vesselness_cutoff = 0.15
    minArea = 15

    # dot_2d_sigma = 1
    dot_3d_sigma = 1.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")

    # 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
    ###################
    response_f3 = vesselness3D(structure_img_smooth,
                               sigmas=vesselness_sigma,
                               tau=1,
                               whiteonblack=True)
    response_f3 = response_f3 > vesselness_cutoff

    response_s3_1 = dot_3d(structure_img_smooth, log_sigma=dot_3d_sigma)
    response_s3_3 = dot_3d(structure_img_smooth, log_sigma=3)

    bw_small_inverse = remove_small_objects(response_s3_1 > 0.03, min_size=150)
    bw_small = np.logical_xor(bw_small_inverse, response_s3_1 > 0.02)

    bw_medium = np.logical_or(bw_small, response_s3_1 > 0.07)
    bw_large = np.logical_or(response_s3_3 > 0.2, response_f3 > 0.25)
    bw = np.logical_or(np.logical_or(bw_small, bw_medium), bw_large)

    ###################
    # 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)

    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, simply save it to the output path
        save_segmentation(seg, False, Path(output_path), fn)
    elif output_type == "customize":
        # the hook for passing in a customized output function
        # use "out_img_list" and "out_name_list" in your hook to
        # customize your output functions
        output_func(out_img_list, out_name_list, Path(output_path), fn)
    elif output_type == "array":
        return seg
    elif output_type == "array_with_contour":
        return (seg, generate_segmentation_contour(seg))
    else:
        raise NotImplementedError("invalid output type: {output_type}")
示例#14
0
def Workflow_slc25a17(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, 36]
    gaussian_smoothing_sigma = 1
    gaussian_smoothing_truncate_range = 3.0
    dot_3d_sigma = 1
    dot_3d_cutoff = 0.045 #0.03 #0.04
    minArea = 3 #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)
        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(-1*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)

    ###### HACK: Only for 2019 April Release #####
    if np.count_nonzero(seg>0)<50000:
        print('FLAG: please check the meta data of the original CZI for QC')
        
    # 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)
        print('please provide custom output function')
    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 = SLC25A17_output(out_img_list, out_name_list, output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
示例#15
0
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()
示例#16
0
def ACTN1_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 = [3, 15]  
    vesselness_sigma_1 = [2]
    vesselness_cutoff_1 = 0.15
    vesselness_sigma_2 = [1]
    vesselness_cutoff_2 = 0.05
    minArea = 5
    ##########################################################################

    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)
        print('please provide custom output function')
    else:
        # the hook for pre-defined RnD output functions (AICS internal)
        img_list, name_list = ACTN1_output(out_img_list, out_name_list, output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
def Workflow_fbl_labelfree_4dn(
    struct_img: np.ndarray,
    rescale_ratio: float = -1,
    output_type: str = "default",
    output_path: Union[str, Path] = None,
    fn: Union[str, Path] = None,
    output_func=None,
):
    """
    classic segmentation workflow wrapper for structure FBL Labelfree 4dn

    Parameter:
    -----------
    struct_img: np.ndarray
        the 3D image to be segmented
    rescale_ratio: float
        an optional parameter to allow rescale the image before running the
        segmentation functions, default is no rescaling
    output_type: str
        select how to handle output. Currently, four types are supported:
        1. default: the result will be saved at output_path whose filename is
            original name without extention + "_struct_segmentaiton.tiff"
        2. array: the segmentation result will be simply returned as a numpy array
        3. array_with_contour: segmentation result will be returned together with
            the contour of the segmentation
        4. customize: pass in an extra output_func to do a special save. All the
            intermediate results, names of these results, the output_path, and the
            original filename (without extension) will be passed in to output_func.
    """
    ##########################################################################
    # PARAMETERS:
    minArea = 5
    low_level_min_size = 7000
    s2_param = [[0.5, 0.1]]
    intensity_scaling_param = [0.5, 19.5]
    gaussian_smoothing_sigma = 1

    ##########################################################################
    out_img_list = []
    out_name_list = []

    ###################
    # PRE_PROCESSING
    ###################
    # intenisty normalization
    struct_norm = intensity_normalization(
        struct_img, scaling_param=intensity_scaling_param)
    out_img_list.append(struct_img.copy())
    out_name_list.append("im_norm")

    # smoothing
    struct_smooth = image_smoothing_gaussian_3d(struct_norm,
                                                sigma=gaussian_smoothing_sigma)

    out_img_list.append(struct_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(struct_smooth)
    global_median = np.percentile(struct_smooth, 50)

    th_low_level = (global_tri + global_median) / 2
    bw_low_level = struct_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(struct_smooth[single_obj])
        bw_high_level[np.logical_and(struct_smooth > local_otsu * 1.2,
                                     single_obj)] = 1

    # step 3: finer segmentation
    response2d = dot_2d_slice_by_slice_wrapper(struct_smooth, s2_param)
    bw_finer = remove_small_objects(response2d,
                                    min_size=minArea,
                                    connectivity=1,
                                    in_place=True)

    # merge finer level detection into high level coarse segmentation
    # to include outside dim parts
    bw_high_level[bw_finer > 0] = 1

    ###################
    # POST-PROCESSING
    # make sure the variable name of final segmentation is 'seg'
    ###################
    seg = remove_small_objects(bw_high_level,
                               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_final")

    if output_type == "default":
        # the default final output, simply save it to the output path
        save_segmentation(seg, False, Path(output_path), fn)
    elif output_type == "customize":
        # the hook for passing in a customized output function
        # use "out_img_list" and "out_name_list" in your hook to
        # customize your output functions
        # TODO CREATE OUT_IMG_LIST/OUT_NAMELIST?
        output_func(out_img_list, out_name_list, Path(output_path), fn)
    elif output_type == "array":
        return seg
    elif output_type == "array_with_contour":
        return (seg, generate_segmentation_contour(seg))
    else:
        raise NotImplementedError("invalid output type: {output_type}")
示例#18
0
def Workflow_ctnnb1(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)
    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 = CTNNB1_output(out_img_list, out_name_list, output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
示例#19
0
def Workflow_son(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, 30]
    vesselness_sigma = [1.2]
    vesselness_cutoff = 0.15
    minArea = 15

    dot_2d_sigma = 1
    dot_3d_sigma = 1.15
    ##########################################################################

    ###################
    # PRE_PROCESSING
    ###################
    # intenisty normalization (min/max)
    struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param)

    # smoothing with boundary preserving smoothing
    structure_img_smooth = edge_preserving_smoothing_3d(struct_img)

    ###################
    # core algorithm
    ###################
    response_f3 = vesselness3D(structure_img_smooth, sigmas=vesselness_sigma,  tau=1, whiteonblack=True)
    response_f3 = response_f3 > vesselness_cutoff

    response_s3_1 = dot_3d(structure_img_smooth, log_sigma=dot_3d_sigma)
    response_s3_3 = dot_3d(structure_img_smooth, log_sigma=3)

    bw_small_inverse = remove_small_objects(response_s3_1>0.03, min_size=150)
    bw_small = np.logical_xor(bw_small_inverse, response_s3_1>0.02)

    bw_medium = np.logical_or(bw_small, response_s3_1>0.07)
    bw_large = np.logical_or(response_s3_3>0.2, response_f3>0.25)
    bw = np.logical_or( np.logical_or(bw_small, bw_medium), bw_large)

    ###################
    # 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)

    seg = seg>0
    seg = seg.astype(np.uint8)
    seg[seg>0]=255

    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()
示例#20
0
def Workflow_slc25a17(
    struct_img: np.ndarray,
    rescale_ratio: float = -1,
    output_type: str = "default",
    output_path: Union[str, Path] = None,
    fn: Union[str, Path] = None,
    output_func=None,
):
    """
    classic segmentation workflow wrapper for structure SLC25A17

    Parameter:
    -----------
    struct_img: np.ndarray
        the 3D image to be segmented
    rescale_ratio: float
        an optional parameter to allow rescale the image before running the
        segmentation functions, default is no rescaling
    output_type: str
        select how to handle output. Currently, four types are supported:
        1. default: the result will be saved at output_path whose filename is
            original name without extention + "_struct_segmentaiton.tiff"
        2. array: the segmentation result will be simply returned as a numpy array
        3. array_with_contour: segmentation result will be returned together with
            the contour of the segmentation
        4. customize: pass in an extra output_func to do a special save. All the
            intermediate results, names of these results, the output_path, and the
            original filename (without extension) will be passed in to output_func.
    """
    ##########################################################################
    # PARAMETERS:
    #   note that these parameters are supposed to be fixed for the structure
    #   and work well accross different datasets

    intensity_norm_param = [2, 36]
    gaussian_smoothing_sigma = 1
    gaussian_smoothing_truncate_range = 3.0
    dot_3d_sigma = 1
    dot_3d_cutoff = 0.045  # 0.03 #0.04
    minArea = 3  # 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 = zoom(struct_img, (1, rescale_ratio, rescale_ratio),
                          order=2)

        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(
        -1 * 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)

    # HACK: Only for 2019 April Release #####
    if np.count_nonzero(seg > 0) < 50000:
        print("FLAG: please check the meta data of the original CZI for QC")

    # 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, simply save it to the output path
        save_segmentation(seg, False, Path(output_path), fn)
    elif output_type == "customize":
        # the hook for passing in a customized output function
        # use "out_img_list" and "out_name_list" in your hook to
        # customize your output functions
        output_func(out_img_list, out_name_list, Path(output_path), fn)
    elif output_type == "array":
        return seg
    elif output_type == "array_with_contour":
        return (seg, generate_segmentation_contour(seg))
    else:
        raise NotImplementedError("invalid output type: {output_type}")
示例#21
0
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)
    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()
示例#22
0
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 = processing.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 other pre-defined RnD output functions (AICS internal)
        ST6GAL1_output(out_img_list, out_name_list, output_type, output_path,
                       fn)
示例#23
0
def RAB5A_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 = [1000]
    gaussian_smoothing_sigma = 1
    gaussian_smoothing_truncate_range = 3.0
    dot_3d_sigma = 1
    dot_3d_cutoff = 0.03

    hole_min = 0
    hole_max = 81

    minArea = 3
    ##########################################################################

    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

    # step 2: fill holes and remove small objects
    bw_filled = hole_filling(bw, hole_min, hole_max, True)
    seg = remove_small_objects(bw_filled,
                               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 = RAB5A_output(out_img_list, out_name_list,
                                           output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
示例#24
0
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)
    else:
        pass
示例#25
0
def Workflow_tomm20(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.5, 15] 
    gaussian_smoothing_sigma = 1
    gaussian_smoothing_truncate_range = 3.0
    vesselness_sigma = [1.5]
    vesselness_cutoff = 0.16
    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 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
    ###################

    # 2d vesselness slice by slice
    response = vesselnessSliceBySlice(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)
    else:
        # the hook for pre-defined RnD output functions (AICS internal)
        img_list, name_list = TOMM20_output(out_img_list, out_name_list, output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
示例#26
0
def TEMPLATE_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

    # ADD you parameters here
    intensity_norm_param = []
    minArea = 0
    #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)

    out_img_list.append(struct_img.copy())
    out_name_list.append('im_norm')

    # rescale if needed
    if rescale_ratio > 0:
        struct_img = processing.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 = ADD_SMOOTHING_FUNCTION_HERE  #ADD-HERE

    out_img_list.append(structure_img_smooth.copy())
    out_name_list.append('im_smooth')

    ###################
    # core algorithm
    ###################

    bw = ADD_CORE_ALGORITHMS_HERE  #ADD-HERE

    ###################
    # 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 (allen institute internal)
        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 other pre-defined RnD output functions (AICS internal)
        DSP_output(out_img_list, out_name_list, output_type, output_path, fn)
示例#27
0
def Workflow_cardio_ttn(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 = [8, 15.5]
    vesselness_sigma = [1]
    vesselness_cutoff = 0.02
    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 = processing.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 = 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 = 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)
    else:
        # the hook for other pre-defined RnD output functions (AICS internal)
        TTN_Cardio_output(out_img_list, out_name_list, output_type,
                          output_path, fn)
示例#28
0
def Workflow_smc1a(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, 12]
    s2_param = [[1, 0.06]]
    minArea = 3
    ##########################################################################

    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 gaussian filter
    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
    ###################

    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.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 = FBL_output(out_img_list, out_name_list,
                                         output_type, output_path, fn)
        if output_type == 'QCB':
            return img_list, name_list
示例#29
0
def Workflow_cardio_myl7(
    struct_img: np.ndarray,
    rescale_ratio: float = -1,
    output_type: str = "default",
    output_path: Union[str, Path] = None,
    fn: Union[str, Path] = None,
    output_func=None,
):
    """
    classic segmentation workflow wrapper for structure Cardio MYL7

    Parameter:
    -----------
    struct_img: np.ndarray
        the 3D image to be segmented
    rescale_ratio: float
        an optional parameter to allow rescale the image before running the
        segmentation functions, default is no rescaling
    output_type: str
        select how to handle output. Currently, four types are supported:
        1. default: the result will be saved at output_path whose filename is
            original name without extention + "_struct_segmentaiton.tiff"
        2. array: the segmentation result will be simply returned as a numpy array
        3. array_with_contour: segmentation result will be returned together with
            the contour of the segmentation
        4. customize: pass in an extra output_func to do a special save. All the
            intermediate results, names of these results, the output_path, and the
            original filename (without extension) will be passed in to output_func.
    """
    ##########################################################################
    # PARAMETERS:
    #   note that these parameters are supposed to be fixed for the structure
    #   and work well accross different datasets

    intensity_norm_param = [8, 15.5]
    vesselness_sigma = [1]
    vesselness_cutoff = 0.01
    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 = zoom(struct_img, (1, rescale_ratio, rescale_ratio),
                          order=2)

        struct_img = (struct_img - struct_img.min() +
                      1e-8) / (struct_img.max() - struct_img.min() + 1e-8)

    # smoothing with gaussian filter
    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 = 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, simply save it to the output path
        save_segmentation(seg, False, Path(output_path), fn)
    elif output_type == "customize":
        # the hook for passing in a customized output function
        # use "out_img_list" and "out_name_list" in your hook to
        # customize your output functions
        output_func(out_img_list, out_name_list, Path(output_path), fn)
    elif output_type == "array":
        return seg
    elif output_type == "array_with_contour":
        return (seg, generate_segmentation_contour(seg))
    else:
        raise NotImplementedError("invalid output type: {output_type}")
def Workflow_npm_labelfree_4dn(struct_img,
                               rescale_ratio,
                               output_type,
                               output_path,
                               fn,
                               output_func=None):
    ##########################################################################
    # PARAMETERS:
    minArea = 5
    low_level_min_size = 7000
    s2_param = [[0.5, 0.12]]
    intensity_scaling_param = [2, 16.5]
    gaussian_smoothing_sigma = 1

    ##########################################################################

    ###################
    # PRE_PROCESSING
    ###################
    # intenisty normalization
    struct_norm = intensity_normalization(
        struct_img, scaling_param=intensity_scaling_param)

    # smoothing
    struct_smooth = image_smoothing_gaussian_3d(struct_norm,
                                                sigma=gaussian_smoothing_sigma)

    ###################
    # core algorithm
    ###################
    # step 1: low level thresholding
    #global_otsu = threshold_otsu(structure_img_smooth)
    global_tri = threshold_triangle(struct_smooth)
    global_median = np.percentile(struct_smooth, 50)

    th_low_level = (global_tri + global_median) / 2
    bw_low_level = struct_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(struct_smooth[single_obj])
        bw_high_level[np.logical_and(struct_smooth > local_otsu * 1.2,
                                     single_obj)] = 1

    # step 3: finer segmentation
    response2d = dot_2d_slice_by_slice_wrapper(struct_smooth, s2_param)
    bw_finer = remove_small_objects(response2d,
                                    min_size=minArea,
                                    connectivity=1,
                                    in_place=True)

    # merge finer level detection into high level coarse segmentation to include outside dim parts
    bw_high_level[bw_finer > 0] = 1

    ###################
    # POST-PROCESSING
    # make sure the variable name of final segmentation is 'seg'
    ###################
    seg = remove_small_objects(bw_high_level,
                               min_size=minArea,
                               connectivity=1,
                               in_place=True)

    # output
    seg = seg > 0
    seg = seg.astype(np.uint8)
    seg[seg > 0] = 255

    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()