celldetective 1.4.1__py3-none-any.whl → 1.4.1.post1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- celldetective/_version.py +1 -1
- celldetective/gui/processes/segment_cells.py +438 -329
- {celldetective-1.4.1.dist-info → celldetective-1.4.1.post1.dist-info}/METADATA +1 -1
- {celldetective-1.4.1.dist-info → celldetective-1.4.1.post1.dist-info}/RECORD +8 -8
- {celldetective-1.4.1.dist-info → celldetective-1.4.1.post1.dist-info}/WHEEL +0 -0
- {celldetective-1.4.1.dist-info → celldetective-1.4.1.post1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.4.1.dist-info → celldetective-1.4.1.post1.dist-info}/licenses/LICENSE +0 -0
- {celldetective-1.4.1.dist-info → celldetective-1.4.1.post1.dist-info}/top_level.txt +0 -0
celldetective/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.4.1"
|
|
1
|
+
__version__ = "1.4.1.post1"
|
|
@@ -4,8 +4,28 @@ import datetime
|
|
|
4
4
|
import os
|
|
5
5
|
import json
|
|
6
6
|
import numpy as np
|
|
7
|
-
from celldetective.io import
|
|
8
|
-
|
|
7
|
+
from celldetective.io import (
|
|
8
|
+
extract_position_name,
|
|
9
|
+
locate_segmentation_model,
|
|
10
|
+
auto_load_number_of_frames,
|
|
11
|
+
load_frames,
|
|
12
|
+
_check_label_dims,
|
|
13
|
+
_load_frames_to_segment,
|
|
14
|
+
)
|
|
15
|
+
from celldetective.utils import (
|
|
16
|
+
_rescale_labels,
|
|
17
|
+
_segment_image_with_stardist_model,
|
|
18
|
+
_segment_image_with_cellpose_model,
|
|
19
|
+
_prep_stardist_model,
|
|
20
|
+
_prep_cellpose_model,
|
|
21
|
+
_get_normalize_kwargs_from_config,
|
|
22
|
+
extract_experiment_channels,
|
|
23
|
+
_estimate_scale_factor,
|
|
24
|
+
_extract_channel_indices_from_config,
|
|
25
|
+
config_section_to_dict,
|
|
26
|
+
_extract_nbr_channels_from_config,
|
|
27
|
+
_get_img_num_per_channel,
|
|
28
|
+
)
|
|
9
29
|
|
|
10
30
|
from pathlib import Path, PurePath
|
|
11
31
|
from glob import glob
|
|
@@ -13,378 +33,467 @@ from shutil import rmtree
|
|
|
13
33
|
from tqdm import tqdm
|
|
14
34
|
import numpy as np
|
|
15
35
|
from csbdeep.io import save_tiff_imagej_compatible
|
|
16
|
-
from celldetective.segmentation import
|
|
36
|
+
from celldetective.segmentation import (
|
|
37
|
+
segment_frame_from_thresholds,
|
|
38
|
+
merge_instance_segmentation,
|
|
39
|
+
)
|
|
17
40
|
import gc
|
|
18
41
|
from art import tprint
|
|
19
42
|
|
|
20
43
|
import concurrent.futures
|
|
21
44
|
|
|
45
|
+
|
|
22
46
|
class BaseSegmentProcess(Process):
|
|
23
47
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
48
|
+
def __init__(self, queue=None, process_args=None, *args, **kwargs):
|
|
49
|
+
|
|
50
|
+
super().__init__(*args, **kwargs)
|
|
51
|
+
|
|
52
|
+
self.queue = queue
|
|
53
|
+
|
|
54
|
+
if process_args is not None:
|
|
55
|
+
for key, value in process_args.items():
|
|
56
|
+
setattr(self, key, value)
|
|
29
57
|
|
|
30
|
-
|
|
31
|
-
for key, value in process_args.items():
|
|
32
|
-
setattr(self, key, value)
|
|
58
|
+
tprint("Segment")
|
|
33
59
|
|
|
34
|
-
|
|
60
|
+
# Experiment
|
|
61
|
+
self.locate_experiment_config()
|
|
35
62
|
|
|
36
|
-
|
|
37
|
-
|
|
63
|
+
print(f"Position: {extract_position_name(self.pos)}...")
|
|
64
|
+
print("Configuration file: ", self.config)
|
|
65
|
+
print(f"Population: {self.mode}...")
|
|
66
|
+
self.instruction_file = os.sep.join(
|
|
67
|
+
["configs", f"segmentation_instructions_{self.mode}.json"]
|
|
68
|
+
)
|
|
38
69
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
self.read_instructions()
|
|
45
|
-
self.extract_experiment_parameters()
|
|
46
|
-
self.detect_movie_length()
|
|
47
|
-
self.write_folders()
|
|
48
|
-
|
|
49
|
-
def read_instructions(self):
|
|
50
|
-
print('Looking for instruction file...')
|
|
51
|
-
instr_path = PurePath(self.exp_dir,Path(f"{self.instruction_file}"))
|
|
52
|
-
if os.path.exists(instr_path):
|
|
53
|
-
with open(instr_path, 'r') as f:
|
|
54
|
-
_instructions = json.load(f)
|
|
55
|
-
print(f"Measurement instruction file successfully loaded...")
|
|
56
|
-
print(f"Instructions: {_instructions}...")
|
|
57
|
-
self.flip = _instructions.get("flip", False)
|
|
58
|
-
else:
|
|
59
|
-
self.flip = False
|
|
70
|
+
self.read_instructions()
|
|
71
|
+
self.extract_experiment_parameters()
|
|
72
|
+
self.detect_movie_length()
|
|
73
|
+
self.write_folders()
|
|
60
74
|
|
|
75
|
+
def read_instructions(self):
|
|
76
|
+
print("Looking for instruction file...")
|
|
77
|
+
instr_path = PurePath(self.exp_dir, Path(f"{self.instruction_file}"))
|
|
78
|
+
if os.path.exists(instr_path):
|
|
79
|
+
with open(instr_path, "r") as f:
|
|
80
|
+
_instructions = json.load(f)
|
|
81
|
+
print(f"Measurement instruction file successfully loaded...")
|
|
82
|
+
print(f"Instructions: {_instructions}...")
|
|
83
|
+
self.flip = _instructions.get("flip", False)
|
|
84
|
+
else:
|
|
85
|
+
self.flip = False
|
|
61
86
|
|
|
62
|
-
|
|
87
|
+
def write_folders(self):
|
|
63
88
|
|
|
64
|
-
|
|
65
|
-
|
|
89
|
+
self.mode = self.mode.lower()
|
|
90
|
+
self.label_folder = f"labels_{self.mode}"
|
|
66
91
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
if os.path.exists(self.pos + self.label_folder):
|
|
93
|
+
print("Erasing the previous labels folder...")
|
|
94
|
+
rmtree(self.pos + self.label_folder)
|
|
95
|
+
os.mkdir(self.pos + self.label_folder)
|
|
96
|
+
print(f"Labels folder successfully generated...")
|
|
72
97
|
|
|
98
|
+
def extract_experiment_parameters(self):
|
|
73
99
|
|
|
74
|
-
|
|
100
|
+
self.spatial_calibration = float(
|
|
101
|
+
config_section_to_dict(self.config, "MovieSettings")["pxtoum"]
|
|
102
|
+
)
|
|
103
|
+
self.len_movie = float(
|
|
104
|
+
config_section_to_dict(self.config, "MovieSettings")["len_movie"]
|
|
105
|
+
)
|
|
106
|
+
self.movie_prefix = config_section_to_dict(self.config, "MovieSettings")[
|
|
107
|
+
"movie_prefix"
|
|
108
|
+
]
|
|
109
|
+
self.nbr_channels = _extract_nbr_channels_from_config(self.config)
|
|
110
|
+
self.channel_names, self.channel_indices = extract_experiment_channels(
|
|
111
|
+
self.exp_dir
|
|
112
|
+
)
|
|
75
113
|
|
|
76
|
-
|
|
77
|
-
self.len_movie = float(config_section_to_dict(self.config, "MovieSettings")["len_movie"])
|
|
78
|
-
self.movie_prefix = config_section_to_dict(self.config, "MovieSettings")["movie_prefix"]
|
|
79
|
-
self.nbr_channels = _extract_nbr_channels_from_config(self.config)
|
|
80
|
-
self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
|
|
114
|
+
def locate_experiment_config(self):
|
|
81
115
|
|
|
82
|
-
|
|
116
|
+
parent1 = Path(self.pos).parent
|
|
117
|
+
self.exp_dir = parent1.parent
|
|
118
|
+
self.config = PurePath(self.exp_dir, Path("config.ini"))
|
|
83
119
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
120
|
+
if not os.path.exists(self.config):
|
|
121
|
+
print(
|
|
122
|
+
"The configuration file for the experiment could not be located. Abort."
|
|
123
|
+
)
|
|
124
|
+
self.abort_process()
|
|
87
125
|
|
|
88
|
-
|
|
89
|
-
print('The configuration file for the experiment could not be located. Abort.')
|
|
90
|
-
self.abort_process()
|
|
126
|
+
def detect_movie_length(self):
|
|
91
127
|
|
|
92
|
-
|
|
128
|
+
try:
|
|
129
|
+
self.file = glob(self.pos + f"movie/{self.movie_prefix}*.tif")[0]
|
|
130
|
+
except Exception as e:
|
|
131
|
+
print(f"Error {e}.\nMovie could not be found. Check the prefix.")
|
|
132
|
+
self.abort_process()
|
|
93
133
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
print(f'Error {e}.\nMovie could not be found. Check the prefix.')
|
|
98
|
-
self.abort_process()
|
|
134
|
+
len_movie_auto = auto_load_number_of_frames(self.file)
|
|
135
|
+
if len_movie_auto is not None:
|
|
136
|
+
self.len_movie = len_movie_auto
|
|
99
137
|
|
|
100
|
-
|
|
101
|
-
if len_movie_auto is not None:
|
|
102
|
-
self.len_movie = len_movie_auto
|
|
138
|
+
def end_process(self):
|
|
103
139
|
|
|
104
|
-
|
|
140
|
+
self.terminate()
|
|
141
|
+
self.queue.put("finished")
|
|
105
142
|
|
|
106
|
-
|
|
107
|
-
self.queue.put("finished")
|
|
143
|
+
def abort_process(self):
|
|
108
144
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
self.terminate()
|
|
112
|
-
self.queue.put("error")
|
|
145
|
+
self.terminate()
|
|
146
|
+
self.queue.put("error")
|
|
113
147
|
|
|
114
148
|
|
|
115
149
|
class SegmentCellDLProcess(BaseSegmentProcess):
|
|
116
|
-
|
|
117
|
-
def __init__(self, *args, **kwargs):
|
|
118
|
-
|
|
119
|
-
super().__init__(*args, **kwargs)
|
|
120
150
|
|
|
121
|
-
|
|
151
|
+
def __init__(self, *args, **kwargs):
|
|
152
|
+
|
|
153
|
+
super().__init__(*args, **kwargs)
|
|
154
|
+
|
|
155
|
+
self.check_gpu()
|
|
156
|
+
|
|
157
|
+
# Model
|
|
158
|
+
self.locate_model_path()
|
|
159
|
+
self.extract_model_input_parameters()
|
|
160
|
+
self.detect_channels()
|
|
161
|
+
self.detect_rescaling()
|
|
122
162
|
|
|
123
|
-
|
|
124
|
-
self.locate_model_path()
|
|
125
|
-
self.extract_model_input_parameters()
|
|
126
|
-
self.detect_channels()
|
|
127
|
-
self.detect_rescaling()
|
|
163
|
+
self.write_log()
|
|
128
164
|
|
|
129
|
-
|
|
165
|
+
self.sum_done = 0
|
|
166
|
+
self.t0 = time.time()
|
|
130
167
|
|
|
131
|
-
|
|
132
|
-
self.t0 = time.time()
|
|
168
|
+
def extract_model_input_parameters(self):
|
|
133
169
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if 'selected_channels' in self.input_config:
|
|
138
|
-
self.required_channels = self.input_config['selected_channels']
|
|
139
|
-
|
|
140
|
-
self.target_cell_size = None
|
|
141
|
-
if 'target_cell_size_um' in self.input_config and 'cell_size_um' in self.input_config:
|
|
142
|
-
self.target_cell_size = self.input_config['target_cell_size_um']
|
|
143
|
-
self.cell_size = self.input_config['cell_size_um']
|
|
144
|
-
|
|
145
|
-
self.normalize_kwargs = _get_normalize_kwargs_from_config(self.input_config)
|
|
146
|
-
|
|
147
|
-
self.model_type = self.input_config['model_type']
|
|
148
|
-
self.required_spatial_calibration = self.input_config['spatial_calibration']
|
|
149
|
-
print(f'Spatial calibration expected by the model: {self.required_spatial_calibration}...')
|
|
150
|
-
|
|
151
|
-
if self.model_type=='cellpose':
|
|
152
|
-
self.diameter = self.input_config['diameter']
|
|
153
|
-
self.cellprob_threshold = self.input_config['cellprob_threshold']
|
|
154
|
-
self.flow_threshold = self.input_config['flow_threshold']
|
|
155
|
-
|
|
156
|
-
def write_log(self):
|
|
157
|
-
|
|
158
|
-
log=f'segmentation model: {self.model_name}\n'
|
|
159
|
-
with open(self.pos+f'log_{self.mode}.txt', 'a') as f:
|
|
160
|
-
f.write(f'{datetime.datetime.now()} SEGMENT \n')
|
|
161
|
-
f.write(log)
|
|
162
|
-
|
|
163
|
-
def detect_channels(self):
|
|
164
|
-
|
|
165
|
-
self.channel_indices = _extract_channel_indices_from_config(self.config, self.required_channels)
|
|
166
|
-
print(f'Required channels: {self.required_channels} located at channel indices {self.channel_indices}.')
|
|
167
|
-
self.img_num_channels = _get_img_num_per_channel(self.channel_indices, int(self.len_movie), self.nbr_channels)
|
|
168
|
-
|
|
169
|
-
def detect_rescaling(self):
|
|
170
|
-
|
|
171
|
-
self.scale = _estimate_scale_factor(self.spatial_calibration, self.required_spatial_calibration)
|
|
172
|
-
print(f"Scale: {self.scale}...")
|
|
173
|
-
|
|
174
|
-
if self.target_cell_size is not None and self.scale is not None:
|
|
175
|
-
self.scale *= self.cell_size / self.target_cell_size
|
|
176
|
-
elif self.target_cell_size is not None:
|
|
177
|
-
if self.target_cell_size != self.cell_size:
|
|
178
|
-
self.scale = self.cell_size / self.target_cell_size
|
|
179
|
-
|
|
180
|
-
print(f"Scale accounting for expected cell size: {self.scale}...")
|
|
181
|
-
|
|
182
|
-
def locate_model_path(self):
|
|
183
|
-
|
|
184
|
-
self.model_complete_path = locate_segmentation_model(self.model_name)
|
|
185
|
-
if self.model_complete_path is None:
|
|
186
|
-
print('Model could not be found. Abort.')
|
|
187
|
-
self.abort_process()
|
|
188
|
-
else:
|
|
189
|
-
print(f'Model path: {self.model_complete_path}...')
|
|
190
|
-
|
|
191
|
-
if not os.path.exists(self.model_complete_path+"config_input.json"):
|
|
192
|
-
print('The configuration for the inputs to the model could not be located. Abort.')
|
|
193
|
-
self.abort_process()
|
|
194
|
-
|
|
195
|
-
with open(self.model_complete_path+"config_input.json") as config_file:
|
|
196
|
-
self.input_config = json.load(config_file)
|
|
197
|
-
|
|
198
|
-
def check_gpu(self):
|
|
199
|
-
|
|
200
|
-
if not self.use_gpu:
|
|
201
|
-
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
|
|
202
|
-
|
|
203
|
-
def run(self):
|
|
204
|
-
|
|
205
|
-
try:
|
|
206
|
-
|
|
207
|
-
if self.model_type=='stardist':
|
|
208
|
-
model, scale_model = _prep_stardist_model(self.model_name, Path(self.model_complete_path).parent, use_gpu=self.use_gpu, scale=self.scale)
|
|
209
|
-
|
|
210
|
-
elif self.model_type=='cellpose':
|
|
211
|
-
model, scale_model = _prep_cellpose_model(self.model_name, self.model_complete_path, use_gpu=self.use_gpu, n_channels=len(self.required_channels), scale=self.scale)
|
|
212
|
-
|
|
213
|
-
list_indices = range(self.len_movie)
|
|
214
|
-
if self.flip:
|
|
215
|
-
list_indices = reversed(list_indices)
|
|
216
|
-
|
|
217
|
-
for t in tqdm(list_indices,desc="frame"):
|
|
218
|
-
|
|
219
|
-
f = _load_frames_to_segment(self.file, self.img_num_channels[:,t], scale_model=scale_model, normalize_kwargs=self.normalize_kwargs)
|
|
220
|
-
|
|
221
|
-
if self.model_type=="stardist":
|
|
222
|
-
Y_pred = _segment_image_with_stardist_model(f, model=model, return_details=False)
|
|
223
|
-
|
|
224
|
-
elif self.model_type=="cellpose":
|
|
225
|
-
Y_pred = _segment_image_with_cellpose_model(f, model=model, diameter=self.diameter, cellprob_threshold=self.cellprob_threshold, flow_threshold=self.flow_threshold)
|
|
226
|
-
|
|
227
|
-
if self.scale is not None:
|
|
228
|
-
Y_pred = _rescale_labels(Y_pred, scale_model=scale_model)
|
|
229
|
-
|
|
230
|
-
Y_pred = _check_label_dims(Y_pred, file=self.file)
|
|
231
|
-
|
|
232
|
-
save_tiff_imagej_compatible(self.pos+os.sep.join([self.label_folder,f"{str(t).zfill(4)}.tif"]), Y_pred, axes='YX')
|
|
233
|
-
|
|
234
|
-
del f;
|
|
235
|
-
del Y_pred;
|
|
236
|
-
gc.collect()
|
|
237
|
-
|
|
238
|
-
# Send signal for progress bar
|
|
239
|
-
self.sum_done+=1/self.len_movie*100
|
|
240
|
-
mean_exec_per_step = (time.time() - self.t0) / (t+1)
|
|
241
|
-
pred_time = (self.len_movie - (t+1)) * mean_exec_per_step
|
|
242
|
-
self.queue.put([self.sum_done, pred_time])
|
|
243
|
-
|
|
244
|
-
except Exception as e:
|
|
245
|
-
print(e)
|
|
246
|
-
|
|
247
|
-
try:
|
|
248
|
-
del model
|
|
249
|
-
except:
|
|
250
|
-
pass
|
|
251
|
-
|
|
252
|
-
gc.collect()
|
|
253
|
-
print("Done.")
|
|
170
|
+
self.required_channels = self.input_config["channels"]
|
|
171
|
+
if "selected_channels" in self.input_config:
|
|
172
|
+
self.required_channels = self.input_config["selected_channels"]
|
|
254
173
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
174
|
+
self.target_cell_size = None
|
|
175
|
+
if (
|
|
176
|
+
"target_cell_size_um" in self.input_config
|
|
177
|
+
and "cell_size_um" in self.input_config
|
|
178
|
+
):
|
|
179
|
+
self.target_cell_size = self.input_config["target_cell_size_um"]
|
|
180
|
+
self.cell_size = self.input_config["cell_size_um"]
|
|
181
|
+
|
|
182
|
+
self.normalize_kwargs = _get_normalize_kwargs_from_config(self.input_config)
|
|
183
|
+
|
|
184
|
+
self.model_type = self.input_config["model_type"]
|
|
185
|
+
self.required_spatial_calibration = self.input_config["spatial_calibration"]
|
|
186
|
+
print(
|
|
187
|
+
f"Spatial calibration expected by the model: {self.required_spatial_calibration}..."
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
if self.model_type == "cellpose":
|
|
191
|
+
self.diameter = self.input_config["diameter"]
|
|
192
|
+
self.cellprob_threshold = self.input_config["cellprob_threshold"]
|
|
193
|
+
self.flow_threshold = self.input_config["flow_threshold"]
|
|
194
|
+
|
|
195
|
+
def write_log(self):
|
|
196
|
+
|
|
197
|
+
log = f"segmentation model: {self.model_name}\n"
|
|
198
|
+
with open(self.pos + f"log_{self.mode}.txt", "a") as f:
|
|
199
|
+
f.write(f"{datetime.datetime.now()} SEGMENT \n")
|
|
200
|
+
f.write(log)
|
|
201
|
+
|
|
202
|
+
def detect_channels(self):
|
|
203
|
+
|
|
204
|
+
self.channel_indices = _extract_channel_indices_from_config(
|
|
205
|
+
self.config, self.required_channels
|
|
206
|
+
)
|
|
207
|
+
print(
|
|
208
|
+
f"Required channels: {self.required_channels} located at channel indices {self.channel_indices}."
|
|
209
|
+
)
|
|
210
|
+
self.img_num_channels = _get_img_num_per_channel(
|
|
211
|
+
self.channel_indices, int(self.len_movie), self.nbr_channels
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def detect_rescaling(self):
|
|
215
|
+
|
|
216
|
+
self.scale = _estimate_scale_factor(
|
|
217
|
+
self.spatial_calibration, self.required_spatial_calibration
|
|
218
|
+
)
|
|
219
|
+
print(f"Scale: {self.scale}...")
|
|
220
|
+
|
|
221
|
+
if self.target_cell_size is not None and self.scale is not None:
|
|
222
|
+
self.scale *= self.cell_size / self.target_cell_size
|
|
223
|
+
elif self.target_cell_size is not None:
|
|
224
|
+
if self.target_cell_size != self.cell_size:
|
|
225
|
+
self.scale = self.cell_size / self.target_cell_size
|
|
226
|
+
|
|
227
|
+
print(f"Scale accounting for expected cell size: {self.scale}...")
|
|
228
|
+
|
|
229
|
+
def locate_model_path(self):
|
|
230
|
+
|
|
231
|
+
self.model_complete_path = locate_segmentation_model(self.model_name)
|
|
232
|
+
if self.model_complete_path is None:
|
|
233
|
+
print("Model could not be found. Abort.")
|
|
234
|
+
self.abort_process()
|
|
235
|
+
else:
|
|
236
|
+
print(f"Model path: {self.model_complete_path}...")
|
|
237
|
+
|
|
238
|
+
if not os.path.exists(self.model_complete_path + "config_input.json"):
|
|
239
|
+
print(
|
|
240
|
+
"The configuration for the inputs to the model could not be located. Abort."
|
|
241
|
+
)
|
|
242
|
+
self.abort_process()
|
|
243
|
+
|
|
244
|
+
with open(self.model_complete_path + "config_input.json") as config_file:
|
|
245
|
+
self.input_config = json.load(config_file)
|
|
246
|
+
|
|
247
|
+
def check_gpu(self):
|
|
248
|
+
|
|
249
|
+
if not self.use_gpu:
|
|
250
|
+
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
|
251
|
+
|
|
252
|
+
def run(self):
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
|
|
256
|
+
if self.model_type == "stardist":
|
|
257
|
+
model, scale_model = _prep_stardist_model(
|
|
258
|
+
self.model_name,
|
|
259
|
+
Path(self.model_complete_path).parent,
|
|
260
|
+
use_gpu=self.use_gpu,
|
|
261
|
+
scale=self.scale,
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
elif self.model_type == "cellpose":
|
|
265
|
+
model, scale_model = _prep_cellpose_model(
|
|
266
|
+
self.model_name,
|
|
267
|
+
self.model_complete_path,
|
|
268
|
+
use_gpu=self.use_gpu,
|
|
269
|
+
n_channels=len(self.required_channels),
|
|
270
|
+
scale=self.scale,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
list_indices = range(self.len_movie)
|
|
274
|
+
if self.flip:
|
|
275
|
+
list_indices = reversed(list_indices)
|
|
276
|
+
|
|
277
|
+
for i, t in enumerate(tqdm(list_indices, desc="frame")):
|
|
278
|
+
|
|
279
|
+
f = _load_frames_to_segment(
|
|
280
|
+
self.file,
|
|
281
|
+
self.img_num_channels[:, t],
|
|
282
|
+
scale_model=scale_model,
|
|
283
|
+
normalize_kwargs=self.normalize_kwargs,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
if self.model_type == "stardist":
|
|
287
|
+
Y_pred = _segment_image_with_stardist_model(
|
|
288
|
+
f, model=model, return_details=False
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
elif self.model_type == "cellpose":
|
|
292
|
+
Y_pred = _segment_image_with_cellpose_model(
|
|
293
|
+
f,
|
|
294
|
+
model=model,
|
|
295
|
+
diameter=self.diameter,
|
|
296
|
+
cellprob_threshold=self.cellprob_threshold,
|
|
297
|
+
flow_threshold=self.flow_threshold,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
if self.scale is not None:
|
|
301
|
+
Y_pred = _rescale_labels(Y_pred, scale_model=scale_model)
|
|
302
|
+
|
|
303
|
+
Y_pred = _check_label_dims(Y_pred, file=self.file)
|
|
304
|
+
|
|
305
|
+
save_tiff_imagej_compatible(
|
|
306
|
+
self.pos
|
|
307
|
+
+ os.sep.join([self.label_folder, f"{str(t).zfill(4)}.tif"]),
|
|
308
|
+
Y_pred,
|
|
309
|
+
axes="YX",
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
del f
|
|
313
|
+
del Y_pred
|
|
314
|
+
gc.collect()
|
|
315
|
+
|
|
316
|
+
# Send signal for progress bar
|
|
317
|
+
self.sum_done += 1 / self.len_movie * 100
|
|
318
|
+
mean_exec_per_step = (time.time() - self.t0) / (i + 1)
|
|
319
|
+
pred_time = (self.len_movie - (i + 1)) * mean_exec_per_step
|
|
320
|
+
self.queue.put([self.sum_done, pred_time])
|
|
321
|
+
|
|
322
|
+
except Exception as e:
|
|
323
|
+
print(e)
|
|
324
|
+
|
|
325
|
+
try:
|
|
326
|
+
del model
|
|
327
|
+
except:
|
|
328
|
+
pass
|
|
329
|
+
|
|
330
|
+
gc.collect()
|
|
331
|
+
print("Done.")
|
|
332
|
+
|
|
333
|
+
# Send end signal
|
|
334
|
+
self.queue.put("finished")
|
|
335
|
+
self.queue.close()
|
|
258
336
|
|
|
259
337
|
|
|
260
338
|
class SegmentCellThresholdProcess(BaseSegmentProcess):
|
|
261
|
-
|
|
262
|
-
def __init__(self, *args, **kwargs):
|
|
263
|
-
|
|
264
|
-
super().__init__(*args, **kwargs)
|
|
265
339
|
|
|
266
|
-
|
|
340
|
+
def __init__(self, *args, **kwargs):
|
|
341
|
+
|
|
342
|
+
super().__init__(*args, **kwargs)
|
|
343
|
+
|
|
344
|
+
self.equalize = False
|
|
345
|
+
|
|
346
|
+
# Model
|
|
347
|
+
|
|
348
|
+
self.load_threshold_config()
|
|
349
|
+
self.extract_threshold_parameters()
|
|
350
|
+
self.detect_channels()
|
|
351
|
+
self.prepare_equalize()
|
|
267
352
|
|
|
268
|
-
|
|
353
|
+
self.write_log()
|
|
269
354
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
self.detect_channels()
|
|
273
|
-
self.prepare_equalize()
|
|
355
|
+
self.sum_done = 0
|
|
356
|
+
self.t0 = time.time()
|
|
274
357
|
|
|
275
|
-
|
|
358
|
+
def prepare_equalize(self):
|
|
276
359
|
|
|
277
|
-
|
|
278
|
-
self.t0 = time.time()
|
|
360
|
+
for i in range(len(self.instructions)):
|
|
279
361
|
|
|
280
|
-
|
|
362
|
+
if self.equalize[i]:
|
|
363
|
+
f_reference = load_frames(
|
|
364
|
+
self.img_num_channels[:, self.equalize_time[i]],
|
|
365
|
+
self.file,
|
|
366
|
+
scale=None,
|
|
367
|
+
normalize_input=False,
|
|
368
|
+
)
|
|
369
|
+
f_reference = f_reference[:, :, self.instructions[i]["target_channel"]]
|
|
370
|
+
else:
|
|
371
|
+
f_reference = None
|
|
372
|
+
|
|
373
|
+
self.instructions[i].update({"equalize_reference": f_reference})
|
|
374
|
+
|
|
375
|
+
def load_threshold_config(self):
|
|
281
376
|
|
|
282
|
-
|
|
377
|
+
self.instructions = []
|
|
378
|
+
for inst in self.threshold_instructions:
|
|
379
|
+
if os.path.exists(inst):
|
|
380
|
+
with open(inst, "r") as f:
|
|
381
|
+
self.instructions.append(json.load(f))
|
|
382
|
+
else:
|
|
383
|
+
print("The configuration path is not valid. Abort.")
|
|
384
|
+
self.abort_process()
|
|
283
385
|
|
|
284
|
-
|
|
285
|
-
f_reference = load_frames(self.img_num_channels[:,self.equalize_time[i]], self.file, scale=None, normalize_input=False)
|
|
286
|
-
f_reference = f_reference[:,:,self.instructions[i]['target_channel']]
|
|
287
|
-
else:
|
|
288
|
-
f_reference = None
|
|
289
|
-
|
|
290
|
-
self.instructions[i].update({'equalize_reference': f_reference})
|
|
291
|
-
|
|
292
|
-
def load_threshold_config(self):
|
|
293
|
-
|
|
294
|
-
self.instructions = []
|
|
295
|
-
for inst in self.threshold_instructions:
|
|
296
|
-
if os.path.exists(inst):
|
|
297
|
-
with open(inst, 'r') as f:
|
|
298
|
-
self.instructions.append(json.load(f))
|
|
299
|
-
else:
|
|
300
|
-
print('The configuration path is not valid. Abort.')
|
|
301
|
-
self.abort_process()
|
|
302
|
-
|
|
303
|
-
def extract_threshold_parameters(self):
|
|
304
|
-
|
|
305
|
-
self.required_channels = []
|
|
306
|
-
self.equalize = []
|
|
307
|
-
self.equalize_time = []
|
|
308
|
-
|
|
309
|
-
for i in range(len(self.instructions)):
|
|
310
|
-
ch = [self.instructions[i]['target_channel']]
|
|
311
|
-
self.required_channels.append(ch)
|
|
312
|
-
|
|
313
|
-
if 'equalize_reference' in self.instructions[i]:
|
|
314
|
-
equalize, equalize_time = self.instructions[i]['equalize_reference']
|
|
315
|
-
self.equalize.append(equalize)
|
|
316
|
-
self.equalize_time.append(equalize_time)
|
|
317
|
-
|
|
318
|
-
def write_log(self):
|
|
319
|
-
|
|
320
|
-
log=f'Threshold segmentation: {self.threshold_instructions}\n'
|
|
321
|
-
with open(self.pos+f'log_{self.mode}.txt', 'a') as f:
|
|
322
|
-
f.write(f'{datetime.datetime.now()} SEGMENT \n')
|
|
323
|
-
f.write(log)
|
|
324
|
-
|
|
325
|
-
def detect_channels(self):
|
|
326
|
-
|
|
327
|
-
for i in range(len(self.instructions)):
|
|
328
|
-
|
|
329
|
-
self.channel_indices = _extract_channel_indices_from_config(self.config, self.required_channels[i])
|
|
330
|
-
print(f'Required channels: {self.required_channels[i]} located at channel indices {self.channel_indices}.')
|
|
331
|
-
self.instructions[i].update({'target_channel': self.channel_indices[0]})
|
|
332
|
-
self.instructions[i].update({'channel_names': self.channel_names})
|
|
333
|
-
|
|
334
|
-
self.img_num_channels = _get_img_num_per_channel(np.arange(self.nbr_channels), self.len_movie, self.nbr_channels)
|
|
335
|
-
|
|
336
|
-
def parallel_job(self, indices):
|
|
337
|
-
|
|
338
|
-
try:
|
|
339
|
-
|
|
340
|
-
for t in tqdm(indices,desc="frame"): #for t in tqdm(range(self.len_movie),desc="frame"):
|
|
341
|
-
|
|
342
|
-
# Load channels at time t
|
|
343
|
-
masks = []
|
|
344
|
-
for i in range(len(self.instructions)):
|
|
345
|
-
f = load_frames(self.img_num_channels[:,t], self.file, scale=None, normalize_input=False)
|
|
346
|
-
mask = segment_frame_from_thresholds(f, **self.instructions[i])
|
|
347
|
-
#print(f'Frame {t}; segment with {self.instructions[i]=}...')
|
|
348
|
-
masks.append(mask)
|
|
349
|
-
|
|
350
|
-
if len(self.instructions)>1:
|
|
351
|
-
mask = merge_instance_segmentation(masks, mode='OR')
|
|
352
|
-
|
|
353
|
-
save_tiff_imagej_compatible(os.sep.join([self.pos, self.label_folder, f"{str(t).zfill(4)}.tif"]), mask.astype(np.uint16), axes='YX')
|
|
354
|
-
|
|
355
|
-
del f;
|
|
356
|
-
del mask;
|
|
357
|
-
gc.collect()
|
|
358
|
-
|
|
359
|
-
# Send signal for progress bar
|
|
360
|
-
self.sum_done+=1/self.len_movie*100
|
|
361
|
-
mean_exec_per_step = (time.time() - self.t0) / (self.sum_done*self.len_movie / 100 + 1)
|
|
362
|
-
pred_time = (self.len_movie - (self.sum_done*self.len_movie / 100 + 1)) * mean_exec_per_step
|
|
363
|
-
self.queue.put([self.sum_done, pred_time])
|
|
386
|
+
def extract_threshold_parameters(self):
|
|
364
387
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
388
|
+
self.required_channels = []
|
|
389
|
+
self.equalize = []
|
|
390
|
+
self.equalize_time = []
|
|
391
|
+
|
|
392
|
+
for i in range(len(self.instructions)):
|
|
393
|
+
ch = [self.instructions[i]["target_channel"]]
|
|
394
|
+
self.required_channels.append(ch)
|
|
395
|
+
|
|
396
|
+
if "equalize_reference" in self.instructions[i]:
|
|
397
|
+
equalize, equalize_time = self.instructions[i]["equalize_reference"]
|
|
398
|
+
self.equalize.append(equalize)
|
|
399
|
+
self.equalize_time.append(equalize_time)
|
|
400
|
+
|
|
401
|
+
def write_log(self):
|
|
402
|
+
|
|
403
|
+
log = f"Threshold segmentation: {self.threshold_instructions}\n"
|
|
404
|
+
with open(self.pos + f"log_{self.mode}.txt", "a") as f:
|
|
405
|
+
f.write(f"{datetime.datetime.now()} SEGMENT \n")
|
|
406
|
+
f.write(log)
|
|
407
|
+
|
|
408
|
+
def detect_channels(self):
|
|
409
|
+
|
|
410
|
+
for i in range(len(self.instructions)):
|
|
411
|
+
|
|
412
|
+
self.channel_indices = _extract_channel_indices_from_config(
|
|
413
|
+
self.config, self.required_channels[i]
|
|
414
|
+
)
|
|
415
|
+
print(
|
|
416
|
+
f"Required channels: {self.required_channels[i]} located at channel indices {self.channel_indices}."
|
|
417
|
+
)
|
|
418
|
+
self.instructions[i].update({"target_channel": self.channel_indices[0]})
|
|
419
|
+
self.instructions[i].update({"channel_names": self.channel_names})
|
|
420
|
+
|
|
421
|
+
self.img_num_channels = _get_img_num_per_channel(
|
|
422
|
+
np.arange(self.nbr_channels), self.len_movie, self.nbr_channels
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
def parallel_job(self, indices):
|
|
426
|
+
|
|
427
|
+
try:
|
|
428
|
+
|
|
429
|
+
for t in tqdm(
|
|
430
|
+
indices, desc="frame"
|
|
431
|
+
): # for t in tqdm(range(self.len_movie),desc="frame"):
|
|
432
|
+
|
|
433
|
+
# Load channels at time t
|
|
434
|
+
masks = []
|
|
435
|
+
for i in range(len(self.instructions)):
|
|
436
|
+
f = load_frames(
|
|
437
|
+
self.img_num_channels[:, t],
|
|
438
|
+
self.file,
|
|
439
|
+
scale=None,
|
|
440
|
+
normalize_input=False,
|
|
441
|
+
)
|
|
442
|
+
mask = segment_frame_from_thresholds(f, **self.instructions[i])
|
|
443
|
+
# print(f'Frame {t}; segment with {self.instructions[i]=}...')
|
|
444
|
+
masks.append(mask)
|
|
445
|
+
|
|
446
|
+
if len(self.instructions) > 1:
|
|
447
|
+
mask = merge_instance_segmentation(masks, mode="OR")
|
|
448
|
+
|
|
449
|
+
save_tiff_imagej_compatible(
|
|
450
|
+
os.sep.join(
|
|
451
|
+
[self.pos, self.label_folder, f"{str(t).zfill(4)}.tif"]
|
|
452
|
+
),
|
|
453
|
+
mask.astype(np.uint16),
|
|
454
|
+
axes="YX",
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
del f
|
|
458
|
+
del mask
|
|
459
|
+
gc.collect()
|
|
460
|
+
|
|
461
|
+
# Send signal for progress bar
|
|
462
|
+
self.sum_done += 1 / self.len_movie * 100
|
|
463
|
+
mean_exec_per_step = (time.time() - self.t0) / (
|
|
464
|
+
self.sum_done * self.len_movie / 100 + 1
|
|
465
|
+
)
|
|
466
|
+
pred_time = (
|
|
467
|
+
self.len_movie - (self.sum_done * self.len_movie / 100 + 1)
|
|
468
|
+
) * mean_exec_per_step
|
|
469
|
+
self.queue.put([self.sum_done, pred_time])
|
|
470
|
+
|
|
471
|
+
except Exception as e:
|
|
472
|
+
print(e)
|
|
473
|
+
|
|
474
|
+
return
|
|
475
|
+
|
|
476
|
+
def run(self):
|
|
477
|
+
|
|
478
|
+
self.indices = list(range(self.img_num_channels.shape[1]))
|
|
479
|
+
if self.flip:
|
|
480
|
+
self.indices = np.array(list(reversed(self.indices)))
|
|
481
|
+
|
|
482
|
+
chunks = np.array_split(self.indices, self.n_threads)
|
|
483
|
+
|
|
484
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
485
|
+
max_workers=self.n_threads
|
|
486
|
+
) as executor:
|
|
487
|
+
results = results = executor.map(
|
|
488
|
+
self.parallel_job, chunks
|
|
489
|
+
) # list(map(lambda x: executor.submit(self.parallel_job, x), chunks))
|
|
490
|
+
try:
|
|
491
|
+
for i, return_value in enumerate(results):
|
|
492
|
+
print(f"Thread {i} output check: ", return_value)
|
|
493
|
+
except Exception as e:
|
|
494
|
+
print("Exception: ", e)
|
|
495
|
+
|
|
496
|
+
print("Done.")
|
|
497
|
+
# Send end signal
|
|
498
|
+
self.queue.put("finished")
|
|
499
|
+
self.queue.close()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
celldetective/__init__.py,sha256=ZygAIkX6Nbjag1czWdQa-yP-GM1mBE_9ss21Xh__JFc,34
|
|
2
2
|
celldetective/__main__.py,sha256=bxTlSvbKhqn3LW_azd2baDCnDsgb37PAP9DfuAJ1_5M,1844
|
|
3
|
-
celldetective/_version.py,sha256=
|
|
3
|
+
celldetective/_version.py,sha256=qNcXPduXDwgAlIy4Zl5BtVTAzShWuh2BZCrIqovJzsk,28
|
|
4
4
|
celldetective/events.py,sha256=n15R53c7QZ2wT8gjb0oeNikQbuRBrVVbyNsRCqXjzXA,8166
|
|
5
5
|
celldetective/exceptions.py,sha256=f3VmIYOthWTiqMEV5xQCox2rw5c5e7yog88h-CcV4oI,356
|
|
6
6
|
celldetective/extra_properties.py,sha256=QxXl-zug3NyxZMNTJUsDxo8PHLIRt0AwOFUkTyYBv7E,19987
|
|
@@ -55,7 +55,7 @@ celldetective/gui/help/tracking.json,sha256=yIAoOToqCSQ_XF4gwEZCcyXcvQ3mROju263Z
|
|
|
55
55
|
celldetective/gui/processes/compute_neighborhood.py,sha256=J0T1DaG58p1nB0_WseVbl3AL5jb76W0hzFaSNci5EDU,29181
|
|
56
56
|
celldetective/gui/processes/downloader.py,sha256=jnNitmQ9xUCGJHSvr3Myts5soe6rdYDBx_AGJKr1AWk,3406
|
|
57
57
|
celldetective/gui/processes/measure_cells.py,sha256=XAw6SnT14EXfJXZ01bQ2FmPLGYWJHnX9Nko25RH0ZIo,13388
|
|
58
|
-
celldetective/gui/processes/segment_cells.py,sha256=
|
|
58
|
+
celldetective/gui/processes/segment_cells.py,sha256=SS1Pg-vPDYo2qfcCB9wDBi5nWr7Mmp9IBpPRAqZaOJ4,16266
|
|
59
59
|
celldetective/gui/processes/track_cells.py,sha256=4t6UZE_dyiryDH9e-G6jdINzdXHXi8BTta2v1gI0w3Q,10165
|
|
60
60
|
celldetective/gui/processes/train_segmentation_model.py,sha256=bvcPG19hBjhNY9hd6Ch5_wk2FOJYQg97Azoz4RKeP-0,10776
|
|
61
61
|
celldetective/gui/processes/train_signal_model.py,sha256=qqqkq9gdvNyvycYkmzWgRXWvsbEozyzNWP_POGvnlIs,3816
|
|
@@ -101,7 +101,7 @@ celldetective/scripts/segment_cells_thresholds.py,sha256=JanfXVbekgxDosKJDU9SejM
|
|
|
101
101
|
celldetective/scripts/track_cells.py,sha256=GfCqXHsuS8k5jizY4tGye2l6Vwkoenb4_VjBq_dMDyI,8892
|
|
102
102
|
celldetective/scripts/train_segmentation_model.py,sha256=8QXyhQtxBhdYBNleqCbkP3II1AztfrtpyeVyx0Ijy6s,9710
|
|
103
103
|
celldetective/scripts/train_signal_model.py,sha256=D643wKVYg-LWHF2VU9FWKSuazXrpCpQK0YjGqoIimD0,3167
|
|
104
|
-
celldetective-1.4.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
104
|
+
celldetective-1.4.1.post1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
105
105
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
106
|
tests/test_events.py,sha256=eLFwwEEJfQAdwhews3-fn1HSvzozcNNFN_Qn0gOvQkE,685
|
|
107
107
|
tests/test_filters.py,sha256=iJksl_HgquqGzPPv46qpNtlD4rkBpZ5eVtIotgZ7LDs,656
|
|
@@ -116,8 +116,8 @@ tests/test_utils.py,sha256=NKRCAC1d89aBK5cWjTb7-pInYow901RrT-uBlIdz4KI,3692
|
|
|
116
116
|
tests/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
117
117
|
tests/gui/test_new_project.py,sha256=D3166GefxQeOBw3Uc2nC_wzklF6b_86xrPiLC46jbUk,8228
|
|
118
118
|
tests/gui/test_project.py,sha256=scDr50WAZybTkeTPPphGvor1VL9nHQXUIjvScdxmAmI,4146
|
|
119
|
-
celldetective-1.4.1.dist-info/METADATA,sha256=
|
|
120
|
-
celldetective-1.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
121
|
-
celldetective-1.4.1.dist-info/entry_points.txt,sha256=2NU6_EOByvPxqBbCvjwxlVlvnQreqZ3BKRCVIKEv3dg,62
|
|
122
|
-
celldetective-1.4.1.dist-info/top_level.txt,sha256=6rsIKKfGMKgud7HPuATcpq6EhdXwcg_yknBVWn9x4C4,20
|
|
123
|
-
celldetective-1.4.1.dist-info/RECORD,,
|
|
119
|
+
celldetective-1.4.1.post1.dist-info/METADATA,sha256=OtZPgPhQcFUBCJFOYy9xHZQo8grDtWn2gon2UigZZ8c,10951
|
|
120
|
+
celldetective-1.4.1.post1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
121
|
+
celldetective-1.4.1.post1.dist-info/entry_points.txt,sha256=2NU6_EOByvPxqBbCvjwxlVlvnQreqZ3BKRCVIKEv3dg,62
|
|
122
|
+
celldetective-1.4.1.post1.dist-info/top_level.txt,sha256=6rsIKKfGMKgud7HPuATcpq6EhdXwcg_yknBVWn9x4C4,20
|
|
123
|
+
celldetective-1.4.1.post1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|