celldetective 1.4.2__py3-none-any.whl → 1.5.0b1__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.
Files changed (152) hide show
  1. celldetective/__init__.py +25 -0
  2. celldetective/__main__.py +62 -43
  3. celldetective/_version.py +1 -1
  4. celldetective/extra_properties.py +477 -399
  5. celldetective/filters.py +192 -97
  6. celldetective/gui/InitWindow.py +541 -411
  7. celldetective/gui/__init__.py +0 -15
  8. celldetective/gui/about.py +44 -39
  9. celldetective/gui/analyze_block.py +120 -84
  10. celldetective/gui/base/__init__.py +0 -0
  11. celldetective/gui/base/channel_norm_generator.py +335 -0
  12. celldetective/gui/base/components.py +249 -0
  13. celldetective/gui/base/feature_choice.py +92 -0
  14. celldetective/gui/base/figure_canvas.py +52 -0
  15. celldetective/gui/base/list_widget.py +133 -0
  16. celldetective/gui/{styles.py → base/styles.py} +92 -36
  17. celldetective/gui/base/utils.py +33 -0
  18. celldetective/gui/base_annotator.py +900 -767
  19. celldetective/gui/classifier_widget.py +6 -22
  20. celldetective/gui/configure_new_exp.py +777 -671
  21. celldetective/gui/control_panel.py +635 -524
  22. celldetective/gui/dynamic_progress.py +449 -0
  23. celldetective/gui/event_annotator.py +2023 -1662
  24. celldetective/gui/generic_signal_plot.py +1292 -944
  25. celldetective/gui/gui_utils.py +899 -1289
  26. celldetective/gui/interactions_block.py +658 -0
  27. celldetective/gui/interactive_timeseries_viewer.py +447 -0
  28. celldetective/gui/json_readers.py +48 -15
  29. celldetective/gui/layouts/__init__.py +5 -0
  30. celldetective/gui/layouts/background_model_free_layout.py +537 -0
  31. celldetective/gui/layouts/channel_offset_layout.py +134 -0
  32. celldetective/gui/layouts/local_correction_layout.py +91 -0
  33. celldetective/gui/layouts/model_fit_layout.py +372 -0
  34. celldetective/gui/layouts/operation_layout.py +68 -0
  35. celldetective/gui/layouts/protocol_designer_layout.py +96 -0
  36. celldetective/gui/pair_event_annotator.py +3130 -2435
  37. celldetective/gui/plot_measurements.py +586 -267
  38. celldetective/gui/plot_signals_ui.py +724 -506
  39. celldetective/gui/preprocessing_block.py +395 -0
  40. celldetective/gui/process_block.py +1678 -1831
  41. celldetective/gui/seg_model_loader.py +580 -473
  42. celldetective/gui/settings/__init__.py +0 -7
  43. celldetective/gui/settings/_cellpose_model_params.py +181 -0
  44. celldetective/gui/settings/_event_detection_model_params.py +95 -0
  45. celldetective/gui/settings/_segmentation_model_params.py +159 -0
  46. celldetective/gui/settings/_settings_base.py +77 -65
  47. celldetective/gui/settings/_settings_event_model_training.py +752 -526
  48. celldetective/gui/settings/_settings_measurements.py +1133 -964
  49. celldetective/gui/settings/_settings_neighborhood.py +574 -488
  50. celldetective/gui/settings/_settings_segmentation_model_training.py +779 -564
  51. celldetective/gui/settings/_settings_signal_annotator.py +329 -305
  52. celldetective/gui/settings/_settings_tracking.py +1304 -1094
  53. celldetective/gui/settings/_stardist_model_params.py +98 -0
  54. celldetective/gui/survival_ui.py +422 -312
  55. celldetective/gui/tableUI.py +1665 -1701
  56. celldetective/gui/table_ops/_maths.py +295 -0
  57. celldetective/gui/table_ops/_merge_groups.py +140 -0
  58. celldetective/gui/table_ops/_merge_one_hot.py +95 -0
  59. celldetective/gui/table_ops/_query_table.py +43 -0
  60. celldetective/gui/table_ops/_rename_col.py +44 -0
  61. celldetective/gui/thresholds_gui.py +382 -179
  62. celldetective/gui/viewers/__init__.py +0 -0
  63. celldetective/gui/viewers/base_viewer.py +700 -0
  64. celldetective/gui/viewers/channel_offset_viewer.py +331 -0
  65. celldetective/gui/viewers/contour_viewer.py +394 -0
  66. celldetective/gui/viewers/size_viewer.py +153 -0
  67. celldetective/gui/viewers/spot_detection_viewer.py +341 -0
  68. celldetective/gui/viewers/threshold_viewer.py +309 -0
  69. celldetective/gui/workers.py +403 -126
  70. celldetective/log_manager.py +92 -0
  71. celldetective/measure.py +1895 -1478
  72. celldetective/napari/__init__.py +0 -0
  73. celldetective/napari/utils.py +1025 -0
  74. celldetective/neighborhood.py +1914 -1448
  75. celldetective/preprocessing.py +1620 -1220
  76. celldetective/processes/__init__.py +0 -0
  77. celldetective/processes/background_correction.py +271 -0
  78. celldetective/processes/compute_neighborhood.py +894 -0
  79. celldetective/processes/detect_events.py +246 -0
  80. celldetective/processes/downloader.py +137 -0
  81. celldetective/processes/measure_cells.py +565 -0
  82. celldetective/processes/segment_cells.py +760 -0
  83. celldetective/processes/track_cells.py +435 -0
  84. celldetective/processes/train_segmentation_model.py +694 -0
  85. celldetective/processes/train_signal_model.py +265 -0
  86. celldetective/processes/unified_process.py +292 -0
  87. celldetective/regionprops/_regionprops.py +358 -317
  88. celldetective/relative_measurements.py +987 -710
  89. celldetective/scripts/measure_cells.py +313 -212
  90. celldetective/scripts/measure_relative.py +90 -46
  91. celldetective/scripts/segment_cells.py +165 -104
  92. celldetective/scripts/segment_cells_thresholds.py +96 -68
  93. celldetective/scripts/track_cells.py +198 -149
  94. celldetective/scripts/train_segmentation_model.py +324 -201
  95. celldetective/scripts/train_signal_model.py +87 -45
  96. celldetective/segmentation.py +844 -749
  97. celldetective/signals.py +3514 -2861
  98. celldetective/tracking.py +30 -15
  99. celldetective/utils/__init__.py +0 -0
  100. celldetective/utils/cellpose_utils/__init__.py +133 -0
  101. celldetective/utils/color_mappings.py +42 -0
  102. celldetective/utils/data_cleaning.py +630 -0
  103. celldetective/utils/data_loaders.py +450 -0
  104. celldetective/utils/dataset_helpers.py +207 -0
  105. celldetective/utils/downloaders.py +235 -0
  106. celldetective/utils/event_detection/__init__.py +8 -0
  107. celldetective/utils/experiment.py +1782 -0
  108. celldetective/utils/image_augmenters.py +308 -0
  109. celldetective/utils/image_cleaning.py +74 -0
  110. celldetective/utils/image_loaders.py +926 -0
  111. celldetective/utils/image_transforms.py +335 -0
  112. celldetective/utils/io.py +62 -0
  113. celldetective/utils/mask_cleaning.py +348 -0
  114. celldetective/utils/mask_transforms.py +5 -0
  115. celldetective/utils/masks.py +184 -0
  116. celldetective/utils/maths.py +351 -0
  117. celldetective/utils/model_getters.py +325 -0
  118. celldetective/utils/model_loaders.py +296 -0
  119. celldetective/utils/normalization.py +380 -0
  120. celldetective/utils/parsing.py +465 -0
  121. celldetective/utils/plots/__init__.py +0 -0
  122. celldetective/utils/plots/regression.py +53 -0
  123. celldetective/utils/resources.py +34 -0
  124. celldetective/utils/stardist_utils/__init__.py +104 -0
  125. celldetective/utils/stats.py +90 -0
  126. celldetective/utils/types.py +21 -0
  127. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/METADATA +1 -1
  128. celldetective-1.5.0b1.dist-info/RECORD +187 -0
  129. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/WHEEL +1 -1
  130. tests/gui/test_new_project.py +129 -117
  131. tests/gui/test_project.py +127 -79
  132. tests/test_filters.py +39 -15
  133. tests/test_notebooks.py +8 -0
  134. tests/test_tracking.py +232 -13
  135. tests/test_utils.py +123 -77
  136. celldetective/gui/base_components.py +0 -23
  137. celldetective/gui/layouts.py +0 -1602
  138. celldetective/gui/processes/compute_neighborhood.py +0 -594
  139. celldetective/gui/processes/downloader.py +0 -111
  140. celldetective/gui/processes/measure_cells.py +0 -360
  141. celldetective/gui/processes/segment_cells.py +0 -499
  142. celldetective/gui/processes/track_cells.py +0 -303
  143. celldetective/gui/processes/train_segmentation_model.py +0 -270
  144. celldetective/gui/processes/train_signal_model.py +0 -108
  145. celldetective/gui/table_ops/merge_groups.py +0 -118
  146. celldetective/gui/viewers.py +0 -1354
  147. celldetective/io.py +0 -3663
  148. celldetective/utils.py +0 -3108
  149. celldetective-1.4.2.dist-info/RECORD +0 -123
  150. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/entry_points.txt +0 -0
  151. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/licenses/LICENSE +0 -0
  152. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/top_level.txt +0 -0
@@ -1,111 +0,0 @@
1
- import os
2
- import ssl
3
- from tqdm import tqdm
4
- from multiprocessing import Process
5
- from glob import glob
6
- import shutil
7
- from urllib.request import urlopen
8
- import zipfile
9
- import tempfile
10
- import time
11
- from pathlib import Path
12
- import json
13
-
14
- class DownloadProcess(Process):
15
-
16
- def __init__(self, queue=None, process_args=None, *args, **kwargs):
17
-
18
- super().__init__(*args, **kwargs)
19
-
20
- if process_args is not None:
21
- for key, value in process_args.items():
22
- setattr(self, key, value)
23
-
24
- self.queue = queue
25
- self.progress = True
26
-
27
- file_path = Path(os.path.dirname(os.path.realpath(__file__)))
28
- zenodo_json = os.sep.join([str(file_path.parents[2]),"celldetective", "links", "zenodo.json"])
29
- print(f"{zenodo_json=}")
30
-
31
- with open(zenodo_json,"r") as f:
32
- zenodo_json = json.load(f)
33
- all_files = list(zenodo_json['files']['entries'].keys())
34
- all_files_short = [f.replace(".zip","") for f in all_files]
35
- zenodo_url = zenodo_json['links']['files'].replace('api/','')
36
- full_links = ["/".join([zenodo_url, f]) for f in all_files]
37
- index = all_files_short.index(self.file)
38
-
39
- self.zip_url = full_links[index]
40
- self.path_to_zip_file = os.sep.join([self.output_dir, 'temp.zip'])
41
-
42
- self.sum_done = 0
43
- self.t0 = time.time()
44
-
45
- def download_url_to_file(self, url, dst):
46
- try:
47
- file_size = None
48
- ssl._create_default_https_context = ssl._create_unverified_context
49
- u = urlopen(url)
50
- meta = u.info()
51
- if hasattr(meta, 'getheaders'):
52
- content_length = meta.getheaders("Content-Length")
53
- else:
54
- content_length = meta.get_all("Content-Length")
55
- if content_length is not None and len(content_length) > 0:
56
- file_size = int(content_length[0])
57
- # We deliberately save it in a temp file and move it after
58
- dst = os.path.expanduser(dst)
59
- dst_dir = os.path.dirname(dst)
60
- f = tempfile.NamedTemporaryFile(delete=False, dir=dst_dir)
61
-
62
- try:
63
- with tqdm(total=file_size, disable=not self.progress,
64
- unit='B', unit_scale=True, unit_divisor=1024) as pbar:
65
- while True:
66
- buffer = u.read(8192) #8192
67
- if len(buffer) == 0:
68
- break
69
- f.write(buffer)
70
- pbar.update(len(buffer))
71
- self.sum_done+=len(buffer) / file_size * 100
72
- mean_exec_per_step = (time.time() - self.t0) / (self.sum_done*file_size / 100 + 1)
73
- pred_time = (file_size - (self.sum_done*file_size / 100 + 1)) * mean_exec_per_step
74
- self.queue.put([self.sum_done, pred_time])
75
- f.close()
76
- shutil.move(f.name, dst)
77
- finally:
78
- f.close()
79
- if os.path.exists(f.name):
80
- os.remove(f.name)
81
- except Exception as e:
82
- print("No internet connection: ", e)
83
- return None
84
-
85
- def run(self):
86
-
87
- self.download_url_to_file(fr"{self.zip_url}",self.path_to_zip_file)
88
- with zipfile.ZipFile(self.path_to_zip_file, 'r') as zip_ref:
89
- zip_ref.extractall(self.output_dir)
90
-
91
- file_to_rename = glob(os.sep.join([self.output_dir,self.file,"*[!.json][!.png][!.h5][!.csv][!.npy][!.tif][!.ini]"]))
92
- if len(file_to_rename)>0 and not file_to_rename[0].endswith(os.sep) and not self.file.startswith('demo'):
93
- os.rename(file_to_rename[0], os.sep.join([self.output_dir,self.file,self.file]))
94
-
95
- os.remove(self.path_to_zip_file)
96
- self.queue.put([100,0])
97
- time.sleep(0.5)
98
-
99
- # Send end signal
100
- self.queue.put("finished")
101
- self.queue.close()
102
-
103
- def end_process(self):
104
-
105
- self.terminate()
106
- self.queue.put("finished")
107
-
108
- def abort_process(self):
109
-
110
- self.terminate()
111
- self.queue.put("error")
@@ -1,360 +0,0 @@
1
- from multiprocessing import Process
2
- import time
3
- import datetime
4
- import os
5
- import json
6
- from pathlib import Path, PurePath
7
-
8
- from celldetective.io import auto_load_number_of_frames, load_frames, locate_labels
9
- from celldetective.utils import extract_experiment_channels, config_section_to_dict, _get_img_num_per_channel
10
- from celldetective.utils import remove_trajectory_measurements, _extract_coordinates_from_features, _remove_invalid_cols
11
- from celldetective.measure import drop_tonal_features, measure_features, measure_isotropic_intensity, measure_radial_distance_to_center, center_of_mass_to_abs_coordinates
12
-
13
- from glob import glob
14
- from tqdm import tqdm
15
- import numpy as np
16
- import concurrent.futures
17
- import pandas as pd
18
- from natsort import natsorted
19
- from art import tprint
20
- from typing import Optional, Union
21
-
22
-
23
- class MeasurementProcess(Process):
24
-
25
- pos: Optional[Union[str,Path]] = None
26
- mode: Optional[str] = None
27
- n_threads: int = 1
28
-
29
- def __init__(self, queue=None, process_args=None):
30
-
31
- super().__init__()
32
-
33
- self.queue = queue
34
-
35
- if process_args is not None:
36
- for key, value in process_args.items():
37
- setattr(self, key, value)
38
-
39
- self.column_labels = {'track': "TRACK_ID", 'time': 'FRAME', 'x': 'POSITION_X', 'y': 'POSITION_Y'}
40
-
41
- tprint("Measure")
42
-
43
- # Experiment
44
- self.prepare_folders()
45
-
46
- self.locate_experiment_config()
47
- self.extract_experiment_parameters()
48
- self.read_measurement_instructions()
49
- self.detect_movie_and_labels()
50
- self.detect_tracks()
51
- self.detect_channels()
52
-
53
- self.check_possible_measurements()
54
-
55
- self.write_log()
56
-
57
- self.sum_done = 0
58
- self.t0 = time.time()
59
-
60
- def check_possible_measurements(self):
61
-
62
- if (self.file is None) or (self.intensity_measurement_radii is None):
63
- self.do_iso_intensities = False
64
- print('Either no image, no positions or no radii were provided... Isotropic intensities will not be computed...')
65
- else:
66
- self.do_iso_intensities = True
67
-
68
- if self.label_path is None:
69
- self.do_features = False
70
- print('No labels were provided... Features will not be computed...')
71
- else:
72
- self.do_features = True
73
-
74
- if self.trajectories is None:
75
- print('Use features as a substitute for the trajectory table.')
76
- if 'label' not in self.features:
77
- self.features.append('label')
78
-
79
-
80
- def read_measurement_instructions(self):
81
-
82
- print('Looking for measurement instruction file...')
83
- instr_path = PurePath(self.exp_dir,Path(f"{self.instruction_file}"))
84
- if os.path.exists(instr_path):
85
- with open(instr_path, 'r') as f:
86
- self.instructions = json.load(f)
87
- print(f"Measurement instruction file successfully loaded...")
88
- print(f"Instructions: {self.instructions}...")
89
-
90
- if 'background_correction' in self.instructions:
91
- self.background_correction = self.instructions['background_correction']
92
- else:
93
- self.background_correction = None
94
-
95
- if 'features' in self.instructions:
96
- self.features = self.instructions['features']
97
- else:
98
- self.features = None
99
-
100
- if 'border_distances' in self.instructions:
101
- self.border_distances = self.instructions['border_distances']
102
- else:
103
- self.border_distances = None
104
-
105
- if 'spot_detection' in self.instructions:
106
- self.spot_detection = self.instructions['spot_detection']
107
- else:
108
- self.spot_detection = None
109
-
110
- if 'haralick_options' in self.instructions:
111
- self.haralick_options = self.instructions['haralick_options']
112
- else:
113
- self.haralick_options = None
114
-
115
- if 'intensity_measurement_radii' in self.instructions:
116
- self.intensity_measurement_radii = self.instructions['intensity_measurement_radii']
117
- else:
118
- self.intensity_measurement_radii = None
119
-
120
- if 'isotropic_operations' in self.instructions:
121
- self.isotropic_operations = self.instructions['isotropic_operations']
122
- else:
123
- self.isotropic_operations = None
124
-
125
- if 'clear_previous' in self.instructions:
126
- self.clear_previous = self.instructions['clear_previous']
127
- else:
128
- self.clear_previous = True
129
-
130
- else:
131
- print('No measurement instructions found. Use default measurements.')
132
- self.features = ['area', 'intensity_mean']
133
- self.border_distances = None
134
- self.haralick_options = None
135
- self.clear_previous = False
136
- self.background_correction = None
137
- self.spot_detection = None
138
- self.intensity_measurement_radii = 10
139
- self.isotropic_operations = ['mean']
140
-
141
- if self.features is None:
142
- self.features = []
143
-
144
-
145
- def detect_channels(self):
146
- self.img_num_channels = _get_img_num_per_channel(self.channel_indices, self.len_movie, self.nbr_channels)
147
-
148
- def write_log(self):
149
-
150
- features_log=f'features: {self.features}'
151
- border_distances_log=f'border_distances: {self.border_distances}'
152
- haralick_options_log=f'haralick_options: {self.haralick_options}'
153
- background_correction_log=f'background_correction: {self.background_correction}'
154
- spot_detection_log=f'spot_detection: {self.spot_detection}'
155
- intensity_measurement_radii_log=f'intensity_measurement_radii: {self.intensity_measurement_radii}'
156
- isotropic_options_log=f'isotropic_operations: {self.isotropic_operations} \n'
157
- log='\n'.join([features_log,border_distances_log,haralick_options_log,background_correction_log,spot_detection_log,intensity_measurement_radii_log,isotropic_options_log])
158
- with open(self.pos + f'log_{self.mode}.txt', 'a') as f:
159
- f.write(f'{datetime.datetime.now()} MEASURE \n')
160
- f.write(log+'\n')
161
-
162
- def prepare_folders(self):
163
-
164
- if self.mode.lower()=="target" or self.mode.lower()=="targets":
165
- self.label_folder = "labels_targets"
166
- self.table_name = "trajectories_targets.csv"
167
- self.instruction_file = os.sep.join(["configs","measurement_instructions_targets.json"])
168
-
169
- elif self.mode.lower()=="effector" or self.mode.lower()=="effectors":
170
- self.label_folder = "labels_effectors"
171
- self.table_name = "trajectories_effectors.csv"
172
- self.instruction_file = os.sep.join(["configs","measurement_instructions_effectors.json"])
173
-
174
- else:
175
- self.label_folder = f"labels_{self.mode}"
176
- self.table_name = f"trajectories_{self.mode}.csv"
177
- self.instruction_file = os.sep.join(["configs",f"measurement_instructions_{self.mode}.json"])
178
-
179
- def extract_experiment_parameters(self):
180
-
181
- self.movie_prefix = config_section_to_dict(self.config, "MovieSettings")["movie_prefix"]
182
- self.spatial_calibration = float(config_section_to_dict(self.config, "MovieSettings")["pxtoum"])
183
- self.time_calibration = float(config_section_to_dict(self.config, "MovieSettings")["frametomin"])
184
- self.len_movie = float(config_section_to_dict(self.config, "MovieSettings")["len_movie"])
185
- self.shape_x = int(config_section_to_dict(self.config, "MovieSettings")["shape_x"])
186
- self.shape_y = int(config_section_to_dict(self.config, "MovieSettings")["shape_y"])
187
-
188
- self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
189
- self.nbr_channels = len(self.channel_names)
190
-
191
- def locate_experiment_config(self):
192
-
193
- parent1 = Path(self.pos).parent
194
- self.exp_dir = parent1.parent
195
- self.config = PurePath(self.exp_dir,Path("config.ini"))
196
-
197
- if not os.path.exists(self.config):
198
- print('The configuration file for the experiment was not found...')
199
- self.abort_process()
200
-
201
- def detect_tracks(self):
202
-
203
- # Load trajectories, add centroid if not in trajectory
204
- self.trajectories = self.pos+os.sep.join(['output','tables', self.table_name])
205
- if os.path.exists(self.trajectories):
206
- print('Previous table detected...')
207
- self.trajectories = pd.read_csv(self.trajectories)
208
- if 'TRACK_ID' not in list(self.trajectories.columns):
209
- print('Static measurements detected...')
210
- self.do_iso_intensities = False
211
- self.intensity_measurement_radii = None
212
- if self.clear_previous:
213
- print('Clear previous measurements...')
214
- self.trajectories = None #remove_trajectory_measurements(trajectories, column_labels)
215
- self.do_features = True
216
- self.features += ['centroid']
217
- self.column_labels.update({'track': 'ID'})
218
- else:
219
- print('Time series detected...')
220
- if self.clear_previous:
221
- print('TRACK_ID found... Clear previous measurements...')
222
- self.trajectories = remove_trajectory_measurements(self.trajectories, self.column_labels)
223
- else:
224
- self.trajectories = None
225
- self.do_features = True
226
- self.features += ['centroid']
227
- self.do_iso_intensities = False
228
-
229
- def detect_movie_and_labels(self):
230
-
231
- self.label_path = natsorted(glob(os.sep.join([self.pos, self.label_folder, '*.tif'])))
232
- if len(self.label_path)>0:
233
- print(f"Found {len(self.label_path)} segmented frames...")
234
- else:
235
- self.features = None
236
- self.haralick_options = None
237
- self.border_distances = None
238
- self.label_path = None
239
-
240
- try:
241
- self.file = glob(self.pos+os.sep.join(["movie", f"{self.movie_prefix}*.tif"]))[0]
242
- except IndexError:
243
- self.file = None
244
- self.haralick_option = None
245
- self.features = drop_tonal_features(self.features)
246
-
247
- len_movie_auto = auto_load_number_of_frames(self.file)
248
- if len_movie_auto is not None:
249
- self.len_movie = len_movie_auto
250
-
251
- def parallel_job(self, indices):
252
-
253
- measurements = []
254
-
255
- for t in tqdm(indices,desc="frame"):
256
-
257
- if self.file is not None:
258
- img = load_frames(self.img_num_channels[:,t], self.file, scale=None, normalize_input=False)
259
-
260
- if self.label_path is not None:
261
-
262
- lbl = locate_labels(self.pos, population=self.mode, frames=t)
263
- if lbl is None:
264
- continue
265
-
266
- if self.trajectories is not None:
267
-
268
- positions_at_t = self.trajectories.loc[self.trajectories[self.column_labels['time']]==t].copy()
269
-
270
- if self.do_features:
271
- feature_table = measure_features(img, lbl, features=self.features, border_dist=self.border_distances,
272
- channels=self.channel_names, haralick_options=self.haralick_options, verbose=False,
273
- normalisation_list=self.background_correction, spot_detection=self.spot_detection)
274
- if self.trajectories is None:
275
- positions_at_t = _extract_coordinates_from_features(feature_table, timepoint=t)
276
- column_labels = {'track': "ID", 'time': self.column_labels['time'], 'x': self.column_labels['x'],
277
- 'y': self.column_labels['y']}
278
- feature_table.rename(columns={'centroid-1': 'POSITION_X', 'centroid-0': 'POSITION_Y'}, inplace=True)
279
-
280
- if self.do_iso_intensities and not self.trajectories is None:
281
- iso_table = measure_isotropic_intensity(positions_at_t, img, channels=self.channel_names, intensity_measurement_radii=self.intensity_measurement_radii, column_labels=self.column_labels, operations=self.isotropic_operations, verbose=False)
282
-
283
- if self.do_iso_intensities and self.do_features and not self.trajectories is None:
284
- measurements_at_t = iso_table.merge(feature_table, how='outer', on='class_id',suffixes=('_delme', ''))
285
- measurements_at_t = measurements_at_t[[c for c in measurements_at_t.columns if not c.endswith('_delme')]]
286
- elif self.do_iso_intensities * (not self.do_features) * (not self.trajectories is None):
287
- measurements_at_t = iso_table
288
- elif self.do_features:
289
- measurements_at_t = positions_at_t.merge(feature_table, how='outer', on='class_id',suffixes=('_delme', ''))
290
- measurements_at_t = measurements_at_t[[c for c in measurements_at_t.columns if not c.endswith('_delme')]]
291
-
292
- measurements_at_t = center_of_mass_to_abs_coordinates(measurements_at_t)
293
- measurements_at_t = measure_radial_distance_to_center(measurements_at_t, volume=img.shape, column_labels=self.column_labels)
294
-
295
- self.sum_done+=1/self.len_movie*100
296
- mean_exec_per_step = (time.time() - self.t0) / (self.sum_done*self.len_movie / 100 + 1)
297
- pred_time = (self.len_movie - (self.sum_done*self.len_movie / 100 + 1)) * mean_exec_per_step
298
- self.queue.put([self.sum_done, pred_time])
299
-
300
- if measurements_at_t is not None:
301
- measurements_at_t[self.column_labels['time']] = t
302
- else:
303
- measurements_at_t = pd.DataFrame()
304
-
305
- measurements.append(measurements_at_t)
306
-
307
- return measurements
308
-
309
- def run(self):
310
-
311
- self.indices = list(range(self.img_num_channels.shape[1]))
312
- chunks = np.array_split(self.indices, self.n_threads)
313
-
314
- self.timestep_dataframes = []
315
- with concurrent.futures.ThreadPoolExecutor(max_workers=self.n_threads) as executor:
316
- results = executor.map(self.parallel_job, chunks) #list(map(lambda x: executor.submit(self.parallel_job, x), chunks))
317
- try:
318
- for i,return_value in enumerate(results):
319
- print(f'Thread {i} completed...')
320
- self.timestep_dataframes.extend(return_value)
321
- except Exception as e:
322
- print("Exception: ", e)
323
-
324
- print('Measurements successfully performed...')
325
-
326
- if len(self.timestep_dataframes)>0:
327
-
328
- df = pd.concat(self.timestep_dataframes)
329
-
330
- if self.trajectories is not None:
331
- df = df.sort_values(by=[self.column_labels['track'],self.column_labels['time']])
332
- df = df.dropna(subset=[self.column_labels['track']])
333
- else:
334
- df['ID'] = np.arange(len(df))
335
- df = df.sort_values(by=[self.column_labels['time'], 'ID'])
336
-
337
- df = df.reset_index(drop=True)
338
- df = _remove_invalid_cols(df)
339
- df = df.replace([np.inf, -np.inf], np.nan)
340
-
341
- df.to_csv(self.pos+os.sep.join(["output", "tables", self.table_name]), index=False)
342
- print(f'Measurement table successfully exported in {os.sep.join(["output", "tables"])}...')
343
- print('Done.')
344
- else:
345
- print('No measurement could be performed. Check your inputs.')
346
- print('Done.')
347
-
348
- # Send end signal
349
- self.queue.put("finished")
350
- self.queue.close()
351
-
352
- def end_process(self):
353
-
354
- self.terminate()
355
- self.queue.put("finished")
356
-
357
- def abort_process(self):
358
-
359
- self.terminate()
360
- self.queue.put("error")