@@ -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+
1872def 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
42129def 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