celldetective 1.1.1.post1__py3-none-any.whl → 1.1.1.post4__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/__main__.py +17 -0
- celldetective/gui/classifier_widget.py +10 -3
- celldetective/gui/control_panel.py +11 -4
- celldetective/gui/layouts.py +253 -8
- celldetective/gui/neighborhood_options.py +11 -5
- celldetective/gui/retrain_segmentation_model_options.py +66 -164
- celldetective/gui/retrain_signal_model_options.py +18 -164
- celldetective/gui/signal_annotator.py +85 -25
- celldetective/gui/tableUI.py +174 -65
- celldetective/gui/viewers.py +1 -1
- celldetective/io.py +69 -3
- celldetective/neighborhood.py +96 -26
- celldetective/preprocessing.py +95 -63
- celldetective/scripts/segment_cells.py +1 -0
- celldetective/scripts/train_segmentation_model.py +11 -22
- celldetective/segmentation.py +67 -29
- celldetective/utils.py +54 -14
- {celldetective-1.1.1.post1.dist-info → celldetective-1.1.1.post4.dist-info}/METADATA +1 -1
- {celldetective-1.1.1.post1.dist-info → celldetective-1.1.1.post4.dist-info}/RECORD +24 -24
- {celldetective-1.1.1.post1.dist-info → celldetective-1.1.1.post4.dist-info}/WHEEL +1 -1
- tests/test_segmentation.py +1 -1
- {celldetective-1.1.1.post1.dist-info → celldetective-1.1.1.post4.dist-info}/LICENSE +0 -0
- {celldetective-1.1.1.post1.dist-info → celldetective-1.1.1.post4.dist-info}/entry_points.txt +0 -0
- {celldetective-1.1.1.post1.dist-info → celldetective-1.1.1.post4.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,8 @@ from PyQt5.QtWidgets import QMainWindow, QApplication,QRadioButton, QMessageBox,
|
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
3
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QIcon
|
|
4
4
|
from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, GeometryChoice, OperationChoice
|
|
5
|
+
from celldetective.gui.layouts import ChannelNormGenerator
|
|
6
|
+
|
|
5
7
|
from superqt import QLabeledDoubleRangeSlider, QLabeledDoubleSlider,QLabeledSlider
|
|
6
8
|
from superqt.fonticon import icon
|
|
7
9
|
from fonticon_mdi6 import MDI6
|
|
@@ -91,6 +93,8 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
91
93
|
self.main_layout.addWidget(self.submit_btn)
|
|
92
94
|
self.submit_btn.setEnabled(False)
|
|
93
95
|
|
|
96
|
+
self.spatial_calib_le.textChanged.connect(self.activate_train_btn)
|
|
97
|
+
|
|
94
98
|
#self.populate_left_panel()
|
|
95
99
|
#grid.addLayout(self.left_side, 0, 0, 1, 1)
|
|
96
100
|
self.button_widget.adjustSize()
|
|
@@ -308,83 +312,25 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
308
312
|
# layout.addLayout(recompile_layout)
|
|
309
313
|
|
|
310
314
|
self.max_nbr_channels = 5
|
|
311
|
-
self.
|
|
312
|
-
|
|
313
|
-
self.normalization_mode = [True for i in range(self.max_nbr_channels)]
|
|
314
|
-
|
|
315
|
-
self.normalization_clip_btns = [QPushButton('') for i in range(self.max_nbr_channels)]
|
|
316
|
-
self.clip_option = [False for i in range(self.max_nbr_channels)]
|
|
317
|
-
|
|
318
|
-
for i in range(self.max_nbr_channels):
|
|
319
|
-
|
|
320
|
-
self.normalization_mode_btns[i].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
|
|
321
|
-
self.normalization_mode_btns[i].setIconSize(QSize(20, 20))
|
|
322
|
-
self.normalization_mode_btns[i].setStyleSheet(self.button_select_all)
|
|
323
|
-
self.normalization_mode_btns[i].setToolTip("Switch to absolute normalization values.")
|
|
324
|
-
self.normalization_mode_btns[i].clicked.connect(partial(self.switch_normalization_mode, i))
|
|
325
|
-
|
|
326
|
-
self.normalization_clip_btns[i].setIcon(icon(MDI6.content_cut,color="black"))
|
|
327
|
-
self.normalization_clip_btns[i].setIconSize(QSize(20, 20))
|
|
328
|
-
self.normalization_clip_btns[i].setStyleSheet(self.button_select_all)
|
|
329
|
-
self.normalization_clip_btns[i].clicked.connect(partial(self.switch_clipping_mode, i))
|
|
330
|
-
self.normalization_clip_btns[i].setToolTip('clip')
|
|
331
|
-
|
|
332
|
-
self.normalization_min_value_lbl = [QLabel('Min %: ') for i in range(self.max_nbr_channels)]
|
|
333
|
-
self.normalization_min_value_le = [QLineEdit('0.1') for i in range(self.max_nbr_channels)]
|
|
334
|
-
|
|
335
|
-
self.normalization_max_value_lbl = [QLabel('Max %: ') for i in range(self.max_nbr_channels)]
|
|
336
|
-
self.normalization_max_value_le = [QLineEdit('99.99') for i in range(self.max_nbr_channels)]
|
|
337
|
-
|
|
338
|
-
self.channel_items = ['--', 'brightfield_channel', 'live_nuclei_channel', 'dead_nuclei_channel',
|
|
339
|
-
'effector_fluo_channel', 'adhesion_channel', 'fluo_channel_1', 'fluo_channel_2','None'
|
|
340
|
-
]
|
|
341
|
-
exp_ch = self.parent_window.parent_window.exp_channels
|
|
342
|
-
for c in exp_ch:
|
|
343
|
-
if c not in self.channel_items:
|
|
344
|
-
self.channel_items.append(c)
|
|
345
|
-
|
|
346
|
-
self.channel_option_layouts = []
|
|
347
|
-
for i in range(len(self.channel_cbs)):
|
|
348
|
-
ch_layout = QHBoxLayout()
|
|
349
|
-
ch_layout.addWidget(QLabel(f'channel {i}: '), 30)
|
|
350
|
-
self.channel_cbs[i].addItems(self.channel_items)
|
|
351
|
-
self.channel_cbs[i].currentIndexChanged.connect(self.check_valid_channels)
|
|
352
|
-
ch_layout.addWidget(self.channel_cbs[i], 70)
|
|
353
|
-
layout.addLayout(ch_layout)
|
|
354
|
-
|
|
355
|
-
channel_norm_options_layout = QHBoxLayout()
|
|
356
|
-
channel_norm_options_layout.setContentsMargins(130,0,0,0)
|
|
357
|
-
channel_norm_options_layout.addWidget(self.normalization_min_value_lbl[i])
|
|
358
|
-
channel_norm_options_layout.addWidget(self.normalization_min_value_le[i])
|
|
359
|
-
channel_norm_options_layout.addWidget(self.normalization_max_value_lbl[i])
|
|
360
|
-
channel_norm_options_layout.addWidget(self.normalization_max_value_le[i])
|
|
361
|
-
channel_norm_options_layout.addWidget(self.normalization_clip_btns[i])
|
|
362
|
-
channel_norm_options_layout.addWidget(self.normalization_mode_btns[i])
|
|
363
|
-
layout.addLayout(channel_norm_options_layout)
|
|
364
|
-
|
|
365
|
-
# for i in range(self.max_nbr_channels):
|
|
366
|
-
# self.channel_cbs[i].currentIndexChanged.connect(partial(self.show_norm_options, i))
|
|
315
|
+
self.ch_norm = ChannelNormGenerator(self, mode='channels')
|
|
316
|
+
layout.addLayout(self.ch_norm)
|
|
367
317
|
|
|
368
318
|
spatial_calib_layout = QHBoxLayout()
|
|
369
319
|
spatial_calib_layout.addWidget(QLabel('input spatial\ncalibration'), 30)
|
|
370
|
-
|
|
320
|
+
parent_pxtoum = f"{self.parent_window.parent_window.PxToUm}"
|
|
321
|
+
self.spatial_calib_le = QLineEdit(parent_pxtoum.replace('.',','))
|
|
371
322
|
self.spatial_calib_le.setPlaceholderText('e.g. 0.1 µm per pixel')
|
|
323
|
+
self.spatial_calib_le.setValidator(self.onlyFloat)
|
|
372
324
|
spatial_calib_layout.addWidget(self.spatial_calib_le, 70)
|
|
373
325
|
layout.addLayout(spatial_calib_layout)
|
|
374
326
|
|
|
375
327
|
|
|
376
|
-
# model_length_layout = QHBoxLayout()
|
|
377
|
-
# model_length_layout.addWidget(QLabel('Max signal length: '), 30)
|
|
378
|
-
# self.model_length_slider = QLabeledSlider()
|
|
379
|
-
# self.model_length_slider.setSingleStep(1)
|
|
380
|
-
# self.model_length_slider.setTickInterval(1)
|
|
381
|
-
# self.model_length_slider.setSingleStep(1)
|
|
382
|
-
# self.model_length_slider.setOrientation(1)
|
|
383
|
-
# self.model_length_slider.setRange(0,1024)
|
|
384
|
-
# self.model_length_slider.setValue(128)
|
|
385
|
-
# model_length_layout.addWidget(self.model_length_slider, 70)
|
|
386
|
-
# layout.addLayout(model_length_layout)
|
|
387
328
|
|
|
329
|
+
def activate_train_btn(self):
|
|
330
|
+
if self.spatial_calib_le.text()=='':
|
|
331
|
+
self.submit_btn.setEnabled(False)
|
|
332
|
+
elif not np.all([cb.currentText()=='--' for cb in self.ch_norm.channel_cbs]):
|
|
333
|
+
self.submit_btn.setEnabled(True)
|
|
388
334
|
|
|
389
335
|
def rescale_slider(self):
|
|
390
336
|
if self.stardist_model.isChecked():
|
|
@@ -400,36 +346,44 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
400
346
|
except:
|
|
401
347
|
pass
|
|
402
348
|
|
|
349
|
+
self.pretrained_model = None
|
|
403
350
|
self.pretrained_model = QFileDialog.getExistingDirectory(
|
|
404
351
|
self, "Open Directory",
|
|
405
352
|
os.sep.join([self.soft_path, 'celldetective', 'models', f'segmentation_generic','']),
|
|
406
353
|
QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks,
|
|
407
354
|
)
|
|
355
|
+
|
|
356
|
+
if self.pretrained_model=='':
|
|
357
|
+
return None
|
|
358
|
+
|
|
359
|
+
if self.pretrained_model is None:
|
|
360
|
+
return None
|
|
408
361
|
|
|
409
|
-
|
|
410
|
-
|
|
362
|
+
else:
|
|
411
363
|
self.pretrained_model = self.pretrained_model.replace('\\','/')
|
|
412
364
|
self.pretrained_model = rf"{self.pretrained_model}"
|
|
413
365
|
|
|
414
|
-
subfiles = glob(
|
|
366
|
+
subfiles = glob(os.sep.join([self.pretrained_model,"*"]))
|
|
415
367
|
subfiles = [s.replace('\\','/') for s in subfiles]
|
|
416
368
|
subfiles = [rf"{s}" for s in subfiles]
|
|
417
369
|
|
|
418
|
-
if
|
|
370
|
+
if os.sep.join([self.pretrained_model,"config_input.json"]) in subfiles:
|
|
419
371
|
self.load_pretrained_config()
|
|
420
372
|
self.pretrained_lbl.setText(self.pretrained_model.split("/")[-1])
|
|
421
373
|
self.cancel_pretrained.setVisible(True)
|
|
422
374
|
#self.recompile_option.setEnabled(True)
|
|
423
|
-
self.modelname_le.setText(f"{self.pretrained_model.split(
|
|
375
|
+
self.modelname_le.setText(f"{self.pretrained_model.split(os.sep)[-1]}_{datetime.today().strftime('%Y-%m-%d')}")
|
|
424
376
|
else:
|
|
425
377
|
self.pretrained_model = None
|
|
426
378
|
self.pretrained_lbl.setText('No folder chosen')
|
|
427
379
|
#self.recompile_option.setEnabled(False)
|
|
428
380
|
self.cancel_pretrained.setVisible(False)
|
|
381
|
+
return None
|
|
382
|
+
|
|
429
383
|
print(self.pretrained_model)
|
|
430
384
|
|
|
431
|
-
self.seg_folder = self.pretrained_model.split(
|
|
432
|
-
self.model_name = self.pretrained_model.split(
|
|
385
|
+
self.seg_folder = self.pretrained_model.split(os.sep)[-2]
|
|
386
|
+
self.model_name = self.pretrained_model.split(os.sep)[-1]
|
|
433
387
|
if self.model_name.startswith('CP') and self.seg_folder=='segmentation_generic':
|
|
434
388
|
|
|
435
389
|
self.diamWidget = QWidget()
|
|
@@ -456,7 +410,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
456
410
|
scale = self.parent_window.parent_window.PxToUm * float(self.diameter_le.text()) / 30.0
|
|
457
411
|
if self.model_name=="CP_nuclei":
|
|
458
412
|
scale = self.parent_window.parent_window.PxToUm * float(self.diameter_le.text()) / 17.0
|
|
459
|
-
self.spatial_calib_le.setText(str(scale))
|
|
413
|
+
self.spatial_calib_le.setText(str(scale).replace('.',','))
|
|
460
414
|
self.diamWidget.close()
|
|
461
415
|
|
|
462
416
|
|
|
@@ -485,14 +439,15 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
485
439
|
|
|
486
440
|
self.pretrained_model = None
|
|
487
441
|
self.pretrained_lbl.setText('No folder chosen')
|
|
488
|
-
for i in range(len(self.channel_cbs)):
|
|
489
|
-
self.channel_cbs[i].setEnabled(True)
|
|
490
|
-
self.normalization_mode_btns[i].setEnabled(True)
|
|
491
|
-
self.normalization_max_value_le[i].setEnabled(True)
|
|
492
|
-
self.normalization_min_value_le[i].setEnabled(True)
|
|
493
|
-
self.normalization_clip_btns[i].setEnabled(True)
|
|
494
|
-
self.normalization_min_value_lbl[i].setEnabled(True)
|
|
495
|
-
self.normalization_max_value_lbl[i].setEnabled(True)
|
|
442
|
+
for i in range(len(self.ch_norm.channel_cbs)):
|
|
443
|
+
self.ch_norm.channel_cbs[i].setEnabled(True)
|
|
444
|
+
self.ch_norm.normalization_mode_btns[i].setEnabled(True)
|
|
445
|
+
self.ch_norm.normalization_max_value_le[i].setEnabled(True)
|
|
446
|
+
self.ch_norm.normalization_min_value_le[i].setEnabled(True)
|
|
447
|
+
self.ch_norm.normalization_clip_btns[i].setEnabled(True)
|
|
448
|
+
self.ch_norm.normalization_min_value_lbl[i].setEnabled(True)
|
|
449
|
+
self.ch_norm.normalization_max_value_lbl[i].setEnabled(True)
|
|
450
|
+
self.ch_norm.add_col_btn.setEnabled(True)
|
|
496
451
|
|
|
497
452
|
self.cancel_pretrained.setVisible(False)
|
|
498
453
|
self.modelname_le.setText(f"Untitled_model_{datetime.today().strftime('%Y-%m-%d')}")
|
|
@@ -507,7 +462,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
507
462
|
|
|
508
463
|
def load_pretrained_config(self):
|
|
509
464
|
|
|
510
|
-
f = open(
|
|
465
|
+
f = open(os.sep.join([self.pretrained_model,"config_input.json"]))
|
|
511
466
|
data = json.load(f)
|
|
512
467
|
channels = data["channels"]
|
|
513
468
|
self.seg_folder = self.pretrained_model.split('/')[-2]
|
|
@@ -533,36 +488,37 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
533
488
|
self.stardist_model.setChecked(False)
|
|
534
489
|
self.cellpose_model.setChecked(True)
|
|
535
490
|
|
|
536
|
-
for c,cb in zip(channels, self.channel_cbs):
|
|
491
|
+
for c,cb in zip(channels, self.ch_norm.channel_cbs):
|
|
537
492
|
index = cb.findText(c)
|
|
538
493
|
cb.setCurrentIndex(index)
|
|
539
494
|
|
|
540
495
|
for i in range(len(channels)):
|
|
541
496
|
|
|
542
497
|
to_clip = normalization_clip[i]
|
|
543
|
-
if self.clip_option[i] != to_clip:
|
|
544
|
-
self.normalization_clip_btns[i].click()
|
|
498
|
+
if self.ch_norm.clip_option[i] != to_clip:
|
|
499
|
+
self.ch_norm.normalization_clip_btns[i].click()
|
|
545
500
|
|
|
546
501
|
use_percentile = normalization_percentile[i]
|
|
547
|
-
if self.normalization_mode[i] != use_percentile:
|
|
548
|
-
self.normalization_mode_btns[i].click()
|
|
502
|
+
if self.ch_norm.normalization_mode[i] != use_percentile:
|
|
503
|
+
self.ch_norm.normalization_mode_btns[i].click()
|
|
549
504
|
|
|
550
|
-
self.normalization_min_value_le[i].setText(str(normalization_values[i][0]))
|
|
551
|
-
self.normalization_max_value_le[i].setText(str(normalization_values[i][1]))
|
|
505
|
+
self.ch_norm.normalization_min_value_le[i].setText(str(normalization_values[i][0]))
|
|
506
|
+
self.ch_norm.normalization_max_value_le[i].setText(str(normalization_values[i][1]))
|
|
552
507
|
|
|
553
508
|
|
|
554
|
-
if len(channels)<len(self.channel_cbs):
|
|
555
|
-
for k in range(len(self.channel_cbs)-len(channels)):
|
|
556
|
-
self.channel_cbs[len(channels)+k].setCurrentIndex(0)
|
|
557
|
-
self.channel_cbs[len(channels)+k].setEnabled(False)
|
|
558
|
-
self.normalization_mode_btns[len(channels)+k].setEnabled(False)
|
|
559
|
-
self.normalization_max_value_le[len(channels)+k].setEnabled(False)
|
|
560
|
-
self.normalization_min_value_le[len(channels)+k].setEnabled(False)
|
|
561
|
-
self.normalization_min_value_lbl[len(channels)+k].setEnabled(False)
|
|
562
|
-
self.normalization_max_value_lbl[len(channels)+k].setEnabled(False)
|
|
563
|
-
self.normalization_clip_btns[len(channels)+k].setEnabled(False)
|
|
509
|
+
if len(channels)<len(self.ch_norm.channel_cbs):
|
|
510
|
+
for k in range(len(self.ch_norm.channel_cbs)-len(channels)):
|
|
511
|
+
self.ch_norm.channel_cbs[len(channels)+k].setCurrentIndex(0)
|
|
512
|
+
self.ch_norm.channel_cbs[len(channels)+k].setEnabled(False)
|
|
513
|
+
self.ch_norm.normalization_mode_btns[len(channels)+k].setEnabled(False)
|
|
514
|
+
self.ch_norm.normalization_max_value_le[len(channels)+k].setEnabled(False)
|
|
515
|
+
self.ch_norm.normalization_min_value_le[len(channels)+k].setEnabled(False)
|
|
516
|
+
self.ch_norm.normalization_min_value_lbl[len(channels)+k].setEnabled(False)
|
|
517
|
+
self.ch_norm.normalization_max_value_lbl[len(channels)+k].setEnabled(False)
|
|
518
|
+
self.ch_norm.normalization_clip_btns[len(channels)+k].setEnabled(False)
|
|
519
|
+
self.ch_norm.add_col_btn.setEnabled(False)
|
|
564
520
|
|
|
565
|
-
self.spatial_calib_le.setText(str(spatial_calib))
|
|
521
|
+
self.spatial_calib_le.setText(str(spatial_calib).replace('.',','))
|
|
566
522
|
|
|
567
523
|
def adjustScrollArea(self):
|
|
568
524
|
|
|
@@ -581,23 +537,23 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
581
537
|
pretrained_model = self.pretrained_model
|
|
582
538
|
|
|
583
539
|
channels = []
|
|
584
|
-
for i in range(len(self.channel_cbs)):
|
|
585
|
-
channels.append(self.channel_cbs[i].currentText())
|
|
540
|
+
for i in range(len(self.ch_norm.channel_cbs)):
|
|
541
|
+
channels.append(self.ch_norm.channel_cbs[i].currentText())
|
|
586
542
|
|
|
587
543
|
slots_to_keep = np.where(np.array(channels)!='--')[0]
|
|
588
544
|
while '--' in channels:
|
|
589
545
|
channels.remove('--')
|
|
590
546
|
|
|
591
|
-
norm_values = np.array([[float(a.replace(',','.')),float(b.replace(',','.'))] for a,b in zip([l.text() for l in self.normalization_min_value_le],
|
|
592
|
-
[l.text() for l in self.normalization_max_value_le])])
|
|
547
|
+
norm_values = np.array([[float(a.replace(',','.')),float(b.replace(',','.'))] for a,b in zip([l.text() for l in self.ch_norm.normalization_min_value_le],
|
|
548
|
+
[l.text() for l in self.ch_norm.normalization_max_value_le])])
|
|
593
549
|
norm_values = norm_values[slots_to_keep]
|
|
594
550
|
norm_values = [list(v) for v in norm_values]
|
|
595
551
|
|
|
596
|
-
clip_values = np.array(self.clip_option)
|
|
552
|
+
clip_values = np.array(self.ch_norm.clip_option)
|
|
597
553
|
clip_values = list(clip_values[slots_to_keep])
|
|
598
554
|
clip_values = [bool(c) for c in clip_values]
|
|
599
555
|
|
|
600
|
-
normalization_mode = np.array(self.normalization_mode)
|
|
556
|
+
normalization_mode = np.array(self.ch_norm.normalization_mode)
|
|
601
557
|
normalization_mode = list(normalization_mode[slots_to_keep])
|
|
602
558
|
normalization_mode = [bool(m) for m in normalization_mode]
|
|
603
559
|
|
|
@@ -650,58 +606,4 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
650
606
|
|
|
651
607
|
train_segmentation_model(model_folder+"training_instructions.json", use_gpu=self.parent_window.parent_window.parent_window.use_gpu)
|
|
652
608
|
|
|
653
|
-
# self.parent.refresh_signal_models()
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
def check_valid_channels(self):
|
|
657
|
-
|
|
658
|
-
if np.all([cb.currentText()=='--' for cb in self.channel_cbs]):
|
|
659
|
-
self.submit_btn.setEnabled(False)
|
|
660
|
-
else:
|
|
661
|
-
self.submit_btn.setEnabled(True)
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
def switch_normalization_mode(self, index):
|
|
665
|
-
|
|
666
|
-
"""
|
|
667
|
-
Use absolute or percentile values for the normalization of each individual channel.
|
|
668
|
-
|
|
669
|
-
"""
|
|
670
|
-
|
|
671
|
-
currentNormMode = self.normalization_mode[index]
|
|
672
|
-
self.normalization_mode[index] = not currentNormMode
|
|
673
|
-
|
|
674
|
-
if self.normalization_mode[index]:
|
|
675
|
-
self.normalization_mode_btns[index].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
|
|
676
|
-
self.normalization_mode_btns[index].setIconSize(QSize(20, 20))
|
|
677
|
-
self.normalization_mode_btns[index].setStyleSheet(self.button_select_all)
|
|
678
|
-
self.normalization_mode_btns[index].setToolTip("Switch to absolute normalization values.")
|
|
679
|
-
self.normalization_min_value_lbl[index].setText('Min %: ')
|
|
680
|
-
self.normalization_max_value_lbl[index].setText('Max %: ')
|
|
681
|
-
self.normalization_min_value_le[index].setText('0.1')
|
|
682
|
-
self.normalization_max_value_le[index].setText('99.99')
|
|
683
|
-
|
|
684
|
-
else:
|
|
685
|
-
self.normalization_mode_btns[index].setIcon(icon(MDI6.percent_circle_outline,color="black"))
|
|
686
|
-
self.normalization_mode_btns[index].setIconSize(QSize(20, 20))
|
|
687
|
-
self.normalization_mode_btns[index].setStyleSheet(self.button_select_all)
|
|
688
|
-
self.normalization_mode_btns[index].setToolTip("Switch to percentile normalization values.")
|
|
689
|
-
self.normalization_min_value_lbl[index].setText('Min: ')
|
|
690
|
-
self.normalization_min_value_le[index].setText('0')
|
|
691
|
-
self.normalization_max_value_lbl[index].setText('Max: ')
|
|
692
|
-
self.normalization_max_value_le[index].setText('1000')
|
|
693
|
-
|
|
694
|
-
def switch_clipping_mode(self, index):
|
|
695
|
-
|
|
696
|
-
currentClipMode = self.clip_option[index]
|
|
697
|
-
self.clip_option[index] = not currentClipMode
|
|
698
|
-
|
|
699
|
-
if self.clip_option[index]:
|
|
700
|
-
self.normalization_clip_btns[index].setIcon(icon(MDI6.content_cut,color="#1565c0"))
|
|
701
|
-
self.normalization_clip_btns[index].setIconSize(QSize(20, 20))
|
|
702
|
-
self.normalization_clip_btns[index].setStyleSheet(self.button_select_all)
|
|
703
|
-
|
|
704
|
-
else:
|
|
705
|
-
self.normalization_clip_btns[index].setIcon(icon(MDI6.content_cut,color="black"))
|
|
706
|
-
self.normalization_clip_btns[index].setIconSize(QSize(20, 20))
|
|
707
|
-
self.normalization_clip_btns[index].setStyleSheet(self.button_select_all)
|
|
609
|
+
# self.parent.refresh_signal_models()
|
|
@@ -2,6 +2,7 @@ from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QScrollArea,
|
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
3
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QIcon
|
|
4
4
|
from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, GeometryChoice, OperationChoice
|
|
5
|
+
from celldetective.gui.layouts import ChannelNormGenerator
|
|
5
6
|
from superqt import QLabeledDoubleRangeSlider, QLabeledDoubleSlider,QLabeledSlider
|
|
6
7
|
from superqt.fonticon import icon
|
|
7
8
|
from fonticon_mdi6 import MDI6
|
|
@@ -306,103 +307,9 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
306
307
|
recompile_layout.addWidget(self.recompile_option, 70)
|
|
307
308
|
layout.addLayout(recompile_layout)
|
|
308
309
|
|
|
309
|
-
#self.channel_cbs = [QComboBox() for i in range(4)]
|
|
310
|
-
|
|
311
310
|
self.max_nbr_channels = 5
|
|
312
|
-
self.
|
|
313
|
-
|
|
314
|
-
self.normalization_mode = [True for i in range(self.max_nbr_channels)]
|
|
315
|
-
|
|
316
|
-
self.normalization_clip_btns = [QPushButton('') for i in range(self.max_nbr_channels)]
|
|
317
|
-
self.clip_option = [False for i in range(self.max_nbr_channels)]
|
|
318
|
-
|
|
319
|
-
for i in range(self.max_nbr_channels):
|
|
320
|
-
|
|
321
|
-
self.normalization_mode_btns[i].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
|
|
322
|
-
self.normalization_mode_btns[i].setIconSize(QSize(20, 20))
|
|
323
|
-
self.normalization_mode_btns[i].setStyleSheet(self.button_select_all)
|
|
324
|
-
self.normalization_mode_btns[i].setToolTip("Switch to absolute normalization values.")
|
|
325
|
-
self.normalization_mode_btns[i].clicked.connect(partial(self.switch_normalization_mode, i))
|
|
326
|
-
|
|
327
|
-
self.normalization_clip_btns[i].setIcon(icon(MDI6.content_cut,color="black"))
|
|
328
|
-
self.normalization_clip_btns[i].setIconSize(QSize(20, 20))
|
|
329
|
-
self.normalization_clip_btns[i].setStyleSheet(self.button_select_all)
|
|
330
|
-
self.normalization_clip_btns[i].clicked.connect(partial(self.switch_clipping_mode, i))
|
|
331
|
-
self.normalization_clip_btns[i].setToolTip('clip')
|
|
332
|
-
|
|
333
|
-
self.normalization_min_value_lbl = [QLabel('Min %: ') for i in range(self.max_nbr_channels)]
|
|
334
|
-
self.normalization_min_value_le = [QLineEdit('0.1') for i in range(self.max_nbr_channels)]
|
|
335
|
-
|
|
336
|
-
self.normalization_max_value_lbl = [QLabel('Max %: ') for i in range(self.max_nbr_channels)]
|
|
337
|
-
self.normalization_max_value_le = [QLineEdit('99.99') for i in range(self.max_nbr_channels)]
|
|
338
|
-
|
|
339
|
-
tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{self.mode}.csv']))
|
|
340
|
-
print(tables)
|
|
341
|
-
all_measurements = []
|
|
342
|
-
for tab in tables:
|
|
343
|
-
cols = pd.read_csv(tab, nrows=1).columns.tolist()
|
|
344
|
-
all_measurements.extend(cols)
|
|
345
|
-
all_measurements = np.unique(all_measurements)
|
|
346
|
-
generic_measurements = ['brightfield_channel', 'live_nuclei_channel', 'dead_nuclei_channel',
|
|
347
|
-
'effector_fluo_channel', 'adhesion_channel', 'fluo_channel_1', 'fluo_channel_2',
|
|
348
|
-
"area", "area_bbox","area_convex","area_filled","major_axis_length",
|
|
349
|
-
"minor_axis_length",
|
|
350
|
-
"eccentricity",
|
|
351
|
-
"equivalent_diameter_area",
|
|
352
|
-
"euler_number",
|
|
353
|
-
"extent",
|
|
354
|
-
"feret_diameter_max",
|
|
355
|
-
"orientation",
|
|
356
|
-
"perimeter",
|
|
357
|
-
"perimeter_crofton",
|
|
358
|
-
"solidity",
|
|
359
|
-
"angular_second_moment",
|
|
360
|
-
"contrast",
|
|
361
|
-
"correlation",
|
|
362
|
-
"sum_of_square_variance",
|
|
363
|
-
"inverse_difference_moment",
|
|
364
|
-
"sum_average",
|
|
365
|
-
"sum_variance",
|
|
366
|
-
"sum_entropy",
|
|
367
|
-
"entropy",
|
|
368
|
-
"difference_variance",
|
|
369
|
-
"difference_entropy",
|
|
370
|
-
"information_measure_of_correlation_1",
|
|
371
|
-
"information_measure_of_correlation_2",
|
|
372
|
-
"maximal_correlation_coefficient",
|
|
373
|
-
"POSITION_X",
|
|
374
|
-
"POSITION_Y",
|
|
375
|
-
]
|
|
376
|
-
|
|
377
|
-
self.channel_items = np.unique(generic_measurements + list(all_measurements))
|
|
378
|
-
self.channel_items = np.insert(self.channel_items, 0, '--')
|
|
379
|
-
|
|
380
|
-
self.channel_option_layouts = []
|
|
381
|
-
for i in range(len(self.channel_cbs)):
|
|
382
|
-
ch_layout = QHBoxLayout()
|
|
383
|
-
ch_layout.addWidget(QLabel(f'channel {i}: '), 30)
|
|
384
|
-
self.channel_cbs[i].addItems(self.channel_items)
|
|
385
|
-
self.channel_cbs[i].currentIndexChanged.connect(self.check_valid_channels)
|
|
386
|
-
ch_layout.addWidget(self.channel_cbs[i], 70)
|
|
387
|
-
layout.addLayout(ch_layout)
|
|
388
|
-
|
|
389
|
-
channel_norm_options_layout = QHBoxLayout()
|
|
390
|
-
channel_norm_options_layout.setContentsMargins(130,0,0,0)
|
|
391
|
-
channel_norm_options_layout.addWidget(self.normalization_min_value_lbl[i])
|
|
392
|
-
channel_norm_options_layout.addWidget(self.normalization_min_value_le[i])
|
|
393
|
-
channel_norm_options_layout.addWidget(self.normalization_max_value_lbl[i])
|
|
394
|
-
channel_norm_options_layout.addWidget(self.normalization_max_value_le[i])
|
|
395
|
-
channel_norm_options_layout.addWidget(self.normalization_clip_btns[i])
|
|
396
|
-
channel_norm_options_layout.addWidget(self.normalization_mode_btns[i])
|
|
397
|
-
layout.addLayout(channel_norm_options_layout)
|
|
398
|
-
|
|
399
|
-
# for i in range(len(self.channel_cbs)):
|
|
400
|
-
# ch_layout = QHBoxLayout()
|
|
401
|
-
# ch_layout.addWidget(QLabel(f'channel {i}: '), 30)
|
|
402
|
-
# self.channel_cbs[i].addItems(self.channel_items)
|
|
403
|
-
# self.channel_cbs[i].currentIndexChanged.connect(self.check_valid_channels)
|
|
404
|
-
# ch_layout.addWidget(self.channel_cbs[i], 70)
|
|
405
|
-
# layout.addLayout(ch_layout)
|
|
311
|
+
self.ch_norm = ChannelNormGenerator(self, mode='signals')
|
|
312
|
+
layout.addLayout(self.ch_norm)
|
|
406
313
|
|
|
407
314
|
model_length_layout = QHBoxLayout()
|
|
408
315
|
model_length_layout.addWidget(QLabel('Max signal length: '), 30)
|
|
@@ -465,8 +372,9 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
465
372
|
|
|
466
373
|
self.pretrained_model = None
|
|
467
374
|
self.pretrained_lbl.setText('No folder chosen')
|
|
468
|
-
for cb in self.channel_cbs:
|
|
375
|
+
for cb in self.ch_norm.channel_cbs:
|
|
469
376
|
cb.setEnabled(True)
|
|
377
|
+
self.ch_norm.add_col_btn.setEnabled(True)
|
|
470
378
|
self.recompile_option.setEnabled(False)
|
|
471
379
|
self.cancel_pretrained.setVisible(False)
|
|
472
380
|
self.model_length_slider.setEnabled(True)
|
|
@@ -495,14 +403,15 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
495
403
|
self.model_length_slider.setValue(int(signal_length))
|
|
496
404
|
self.model_length_slider.setEnabled(False)
|
|
497
405
|
|
|
498
|
-
for c,cb in zip(channels, self.channel_cbs):
|
|
406
|
+
for c,cb in zip(channels, self.ch_norm.channel_cbs):
|
|
499
407
|
index = cb.findText(c)
|
|
500
408
|
cb.setCurrentIndex(index)
|
|
501
409
|
|
|
502
|
-
if len(channels)<len(self.channel_cbs):
|
|
503
|
-
for k in range(len(self.channel_cbs)-len(channels)):
|
|
504
|
-
self.channel_cbs[len(channels)+k].setCurrentIndex(0)
|
|
505
|
-
self.channel_cbs[len(channels)+k].setEnabled(False)
|
|
410
|
+
if len(channels)<len(self.ch_norm.channel_cbs):
|
|
411
|
+
for k in range(len(self.ch_norm.channel_cbs)-len(channels)):
|
|
412
|
+
self.ch_norm.channel_cbs[len(channels)+k].setCurrentIndex(0)
|
|
413
|
+
self.ch_norm.channel_cbs[len(channels)+k].setEnabled(False)
|
|
414
|
+
self.ch_norm.add_col_btn.setEnabled(False)
|
|
506
415
|
|
|
507
416
|
|
|
508
417
|
def adjustScrollArea(self):
|
|
@@ -524,23 +433,23 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
524
433
|
recompile_op = self.recompile_option.isChecked()
|
|
525
434
|
|
|
526
435
|
channels = []
|
|
527
|
-
for i in range(len(self.channel_cbs)):
|
|
528
|
-
channels.append(self.channel_cbs[i].currentText())
|
|
436
|
+
for i in range(len(self.ch_norm.channel_cbs)):
|
|
437
|
+
channels.append(self.ch_norm.channel_cbs[i].currentText())
|
|
529
438
|
|
|
530
439
|
slots_to_keep = np.where(np.array(channels)!='--')[0]
|
|
531
440
|
while '--' in channels:
|
|
532
441
|
channels.remove('--')
|
|
533
442
|
|
|
534
|
-
norm_values = np.array([[float(a.replace(',','.')),float(b.replace(',','.'))] for a,b in zip([l.text() for l in self.normalization_min_value_le],
|
|
535
|
-
[l.text() for l in self.normalization_max_value_le])])
|
|
443
|
+
norm_values = np.array([[float(a.replace(',','.')),float(b.replace(',','.'))] for a,b in zip([l.text() for l in self.ch_norm.normalization_min_value_le],
|
|
444
|
+
[l.text() for l in self.ch_norm.normalization_max_value_le])])
|
|
536
445
|
norm_values = norm_values[slots_to_keep]
|
|
537
446
|
norm_values = [list(v) for v in norm_values]
|
|
538
447
|
|
|
539
|
-
clip_values = np.array(self.clip_option)
|
|
448
|
+
clip_values = np.array(self.ch_norm.clip_option)
|
|
540
449
|
clip_values = list(clip_values[slots_to_keep])
|
|
541
450
|
clip_values = [bool(c) for c in clip_values]
|
|
542
451
|
|
|
543
|
-
normalization_mode = np.array(self.normalization_mode)
|
|
452
|
+
normalization_mode = np.array(self.ch_norm.normalization_mode)
|
|
544
453
|
normalization_mode = list(normalization_mode[slots_to_keep])
|
|
545
454
|
normalization_mode = [bool(m) for m in normalization_mode]
|
|
546
455
|
|
|
@@ -586,59 +495,4 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
586
495
|
|
|
587
496
|
train_signal_model(model_folder+"training_instructions.json")
|
|
588
497
|
|
|
589
|
-
self.parent_window.refresh_signal_models()
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
def check_valid_channels(self):
|
|
593
|
-
|
|
594
|
-
if np.all([cb.currentText()=='--' for cb in self.channel_cbs]):
|
|
595
|
-
self.submit_btn.setEnabled(False)
|
|
596
|
-
else:
|
|
597
|
-
self.submit_btn.setEnabled(True)
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
def switch_normalization_mode(self, index):
|
|
601
|
-
|
|
602
|
-
"""
|
|
603
|
-
Use absolute or percentile values for the normalization of each individual channel.
|
|
604
|
-
|
|
605
|
-
"""
|
|
606
|
-
|
|
607
|
-
currentNormMode = self.normalization_mode[index]
|
|
608
|
-
self.normalization_mode[index] = not currentNormMode
|
|
609
|
-
|
|
610
|
-
if self.normalization_mode[index]:
|
|
611
|
-
self.normalization_mode_btns[index].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
|
|
612
|
-
self.normalization_mode_btns[index].setIconSize(QSize(20, 20))
|
|
613
|
-
self.normalization_mode_btns[index].setStyleSheet(self.button_select_all)
|
|
614
|
-
self.normalization_mode_btns[index].setToolTip("Switch to absolute normalization values.")
|
|
615
|
-
self.normalization_min_value_lbl[index].setText('Min %: ')
|
|
616
|
-
self.normalization_max_value_lbl[index].setText('Max %: ')
|
|
617
|
-
self.normalization_min_value_le[index].setText('0.1')
|
|
618
|
-
self.normalization_max_value_le[index].setText('99.99')
|
|
619
|
-
|
|
620
|
-
else:
|
|
621
|
-
self.normalization_mode_btns[index].setIcon(icon(MDI6.percent_circle_outline,color="black"))
|
|
622
|
-
self.normalization_mode_btns[index].setIconSize(QSize(20, 20))
|
|
623
|
-
self.normalization_mode_btns[index].setStyleSheet(self.button_select_all)
|
|
624
|
-
self.normalization_mode_btns[index].setToolTip("Switch to percentile normalization values.")
|
|
625
|
-
self.normalization_min_value_lbl[index].setText('Min: ')
|
|
626
|
-
self.normalization_min_value_le[index].setText('0')
|
|
627
|
-
self.normalization_max_value_lbl[index].setText('Max: ')
|
|
628
|
-
self.normalization_max_value_le[index].setText('1000')
|
|
629
|
-
|
|
630
|
-
def switch_clipping_mode(self, index):
|
|
631
|
-
|
|
632
|
-
currentClipMode = self.clip_option[index]
|
|
633
|
-
self.clip_option[index] = not currentClipMode
|
|
634
|
-
|
|
635
|
-
if self.clip_option[index]:
|
|
636
|
-
self.normalization_clip_btns[index].setIcon(icon(MDI6.content_cut,color="#1565c0"))
|
|
637
|
-
self.normalization_clip_btns[index].setIconSize(QSize(20, 20))
|
|
638
|
-
self.normalization_clip_btns[index].setStyleSheet(self.button_select_all)
|
|
639
|
-
|
|
640
|
-
else:
|
|
641
|
-
self.normalization_clip_btns[index].setIcon(icon(MDI6.content_cut,color="black"))
|
|
642
|
-
self.normalization_clip_btns[index].setIconSize(QSize(20, 20))
|
|
643
|
-
self.normalization_clip_btns[index].setStyleSheet(self.button_select_all)
|
|
644
|
-
|
|
498
|
+
self.parent_window.refresh_signal_models()
|