celldetective 1.3.9.post5__py3-none-any.whl → 1.4.1__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/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/exceptions.py +11 -0
- celldetective/extra_properties.py +132 -0
- celldetective/filters.py +7 -1
- celldetective/gui/InitWindow.py +37 -46
- celldetective/gui/__init__.py +3 -9
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_annotator.py +786 -0
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/classifier_widget.py +86 -94
- celldetective/gui/configure_new_exp.py +163 -46
- celldetective/gui/control_panel.py +76 -146
- celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
- celldetective/gui/generic_signal_plot.py +11 -13
- celldetective/gui/gui_utils.py +54 -23
- celldetective/gui/help/neighborhood.json +2 -2
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +265 -31
- celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +125 -72
- celldetective/gui/process_block.py +283 -188
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/downloader.py +37 -34
- celldetective/gui/processes/measure_cells.py +19 -8
- celldetective/gui/processes/segment_cells.py +47 -11
- celldetective/gui/processes/track_cells.py +18 -13
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/settings/__init__.py +7 -0
- celldetective/gui/settings/_settings_base.py +70 -0
- celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
- celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
- celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
- celldetective/gui/settings/_settings_segmentation.py +49 -0
- celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
- celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
- celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
- celldetective/gui/styles.py +2 -1
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +53 -25
- celldetective/gui/table_ops/__init__.py +0 -0
- celldetective/gui/table_ops/merge_groups.py +118 -0
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +107 -42
- celldetective/gui/workers.py +8 -4
- celldetective/io.py +137 -57
- celldetective/links/zenodo.json +145 -144
- celldetective/measure.py +94 -53
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +56 -35
- celldetective/regionprops/_regionprops.py +16 -5
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_cells.py +5 -5
- celldetective/scripts/measure_relative.py +20 -12
- celldetective/scripts/segment_cells.py +4 -10
- celldetective/scripts/segment_cells_thresholds.py +3 -3
- celldetective/scripts/track_cells.py +10 -8
- celldetective/scripts/train_segmentation_model.py +18 -6
- celldetective/signals.py +29 -14
- celldetective/tracking.py +14 -3
- celldetective/utils.py +91 -62
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
- celldetective-1.4.1.dist-info/RECORD +123 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
- tests/gui/__init__.py +0 -0
- tests/gui/test_new_project.py +228 -0
- tests/gui/test_project.py +99 -0
- tests/test_preprocessing.py +2 -2
- celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
- celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
- celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
- celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
- celldetective/models/signal_detection/NucCond/config_input.json +0 -1
- celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
- celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
- celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
- celldetective/models/signal_detection/NucCond/scores.npy +0 -0
- celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
- celldetective-1.3.9.post5.dist-info/RECORD +0 -129
- tests/test_qt.py +0 -103
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@ import json
|
|
|
6
6
|
from pathlib import Path, PurePath
|
|
7
7
|
|
|
8
8
|
from celldetective.io import auto_load_number_of_frames, load_frames, locate_labels
|
|
9
|
-
from celldetective.utils import extract_experiment_channels,
|
|
9
|
+
from celldetective.utils import extract_experiment_channels, config_section_to_dict, _get_img_num_per_channel
|
|
10
10
|
from celldetective.utils import remove_trajectory_measurements, _extract_coordinates_from_features, _remove_invalid_cols
|
|
11
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
12
|
|
|
@@ -17,9 +17,14 @@ import concurrent.futures
|
|
|
17
17
|
import pandas as pd
|
|
18
18
|
from natsort import natsorted
|
|
19
19
|
from art import tprint
|
|
20
|
+
from typing import Optional, Union
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class MeasurementProcess(Process):
|
|
24
|
+
|
|
25
|
+
pos: Optional[Union[str,Path]] = None
|
|
26
|
+
mode: Optional[str] = None
|
|
27
|
+
n_threads: int = 1
|
|
23
28
|
|
|
24
29
|
def __init__(self, queue=None, process_args=None):
|
|
25
30
|
|
|
@@ -166,14 +171,19 @@ class MeasurementProcess(Process):
|
|
|
166
171
|
self.table_name = "trajectories_effectors.csv"
|
|
167
172
|
self.instruction_file = os.sep.join(["configs","measurement_instructions_effectors.json"])
|
|
168
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
|
+
|
|
169
179
|
def extract_experiment_parameters(self):
|
|
170
180
|
|
|
171
|
-
self.movie_prefix =
|
|
172
|
-
self.spatial_calibration = float(
|
|
173
|
-
self.time_calibration = float(
|
|
174
|
-
self.len_movie = float(
|
|
175
|
-
self.shape_x = int(
|
|
176
|
-
self.shape_y = int(
|
|
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"])
|
|
177
187
|
|
|
178
188
|
self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
|
|
179
189
|
self.nbr_channels = len(self.channel_names)
|
|
@@ -326,7 +336,8 @@ class MeasurementProcess(Process):
|
|
|
326
336
|
|
|
327
337
|
df = df.reset_index(drop=True)
|
|
328
338
|
df = _remove_invalid_cols(df)
|
|
329
|
-
|
|
339
|
+
df = df.replace([np.inf, -np.inf], np.nan)
|
|
340
|
+
|
|
330
341
|
df.to_csv(self.pos+os.sep.join(["output", "tables", self.table_name]), index=False)
|
|
331
342
|
print(f'Measurement table successfully exported in {os.sep.join(["output", "tables"])}...')
|
|
332
343
|
print('Done.')
|
|
@@ -5,7 +5,7 @@ import os
|
|
|
5
5
|
import json
|
|
6
6
|
import numpy as np
|
|
7
7
|
from celldetective.io import extract_position_name, locate_segmentation_model, auto_load_number_of_frames, load_frames, _check_label_dims, _load_frames_to_segment
|
|
8
|
-
from celldetective.utils import _rescale_labels, _segment_image_with_stardist_model, _segment_image_with_cellpose_model, _prep_stardist_model, _prep_cellpose_model, _get_normalize_kwargs_from_config, extract_experiment_channels, _estimate_scale_factor, _extract_channel_indices_from_config,
|
|
8
|
+
from celldetective.utils import _rescale_labels, _segment_image_with_stardist_model, _segment_image_with_cellpose_model, _prep_stardist_model, _prep_cellpose_model, _get_normalize_kwargs_from_config, extract_experiment_channels, _estimate_scale_factor, _extract_channel_indices_from_config, config_section_to_dict, _extract_nbr_channels_from_config, _get_img_num_per_channel
|
|
9
9
|
|
|
10
10
|
from pathlib import Path, PurePath
|
|
11
11
|
from glob import glob
|
|
@@ -39,19 +39,30 @@ class BaseSegmentProcess(Process):
|
|
|
39
39
|
print(f"Position: {extract_position_name(self.pos)}...")
|
|
40
40
|
print("Configuration file: ",self.config)
|
|
41
41
|
print(f"Population: {self.mode}...")
|
|
42
|
-
|
|
42
|
+
self.instruction_file = os.sep.join(["configs", f"segmentation_instructions_{self.mode}.json"])
|
|
43
|
+
|
|
44
|
+
self.read_instructions()
|
|
43
45
|
self.extract_experiment_parameters()
|
|
44
46
|
self.detect_movie_length()
|
|
45
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
|
|
60
|
+
|
|
46
61
|
|
|
47
62
|
def write_folders(self):
|
|
48
63
|
|
|
49
64
|
self.mode = self.mode.lower()
|
|
50
|
-
|
|
51
|
-
if self.mode=="target" or self.mode=="targets":
|
|
52
|
-
self.label_folder = "labels_targets"
|
|
53
|
-
elif self.mode=="effector" or self.mode=="effectors":
|
|
54
|
-
self.label_folder = "labels_effectors"
|
|
65
|
+
self.label_folder = f"labels_{self.mode}"
|
|
55
66
|
|
|
56
67
|
if os.path.exists(self.pos+self.label_folder):
|
|
57
68
|
print('Erasing the previous labels folder...')
|
|
@@ -62,9 +73,9 @@ class BaseSegmentProcess(Process):
|
|
|
62
73
|
|
|
63
74
|
def extract_experiment_parameters(self):
|
|
64
75
|
|
|
65
|
-
self.spatial_calibration = float(
|
|
66
|
-
self.len_movie = float(
|
|
67
|
-
self.movie_prefix =
|
|
76
|
+
self.spatial_calibration = float(config_section_to_dict(self.config, "MovieSettings")["pxtoum"])
|
|
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"]
|
|
68
79
|
self.nbr_channels = _extract_nbr_channels_from_config(self.config)
|
|
69
80
|
self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
|
|
70
81
|
|
|
@@ -123,6 +134,14 @@ class SegmentCellDLProcess(BaseSegmentProcess):
|
|
|
123
134
|
def extract_model_input_parameters(self):
|
|
124
135
|
|
|
125
136
|
self.required_channels = self.input_config["channels"]
|
|
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
|
+
|
|
126
145
|
self.normalize_kwargs = _get_normalize_kwargs_from_config(self.input_config)
|
|
127
146
|
|
|
128
147
|
self.model_type = self.input_config['model_type']
|
|
@@ -152,6 +171,14 @@ class SegmentCellDLProcess(BaseSegmentProcess):
|
|
|
152
171
|
self.scale = _estimate_scale_factor(self.spatial_calibration, self.required_spatial_calibration)
|
|
153
172
|
print(f"Scale: {self.scale}...")
|
|
154
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
|
+
|
|
155
182
|
def locate_model_path(self):
|
|
156
183
|
|
|
157
184
|
self.model_complete_path = locate_segmentation_model(self.model_name)
|
|
@@ -183,7 +210,11 @@ class SegmentCellDLProcess(BaseSegmentProcess):
|
|
|
183
210
|
elif self.model_type=='cellpose':
|
|
184
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)
|
|
185
212
|
|
|
186
|
-
|
|
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"):
|
|
187
218
|
|
|
188
219
|
f = _load_frames_to_segment(self.file, self.img_num_channels[:,t], scale_model=scale_model, normalize_kwargs=self.normalize_kwargs)
|
|
189
220
|
|
|
@@ -219,6 +250,7 @@ class SegmentCellDLProcess(BaseSegmentProcess):
|
|
|
219
250
|
pass
|
|
220
251
|
|
|
221
252
|
gc.collect()
|
|
253
|
+
print("Done.")
|
|
222
254
|
|
|
223
255
|
# Send end signal
|
|
224
256
|
self.queue.put("finished")
|
|
@@ -339,6 +371,9 @@ class SegmentCellThresholdProcess(BaseSegmentProcess):
|
|
|
339
371
|
def run(self):
|
|
340
372
|
|
|
341
373
|
self.indices = list(range(self.img_num_channels.shape[1]))
|
|
374
|
+
if self.flip:
|
|
375
|
+
self.indices = np.array(list(reversed(self.indices)))
|
|
376
|
+
|
|
342
377
|
chunks = np.array_split(self.indices, self.n_threads)
|
|
343
378
|
|
|
344
379
|
with concurrent.futures.ThreadPoolExecutor(max_workers=self.n_threads) as executor:
|
|
@@ -349,6 +384,7 @@ class SegmentCellThresholdProcess(BaseSegmentProcess):
|
|
|
349
384
|
except Exception as e:
|
|
350
385
|
print("Exception: ", e)
|
|
351
386
|
|
|
387
|
+
print('Done.')
|
|
352
388
|
# Send end signal
|
|
353
389
|
self.queue.put("finished")
|
|
354
390
|
self.queue.close()
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
from multiprocessing import Process
|
|
2
2
|
import time
|
|
3
|
-
import datetime
|
|
4
|
-
import os
|
|
5
|
-
import json
|
|
6
3
|
from celldetective.io import auto_load_number_of_frames, _load_frames_to_measure, locate_labels
|
|
7
|
-
from celldetective.utils import
|
|
4
|
+
from celldetective.utils import config_section_to_dict, _get_img_num_per_channel, \
|
|
5
|
+
_mask_intensity_measurements, remove_file_if_exists
|
|
8
6
|
from pathlib import Path, PurePath
|
|
9
7
|
from glob import glob
|
|
10
8
|
from tqdm import tqdm
|
|
@@ -147,14 +145,20 @@ class TrackingProcess(Process):
|
|
|
147
145
|
self.napari_name = "napari_effector_trajectories.npy"
|
|
148
146
|
self.table_name = "trajectories_effectors.csv"
|
|
149
147
|
|
|
148
|
+
else:
|
|
149
|
+
self.label_folder = f"labels_{self.mode}"
|
|
150
|
+
self.instruction_file = os.sep.join(["configs",f"tracking_instructions_{self.mode}.json"])
|
|
151
|
+
self.napari_name = f"napari_{self.mode}_trajectories.npy"
|
|
152
|
+
self.table_name = f"trajectories_{self.mode}.csv"
|
|
153
|
+
|
|
150
154
|
def extract_experiment_parameters(self):
|
|
151
155
|
|
|
152
|
-
self.movie_prefix =
|
|
153
|
-
self.spatial_calibration = float(
|
|
154
|
-
self.time_calibration = float(
|
|
155
|
-
self.len_movie = float(
|
|
156
|
-
self.shape_x = int(
|
|
157
|
-
self.shape_y = int(
|
|
156
|
+
self.movie_prefix = config_section_to_dict(self.config, "MovieSettings")["movie_prefix"]
|
|
157
|
+
self.spatial_calibration = float(config_section_to_dict(self.config, "MovieSettings")["pxtoum"])
|
|
158
|
+
self.time_calibration = float(config_section_to_dict(self.config, "MovieSettings")["frametomin"])
|
|
159
|
+
self.len_movie = float(config_section_to_dict(self.config, "MovieSettings")["len_movie"])
|
|
160
|
+
self.shape_x = int(config_section_to_dict(self.config, "MovieSettings")["shape_x"])
|
|
161
|
+
self.shape_y = int(config_section_to_dict(self.config, "MovieSettings")["shape_y"])
|
|
158
162
|
|
|
159
163
|
self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
|
|
160
164
|
self.nbr_channels = len(self.channel_names)
|
|
@@ -240,7 +244,9 @@ class TrackingProcess(Process):
|
|
|
240
244
|
|
|
241
245
|
print('Features successfully measured...')
|
|
242
246
|
|
|
243
|
-
df = pd.concat(self.timestep_dataframes)
|
|
247
|
+
df = pd.concat(self.timestep_dataframes)
|
|
248
|
+
df = df.replace([np.inf, -np.inf], np.nan)
|
|
249
|
+
|
|
244
250
|
df.reset_index(inplace=True, drop=True)
|
|
245
251
|
df = _mask_intensity_measurements(df, self.mask_channels)
|
|
246
252
|
|
|
@@ -274,8 +280,7 @@ class TrackingProcess(Process):
|
|
|
274
280
|
trajectories.to_csv(self.pos+os.sep.join(['output', 'tables', self.table_name]), index=False)
|
|
275
281
|
print(f"Trajectory table successfully exported in {os.sep.join(['output', 'tables'])}...")
|
|
276
282
|
|
|
277
|
-
|
|
278
|
-
os.remove(self.pos+os.sep.join(['output', 'tables', self.table_name.replace('.csv','.pkl')]))
|
|
283
|
+
remove_file_if_exists(self.pos+os.sep.join(['output', 'tables', self.table_name.replace('.csv','.pkl')]))
|
|
279
284
|
|
|
280
285
|
del trajectories; del napari_data;
|
|
281
286
|
gc.collect()
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import
|
|
1
|
+
from PyQt5.QtWidgets import QGridLayout, QComboBox, QVBoxLayout, QLabel, QLineEdit, QHBoxLayout, QRadioButton, QFileDialog, QPushButton, QMessageBox
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
|
-
from celldetective.gui.gui_utils import center_window
|
|
3
|
+
from celldetective.gui.gui_utils import center_window, generic_message
|
|
4
4
|
from celldetective.gui.layouts import ChannelNormGenerator
|
|
5
|
-
from celldetective.gui import ThresholdConfigWizard
|
|
5
|
+
from celldetective.gui import ThresholdConfigWizard, CelldetectiveWidget
|
|
6
6
|
from PyQt5.QtGui import QDoubleValidator
|
|
7
7
|
from superqt.fonticon import icon
|
|
8
8
|
from fonticon_mdi6 import MDI6
|
|
@@ -16,7 +16,7 @@ import gc
|
|
|
16
16
|
from cellpose.models import CellposeModel
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class SegmentationModelLoader(
|
|
19
|
+
class SegmentationModelLoader(CelldetectiveWidget):
|
|
20
20
|
|
|
21
21
|
"""
|
|
22
22
|
Upload a segmentation model or define a Threshold pipeline.
|
|
@@ -27,15 +27,10 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
27
27
|
super().__init__()
|
|
28
28
|
self.parent_window = parent_window
|
|
29
29
|
self.mode = self.parent_window.mode
|
|
30
|
-
|
|
31
|
-
self.target_folder = "segmentation_targets"
|
|
32
|
-
elif self.mode=="effectors":
|
|
33
|
-
self.target_folder = "segmentation_effectors"
|
|
30
|
+
self.target_folder = f"segmentation_{self.mode}"
|
|
34
31
|
self.setWindowTitle('Upload model')
|
|
35
32
|
self.generate_content()
|
|
36
|
-
self.setWindowIcon(self.celldetective_icon)
|
|
37
33
|
center_window(self)
|
|
38
|
-
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
39
34
|
|
|
40
35
|
def generate_content(self):
|
|
41
36
|
|
|
@@ -230,14 +225,9 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
230
225
|
self.destination = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]+f"/models/{self.target_folder}/"+self.modelname
|
|
231
226
|
self.folder_dest = self.destination
|
|
232
227
|
else:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
msgBox.setWindowTitle("Warning")
|
|
237
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
238
|
-
returnValue = msgBox.exec()
|
|
239
|
-
if returnValue == QMessageBox.Ok:
|
|
240
|
-
return None
|
|
228
|
+
generic_message(
|
|
229
|
+
"StarDist model not recognized... Please ensure that it contains a thresholds.json file or that it is a valid StarDist model...")
|
|
230
|
+
return None
|
|
241
231
|
|
|
242
232
|
if self.seg_mode=="cellpose":
|
|
243
233
|
self.file_label.setText(self.filename.split("/")[-1])
|
|
@@ -264,15 +254,8 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
264
254
|
self.merge_lbl.hide()
|
|
265
255
|
self.file_label.setText(self.filename[0].split("/")[-1])
|
|
266
256
|
else:
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
msgBox.setText("You selected more than one pipeline. Please set a merging procedure for the resulting masks...")
|
|
270
|
-
msgBox.setWindowTitle("Warning")
|
|
271
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
272
|
-
returnValue = msgBox.exec()
|
|
273
|
-
if returnValue == QMessageBox.Ok:
|
|
274
|
-
pass
|
|
275
|
-
|
|
257
|
+
generic_message(
|
|
258
|
+
"You selected more than one pipeline. Please set a merging procedure for the resulting masks...")
|
|
276
259
|
self.merge_cb.show()
|
|
277
260
|
self.merge_lbl.show()
|
|
278
261
|
self.file_label.setText(f"{n_files} configs loaded...")
|
|
@@ -327,14 +310,8 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
327
310
|
channels.append(self.channel_layout.channel_cbs[i].currentText())
|
|
328
311
|
|
|
329
312
|
if self.file_label.text()=='No file chosen':
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
msgBox.setText("Please select a model first.")
|
|
333
|
-
msgBox.setWindowTitle("Warning")
|
|
334
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
335
|
-
returnValue = msgBox.exec()
|
|
336
|
-
if returnValue == QMessageBox.Ok:
|
|
337
|
-
return None
|
|
313
|
+
generic_message('Please select a model first...')
|
|
314
|
+
return None
|
|
338
315
|
|
|
339
316
|
if not self.threshold_button.isChecked():
|
|
340
317
|
|
|
@@ -343,14 +320,8 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
343
320
|
try:
|
|
344
321
|
shutil.copytree(self.filename, self.destination)
|
|
345
322
|
except FileExistsError:
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
msgBox.setText("A model with the same name already exists in the models folder. Please rename it.")
|
|
349
|
-
msgBox.setWindowTitle("Warning")
|
|
350
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
351
|
-
returnValue = msgBox.exec()
|
|
352
|
-
if returnValue == QMessageBox.Ok:
|
|
353
|
-
return None
|
|
323
|
+
generic_message("A model with the same name already exists in the models folder. Please rename it.")
|
|
324
|
+
return None
|
|
354
325
|
|
|
355
326
|
elif self.cellpose_button.isChecked():
|
|
356
327
|
|
|
@@ -359,15 +330,8 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
359
330
|
os.mkdir(self.folder_dest)
|
|
360
331
|
shutil.copy(self.filename, self.destination)
|
|
361
332
|
except FileExistsError:
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
msgBox.setText("A model with the same name already exists in the models folder. Please rename it.")
|
|
365
|
-
msgBox.setWindowTitle("Warning")
|
|
366
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
367
|
-
returnValue = msgBox.exec()
|
|
368
|
-
if returnValue == QMessageBox.Ok:
|
|
369
|
-
return None
|
|
370
|
-
|
|
333
|
+
generic_message("A model with the same name already exists in the models folder. Please rename it.")
|
|
334
|
+
return None
|
|
371
335
|
try:
|
|
372
336
|
model = CellposeModel(pretrained_model=self.destination, model_type=None, nchan=len(channels))
|
|
373
337
|
self.scale_model = model.diam_mean
|
|
@@ -392,16 +356,11 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
392
356
|
if not isinstance(self.filename, list):
|
|
393
357
|
if not self.filename is None:
|
|
394
358
|
self.filename = [self.filename]
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
elif self.mode=="effectors":
|
|
401
|
-
self.parent_window.threshold_config_effectors = self.filename
|
|
402
|
-
self.parent_window.seg_model_list.setCurrentText('Threshold')
|
|
403
|
-
print('Path to the traditional segmentation pipeline successfully set in celldetective...')
|
|
404
|
-
self.close()
|
|
359
|
+
|
|
360
|
+
idx = self.parent_window.parent_window.populations.index(self.mode)
|
|
361
|
+
self.parent_window.threshold_configs[idx] = self.filename
|
|
362
|
+
self.parent_window.seg_model_list.setCurrentText('Threshold')
|
|
363
|
+
self.close()
|
|
405
364
|
|
|
406
365
|
def generate_input_config(self):
|
|
407
366
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from ._settings_measurements import SettingsMeasurements
|
|
2
|
+
from ._settings_segmentation import SettingsSegmentation
|
|
3
|
+
from ._settings_tracking import SettingsTracking
|
|
4
|
+
from ._settings_segmentation_model_training import SettingsSegmentationModelTraining
|
|
5
|
+
from ._settings_event_model_training import SettingsEventDetectionModelTraining
|
|
6
|
+
from ._settings_signal_annotator import SettingsSignalAnnotator
|
|
7
|
+
from ._settings_neighborhood import SettingsNeighborhood
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from PyQt5.QtWidgets import QApplication, QScrollArea, QSizePolicy, QVBoxLayout, QPushButton
|
|
3
|
+
from PyQt5.QtCore import Qt
|
|
4
|
+
from celldetective.utils import get_software_location
|
|
5
|
+
from celldetective.gui.gui_utils import center_window
|
|
6
|
+
from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
|
|
7
|
+
from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
8
|
+
|
|
9
|
+
class CelldetectiveSettingsPanel(CelldetectiveMainWindow):
|
|
10
|
+
|
|
11
|
+
def __init__(self, title=""):
|
|
12
|
+
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.setWindowTitle(title)
|
|
15
|
+
|
|
16
|
+
self._get_screen_height()
|
|
17
|
+
#self.setMinimumWidth(500)
|
|
18
|
+
self.setMaximumHeight(int(0.8 * self._screen_height))
|
|
19
|
+
self._scroll_area = QScrollArea(self)
|
|
20
|
+
self._floatValidator = QDoubleValidator()
|
|
21
|
+
self._intValidator = QIntValidator()
|
|
22
|
+
self._software_path = get_software_location()
|
|
23
|
+
|
|
24
|
+
self._create_widgets()
|
|
25
|
+
self._build_layouts()
|
|
26
|
+
self.center_window()
|
|
27
|
+
|
|
28
|
+
def _create_widgets(self):
|
|
29
|
+
self.submit_btn: QPushButton = QPushButton("Save")
|
|
30
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
31
|
+
self.submit_btn.clicked.connect(self._write_instructions)
|
|
32
|
+
|
|
33
|
+
def center_window(self):
|
|
34
|
+
return center_window(self)
|
|
35
|
+
|
|
36
|
+
def _get_screen_height(self):
|
|
37
|
+
app = QApplication.instance()
|
|
38
|
+
screen = app.primaryScreen()
|
|
39
|
+
geometry = screen.availableGeometry()
|
|
40
|
+
self._screen_width, self._screen_height = geometry.getRect()[-2:]
|
|
41
|
+
|
|
42
|
+
def _adjustSize(self):
|
|
43
|
+
self._widget.adjustSize()
|
|
44
|
+
self._scroll_area.adjustSize()
|
|
45
|
+
self.adjustSize()
|
|
46
|
+
|
|
47
|
+
def _build_layouts(self):
|
|
48
|
+
|
|
49
|
+
self._layout: QVBoxLayout = QVBoxLayout()
|
|
50
|
+
self._widget: CelldetectiveWidget = CelldetectiveWidget()
|
|
51
|
+
self._widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
52
|
+
|
|
53
|
+
# Create button widget and layout
|
|
54
|
+
self._widget.setLayout(self._layout)
|
|
55
|
+
self._layout.setContentsMargins(30, 30, 30, 30)
|
|
56
|
+
|
|
57
|
+
self._scroll_area.setAlignment(Qt.AlignCenter)
|
|
58
|
+
self._scroll_area.setWidget(self._widget)
|
|
59
|
+
self._scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
60
|
+
self._scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
61
|
+
self._scroll_area.setWidgetResizable(True)
|
|
62
|
+
self.setCentralWidget(self._scroll_area)
|
|
63
|
+
|
|
64
|
+
QApplication.processEvents()
|
|
65
|
+
|
|
66
|
+
@abstractmethod
|
|
67
|
+
def _load_previous_instructions(self): pass
|
|
68
|
+
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def _write_instructions(self): pass
|