Skip to content

Commit 326bc96

Browse files
Update doc strings
1 parent 431c748 commit 326bc96

File tree

1 file changed

+153
-23
lines changed
  • flamingo_tools/segmentation

1 file changed

+153
-23
lines changed

flamingo_tools/segmentation/cli.py

Lines changed: 153 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,52 +11,182 @@ def _get_model_path(model_type, checkpoint_path=None):
1111
if checkpoint_path is None:
1212
model_path = get_model_path(model_type)
1313
else:
14-
model_path = ... # TODO
14+
model_path = checkpoint_path
1515
return model_path
1616

1717

18+
def _parse_kwargs(extra_kwargs, **default_kwargs):
19+
def _convert_argval(value):
20+
# The values for the parsed arguments need to be in the expected input structure as provided.
21+
# i.e. integers and floats should be in their original types.
22+
try:
23+
return int(value)
24+
except ValueError:
25+
return float(value)
26+
27+
extra_kwargs = {
28+
extra_kwargs[i].lstrip("--"): _convert_argval(extra_kwargs[i + 1]) for i in range(0, len(extra_kwargs), 2)
29+
}
30+
31+
known_kwargs, unknown_kwargs = {}, {}
32+
for name, val in extra_kwargs.items():
33+
if name in default_kwargs:
34+
known_kwargs[name] = val
35+
else:
36+
unknown_kwargs[name] = val
37+
38+
missing_default_kwargs = {name: val for name, val in default_kwargs.items() if name not in known_kwargs}
39+
if unknown_kwargs:
40+
raise ValueError(
41+
f"The following options are not supported: {list(unknown_kwargs.keys())}."
42+
f"Did you mean any of the following additional options: {list(missing_default_kwargs.keys())}?"
43+
)
44+
45+
known_kwargs.update(missing_default_kwargs)
46+
return known_kwargs
47+
48+
49+
def _parse_segmentation_kwargs(extra_kwargs, model_type):
50+
if model_type.startswith("SGN"):
51+
default_kwargs = {
52+
"center_distance_threshold": 0.4,
53+
"boundary_distance_threshold": None,
54+
"fg_threshold": 0.5,
55+
"distance_smoothing": 0.0,
56+
"seg_class": "sgn_low" if model_type == "SGN-lowres" else "sgn",
57+
}
58+
else:
59+
assert model_type.startswith("IHC")
60+
default_kwargs = {
61+
"center_distance_threshold": 0.4,
62+
"boundary_distance_threshold": None,
63+
"fg_threshold": 0.5,
64+
"distance_smoothing": 0.0,
65+
"seg_class": "ihc",
66+
}
67+
68+
kwargs = _parse_kwargs(extra_kwargs, **default_kwargs)
69+
return kwargs
70+
71+
1872
def run_segmentation():
1973
"""private
2074
"""
21-
parser = argparse.ArgumentParser(description="")
22-
parser.add_argument("-i", "--input_path", required=True, help="The path to the input data.")
23-
parser.add_argument("-k", "--input_key", help="The key to the input data.")
24-
parser.add_argument("-o", "--output_folder", required=True)
25-
parser.add_argument("-m", "--model_type", required=True)
26-
parser.add_argument("-c", "--checkpoint_path")
27-
parser.add_argument("--min_size", type=int, default=250)
28-
# TODO other stuff
29-
args = parser.parse_args()
30-
3175
segmentation_models = ["SGN", "IHC", "SGN-lowres", "IHC-lowres"]
76+
77+
parser = argparse.ArgumentParser(
78+
description="Segment individual cells in volumetric light microscopy data. "
79+
"This function supports the segmentation of SGNs and IHCs, at high- and low-resolution. "
80+
"Which model to use is specified with the argument '--model_type' ('-m'). "
81+
"It also supports custom models via the (optional) argument '--checkpoint_path' ('-c'). "
82+
)
83+
parser.add_argument(
84+
"-i", "--input_path", required=True,
85+
help="The path to the input data. Supports .tif, .zarr, .h5 or .n5 files. "
86+
"Zarr, HDF5 or N5 files also require the 'input_key' argument."
87+
)
88+
parser.add_argument(
89+
"-k", "--input_key",
90+
help="The key to the input data. This refers to an internal data path for Zarr, HDF5 or N5 data."
91+
)
92+
parser.add_argument(
93+
"-o", "--output_folder", required=True,
94+
help="The output folder where the segmentation result and intermediates are stored. "
95+
"The segmentation result is stored in the file 'segmentation.zarr' under the key 'segmentation'."
96+
)
97+
parser.add_argument(
98+
"-m", "--model_type", required=True,
99+
help=f"The model to use for segmentation. One of {segmentation_models}.",
100+
)
101+
parser.add_argument(
102+
"-c", "--checkpoint_path",
103+
help="Path to the checkpoint of a customly fine-tuned model (optional).",
104+
)
105+
parser.add_argument(
106+
"--min_size", type=int, default=250,
107+
help="The minimum size of cells in the resulting segmentation.",
108+
)
109+
parser.add_argument(
110+
"--disable_masking", action="store_true",
111+
help="Whether to disable intensity-based masking. By default, "
112+
"segmentation is only applied for parts of the data with foreground signal."
113+
)
114+
args, extra_kwargs = parser.parse_known_args()
115+
32116
if args.model_type not in segmentation_models:
33-
raise ValueError
117+
raise ValueError(f"Unknown model: {args.model_type}. Choose one of {segmentation_models}.")
118+
segmentation_kwargs = _parse_segmentation_kwargs(extra_kwargs, args.model_type)
119+
34120
model_path = _get_model_path(args.model_type, args.checkpoint_path)
35121
run_unet_prediction(
36122
input_path=args.input_path, input_key=args.input_key,
37123
output_folder=args.output_folder, model_path=model_path,
38-
min_size=args.min_size,
124+
min_size=args.min_size, use_mask=args.disable_masking,
125+
**segmentation_kwargs,
39126
)
40127

41128

42129
def run_detection():
43130
"""private
44131
"""
45-
parser = argparse.ArgumentParser()
46-
parser.add_argument("-i", "--input_path", required=True, help="The path to the input data.")
47-
parser.add_argument("-k", "--input_key", help="The key to the input data.")
48-
parser.add_argument("-o", "--output_folder", required=True)
49-
parser.add_argument("-m", "--model_type", default="Synapses")
50-
parser.add_argument("--mask_path")
51-
parser.add_argument("--mask_key")
52-
parser.add_argument("-c", "--checkpoint_path")
53-
args = parser.parse_args()
54132
detection_models = ["Synapses"]
133+
134+
parser = argparse.ArgumentParser(
135+
description="Detect spot intensity signals in volumetric light microscopy data. "
136+
"This function supports the detection of synapses in high-resolution light-microscopy data. "
137+
"It also supports custom models via the (optional) argument '--checkpoint_path' ('-c'). "
138+
)
139+
parser.add_argument(
140+
"-i", "--input_path", required=True,
141+
help="The path to the input data. Supports .tif, .zarr, .h5 or .n5 files."
142+
"Zarr, HDF5 or N5 files also require the 'input_key' argument."
143+
)
144+
parser.add_argument(
145+
"-k", "--input_key",
146+
help="The key to the input data. This refers to an internal data path for Zarr, HDF5 or N5 data."
147+
)
148+
parser.add_argument(
149+
"-o", "--output_folder", required=True,
150+
help="The output folder where the detectio result and intermediates are stored. "
151+
"The result is stored in the file 'synapse_detection.tsv'. "
152+
"In case detections are assigned to segmentation masks and filtered (via '--mask_path' and '--mask_key'), "
153+
"the corresponding results are stored in 'synapse_detection_filtered.tsv'."
154+
155+
)
156+
parser.add_argument(
157+
"-m", "--model_type", default="Synapses",
158+
help=f"The model to use for detection. One of {detection_models}.",
159+
)
160+
parser.add_argument(
161+
"-c", "--checkpoint_path",
162+
help="Path to the checkpoint of a customly fine-tuned model (optional).",
163+
)
164+
parser.add_argument(
165+
"--mask_path",
166+
help="Path to a segmentation mask to use for assigning and filtering the detected synapses (optional). "
167+
"If given, each detected synapse will be assigned to the closest object in the segmentation and "
168+
"synapses that are more distant than 'max_distance' will be removed from the result."
169+
)
170+
parser.add_argument(
171+
"--mask_key",
172+
help="The key to the mask data. Refers to an internal data path, see '--input_key' ('-k') for details."
173+
)
174+
parser.add_argument(
175+
"--max_distance", type=float, default=2.0,
176+
help="The maximal distance (in microns) for matching synapses to segmented cells. "
177+
"Synapses with a larger distance will be filtered from the result."
178+
)
179+
parser.add_argument(
180+
"--resolution", type=float, default=0.38, help="The resolution of the data (in microns)."
181+
)
182+
args = parser.parse_args()
55183
if args.model_type not in detection_models:
56-
raise ValueError
184+
raise ValueError(f"Unknown model: {args.model_type}. Choose one of {detection_models}.")
185+
57186
model_path = _get_model_path(args.model_type, args.checkpoint_path)
58187
marker_detection(
59188
input_path=args.input_path, input_key=args.input_key,
60189
output_folder=args.output_folder, model_path=model_path,
61190
mask_path=args.mask_path, mask_input_key=args.mask_key,
191+
max_distance=args.max_distance, resolution=args.resolution,
62192
)

0 commit comments

Comments
 (0)