-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Create seg_PCNA workflows Two versions of PCNA segmentation workflows which includes OTSU masking of apoptotic debris. PCNA_lateS has fewest G1/late S/G2 errors. PCNA_earlyS_midS detects all dim early S / mid S phase spots but picks up bright G2 pixels. * update pcna workflow function names * Updated PCNA lateS workflow with hole filling 3D dot filter method creates holes if spot is too large. This workflow update addresses that issue. * Removed vesselness filter step * Added scipy import --------- Co-authored-by: Benjamin Morris <benjijamorris@gmail.com>
- Loading branch information
1 parent
c9c7b68
commit 1910df7
Showing
3 changed files
with
437 additions
and
0 deletions.
There are no files selected for viewing
138 changes: 138 additions & 0 deletions
138
aicssegmentation/structure_wrapper/seg_PCNA_earlyS_midS.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import numpy as np | ||
from typing import Union | ||
from pathlib import Path | ||
|
||
from aicssegmentation.core.vessel import vesselness3D | ||
from aicssegmentation.core.seg_dot import dot_3d | ||
from aicssegmentation.core.pre_processing_utils import ( | ||
intensity_normalization, | ||
edge_preserving_smoothing_3d, | ||
) | ||
from skimage.morphology import remove_small_objects | ||
from aicssegmentation.core.output_utils import ( | ||
save_segmentation, | ||
generate_segmentation_contour, | ||
) | ||
|
||
from skimage.filters import threshold_otsu | ||
|
||
|
||
def Workflow_PCNA_earlyS_midS( | ||
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 pcna | ||
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, 10] | ||
intensity_norm_param_otsu = [0.5, 15] | ||
scaling_factor = 1.0 | ||
vesselness_sigma = [1.0] | ||
vesselness_cutoff = 0.0125 | ||
minArea = 20 | ||
dot_3d_sigma = 1.0 | ||
########################################################################## | ||
|
||
out_img_list = [] | ||
out_name_list = [] | ||
|
||
################### | ||
# PRE_PROCESSING | ||
################### | ||
# intenisty normalization (min/max) | ||
struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) | ||
struct_img_otsu = intensity_normalization(struct_img, scaling_param=intensity_norm_param_otsu) | ||
|
||
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) | ||
structure_img_smooth_otsu = edge_preserving_smoothing_3d(struct_img_otsu) | ||
|
||
out_img_list.append(structure_img_smooth.copy()) | ||
out_name_list.append("im_smooth") | ||
out_img_list.append(structure_img_smooth_otsu.copy()) | ||
out_name_list.append("im_smooth_otsu") | ||
|
||
################### | ||
# core algorithm | ||
################### | ||
otsu_thresh = threshold_otsu(structure_img_smooth_otsu) | ||
global_thresh = otsu_thresh * scaling_factor | ||
bw_otsu_mask = structure_img_smooth_otsu > global_thresh | ||
|
||
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.035, min_size=150) | ||
bw_small = np.logical_xor(bw_small_inverse, response_s3_1 > 0.025) | ||
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_dots = np.logical_or(np.logical_or(bw_small, bw_medium), bw_large) | ||
bw = np.logical_and(bw_dots, bw_otsu_mask) | ||
|
||
################### | ||
# 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) | ||
|
||
from aicssegmentation.core.utils import remove_hot_pixel | ||
|
||
seg = seg > 0 | ||
seg_clean = remove_hot_pixel(seg) | ||
seg = seg_clean.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}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import numpy as np | ||
from typing import Union | ||
from pathlib import Path | ||
|
||
from aicssegmentation.core.vessel import vesselness3D | ||
from aicssegmentation.core.seg_dot import dot_3d | ||
from aicssegmentation.core.pre_processing_utils import ( | ||
intensity_normalization, | ||
edge_preserving_smoothing_3d, | ||
) | ||
from skimage.morphology import remove_small_objects | ||
from aicssegmentation.core.output_utils import ( | ||
save_segmentation, | ||
generate_segmentation_contour, | ||
) | ||
|
||
from skimage.filters import threshold_otsu | ||
|
||
|
||
def Workflow_PCNA_lateS( | ||
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 pcna | ||
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, 15] | ||
intensity_norm_param_otsu = [0.5, 15] | ||
scaling_factor = 1.0 | ||
vesselness_sigma = [1.0] | ||
vesselness_cutoff = 0.15 | ||
minArea = 30 | ||
dot_3d_sigma = 1.0 | ||
otsumask_min_area = 50 | ||
########################################################################## | ||
|
||
out_img_list = [] | ||
out_name_list = [] | ||
|
||
################### | ||
# PRE_PROCESSING | ||
################### | ||
# intenisty normalization (min/max) | ||
struct_img = intensity_normalization(struct_img, scaling_param=intensity_norm_param) | ||
struct_img_otsu = intensity_normalization(struct_img, scaling_param=intensity_norm_param_otsu) | ||
|
||
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) | ||
structure_img_smooth_otsu = edge_preserving_smoothing_3d(struct_img_otsu) | ||
|
||
|
||
out_img_list.append(structure_img_smooth.copy()) | ||
out_name_list.append("im_smooth") | ||
out_img_list.append(structure_img_smooth_otsu.copy()) | ||
out_name_list.append("im_smooth_otsu") | ||
|
||
|
||
################### | ||
# core algorithm | ||
################### | ||
otsu_thresh = threshold_otsu(structure_img_smooth_otsu) | ||
global_thresh = otsu_thresh * scaling_factor | ||
bw_otsu_mask = structure_img_smooth_otsu > global_thresh | ||
bw_otsu_mask_removesmallobjects = remove_small_objects( | ||
bw_otsu_mask, min_size=otsumask_min_area, connectivity=1, in_place=False | ||
) | ||
|
||
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.035, min_size=150) | ||
#bw_small = np.logical_xor(bw_small_inverse, response_s3_1 > 0.025) | ||
#bw_small = response_s3_1 > 0.12 | ||
bw_medium = response_s3_1 > 0.05 | ||
#bw_large = response_s3_3 > 0.45 | ||
#bw_large = np.logical_or(response_s3_3 > 0.45, response_f3 > 0.5) | ||
#bw_dots = np.logical_or(bw_medium, bw_large) | ||
#bw = np.logical_and(bw_dots, bw_otsu_mask_removesmallobjects) | ||
bw = np.logical_and(bw_medium, bw_otsu_mask_removesmallobjects) | ||
|
||
out_img_list.append(bw_otsu_mask.copy()) | ||
out_name_list.append("bw_otsu_mask") | ||
out_img_list.append(bw_otsu_mask_removesmallobjects.copy()) | ||
out_name_list.append("bw_otsu_mask_removesmallobjects") | ||
out_img_list.append(bw.copy()) | ||
out_name_list.append("bw") | ||
|
||
################### | ||
# 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) | ||
|
||
from aicssegmentation.core.utils import remove_hot_pixel | ||
|
||
seg = seg > 0 | ||
seg_clean = remove_hot_pixel(seg) | ||
seg = seg_clean.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}") |
Oops, something went wrong.