-
Notifications
You must be signed in to change notification settings - Fork 5
/
mainwindow.py
1038 lines (837 loc) · 36.6 KB
/
mainwindow.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
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
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
"""
Module implementing MainWindow.
Copyright (c) 2012-2014, Emanuele Olivetti and Eleftherios Garyfallidis
Distributed under the BSD 3-clause license. See COPYING.txt.
"""
import os
import platform
if platform.system() == 'Darwin':
os.environ['DYLD_FALLBACK_LIBRARY_PATH']="/lib:/usr/lib:/usr/bin/lib:/System/Library/Frameworks/OpenGL.framework/Libraries:/usr/X11/lib:/"
from PySide.QtCore import Slot
from PySide.QtGui import QMainWindow
from Ui_mainwindow import *
from fos.vsml import vsml
from fos.actor import *
from fos.world import *
from glwidget import GLWidget
from tractome import Tractome, TractomeError
import sys
class MainWindow(QMainWindow, Ui_MainWindow):
"""
Class documentation goes here.
"""
def __init__(self, parent=None):
"""
Constructor
@param parent reference to the parent widget (QWidget)
"""
# calling base initializers
super(MainWindow, self).__init__(parent)
# calling base setupUi for ui configuration
self.setupUi(self)
# setting up the gui
self.setup_gui()
def setup_gui(self):
"""
"""
self.glWidget = GLWidget(parent = self.gridWidget_4,
width = 1508,
height = 713,
bgcolor = (.5, .5, 0.9),
enable_light = False)
self.gridLayout_4.addWidget(self.glWidget)
#for now, pbExtCluster will be invisible
self.pbExtCluster.setVisible(False)
# adding the editing items to ROI table
# double spinbox for x,y and z coordinates
self.dspbxcoord = QtGui.QDoubleSpinBox()
self.tblROI.setCellWidget(3, 1, self.dspbxcoord)
self.dspbycoord = QtGui.QDoubleSpinBox()
self.tblROI.setCellWidget(4, 1, self.dspbycoord)
self.dspbzcoord = QtGui.QDoubleSpinBox()
self.tblROI.setCellWidget(5, 1, self.dspbzcoord)
self.spbrad = QtGui.QSpinBox()
self.tblROI.setCellWidget(6, 1, self.spbrad)
# define method ROI
self.roimethod = 1 #tractome inside
# color button
self.colorlist = [QtGui.QColor('red'), QtGui.QColor('blue'), QtGui.QColor('green'), QtGui.QColor('yellow'), QtGui.QColor('cyan'), QtGui.QColor('black')]
self.btncolor = QtGui.QPushButton()
self.tblROI.setCellWidget(2, 1, self.btncolor)
self.btncolor.setAutoFillBackground(True)
# connect button with QColorDialog
self.connect(self.btncolor, QtCore.SIGNAL("clicked()"),
self.on_btncolor_clicked)
# visibility checkbox
self.chkbvis = QtGui.QCheckBox()
self.chkbvis.setCheckState(QtCore.Qt.Checked)
self.connect(self.chkbvis, QtCore.SIGNAL("stateChanged(int)"), self.on_chkbvis_stateChanged)
self.tblROI.setCellWidget(1, 1, self.chkbvis)
# self.show_hide_rows(True)
# creating the main Scene
self.tractome= Tractome()
self.add_scene(self.tractome.scene)
def changenumstreamlines_handler(self, n_stream):
"""
"""
if (n_stream< 1e5) and (n_stream>= 50):
default = 50
else:
default = n_stream
self.spbRecluster.setValue(default)
self.spbRecluster.setRange(1, n_stream)
self.hSlReCluster.setValue(default)
self.hSlReCluster.setMinimum(1)
self.hSlReCluster.setMaximum(min(150, n_stream))
self.tblTract.item(1, 1).setText(str(n_stream))
def changenumrepresentatives_handler(self, n_rep):
"""
"""
self.tblTract.item(2, 1).setText(str(n_rep))
def changenumknnextend_handler(self, changenn):
"""
"""
if changenn is True:
self.hSlExtclust.setValue(0)
def on_dspbxcoord_valueChanged(self, value):
"""
"""
self.tractome.update_ROI(self.tblROI.item(0, 1).text(), coordx = value, rebuild = self.list_chkROIS[self.activeROI].isChecked())
self.glWidget.updateGL()
def on_dspbycoord_valueChanged(self, value):
"""
"""
self.tractome.update_ROI(self.tblROI.item(0, 1).text(), coordy = value, rebuild = self.list_chkROIS[self.activeROI].isChecked())
self.glWidget.updateGL()
def on_dspbzcoord_valueChanged(self, value):
self.tractome.update_ROI(self.tblROI.item(0, 1).text(), coordz = value, rebuild = self.list_chkROIS[self.activeROI].isChecked())
self.glWidget.updateGL()
def on_spbrad_valueChanged(self, value):
"""
"""
self.tractome.update_ROI(self.tblROI.item(0, 1).text(), radius=value, rebuild = self.list_chkROIS[self.activeROI].isChecked())
self.glWidget.updateGL()
def on_chkbvis_stateChanged(self, state):
"""
Shows or hides the ROI if the visibility checkbox is checked
or not correspondingly.
"""
self.tractome.show_hide_actor(self.tblROI.item(0, 1).text(), state)
self.glWidget.updateGL()
@Slot(QtGui.QTreeWidgetItem, int)
def on_treeObject_itemClicked(self, item, column):
"""
If the item selected is a ROI, the corresponding information
will be shown in the tableROI.
"""
name = str(item.text(0))
xcoord, ycoord, zcoord, radius, color= self.tractome.information_from_ROI(name)
index= self.treeObject.indexFromItem(item)
self.activeROI = index.row()
self.disconnect(self.tblROI, QtCore.SIGNAL("itemChanged(QtGui.QTableWidgetItem)"), self.on_tblROI_itemChanged)
self.updateROItable(name, xcoord, ycoord, zcoord, radius, color)
self.connect(self.tblROI, QtCore.SIGNAL("itemChanged(QtGui.QTableWidgetItem)"), self.on_tblROI_itemChanged)
def on_btncolor_clicked(self):
"""
"""
color = QtGui.QColorDialog().getColor()
self.btncolor.setStyleSheet( u'background-color:%s' % color.name())
self.tractome.update_ROI(self.tblROI.item(0, 1).text(), color = color.getRgbF())
@Slot(int)
def on_chkbShowTract_stateChanged(self, state):
"""
Shows or hides the tractography if the Checkbox is checked or
not correspondingly
"""
self.tractome.show_hide_actor('Bundle Picker', state)
self.glWidget.updateGL()
@Slot(int)
def on_chkbShowStruct_stateChanged(self, state):
"""
Shows or hides the structural image if the Checkbox is checked
or not correspondingly
"""
self.tractome.show_hide_actor('Volume Slicer', state)
self.glWidget.updateGL()
# @Slot(bool)
# def on_rdbInsSphere_toggled(self, checked):
# """
# Use method of Tractome inside sphere to compute the ROI
# """
# if checked:
# self.roimethod = 1
# self.tractome.update_ROI(self.tblROI.item(0, 1).text(), method = self.roimethod, rebuild= True)
# if len(self.list_chkROIS)>0:
# self.tractome.compute_streamlines_ROIS()
# @Slot(bool)
# def on_rdbtrackvis_toggled(self, checked):
# """
# Use method of Trackvis to compute the ROI
# """
# if checked:
# self.roimethod = 0
# self.tractome.update_ROI(self.tblROI.item(0, 1).text(), method = self.roimethod, rebuild= True)
# if len(self.list_chkROIS)>0:
# self.tractome.compute_streamlines_ROIS()
@Slot(int)
def on_spbRecluster_valueChanged(self, p0):
"""
Update slider Recluster
"""
self.hSlReCluster.setValue(p0)
@Slot(int)
def on_hSlReCluster_valueChanged(self, value):
"""
Update spbRecluster
"""
self.spbRecluster.setValue(value)
@Slot()
def on_pbRecluster_clicked(self):
"""
Call re-cluster function from tractome and update values of possible number of clusters for related objects.
"""
self.tractome.recluster(self.spbRecluster.value())
self.hSlExtclust.setValue(0)
self.glWidget.updateGL()
@Slot(int)
def on_spbExtClust_valueChanged(self, p0):
"""
Update hSlExtclust and call method that computes kdtree-query.
"""
self.hSlExtclust.setValue(p0)
try:
self.tractome.compute_kqueries(p0)
self.glWidget.updateGL()
except TractomeError,e:
msgBox = QtGui.QMessageBox.critical(self, "Tractome Message", ''.join(e.args))
@Slot(int)
def on_hSlExtclust_valueChanged(self, value):
"""
Update spbExtClust.
"""
self.spbExtClust.setValue(value)
@Slot()
def on_pbExtCluster_clicked(self):
"""
Sets the new composition of clusters with the added neighbor streamlines
"""
self.tractome.set_streamlines_clusters()
self.glWidget.updateGL()
self.hSlExtclust.setValue(0)
@Slot()
def on_actionLoad_Structural_Image_triggered(self):
"""
Opens a dialog to allow the user to choose the structural
file.
"""
#Creating filedialog to search for the structural file
filedialog=QtGui.QFileDialog()
filedialog.setNameFilter(str("((*.gz *.nii *.img)"))
fileStruct, _= filedialog.getOpenFileName(self,"Open Structural file", os.getcwd(), str("(*.gz *.nii *.img)"))
if fileStruct != "":
struct_basename = os.path.basename(fileStruct)
self.create_update_Item('slicer')
self.tractome.loading_structural(fileStruct)
self.structnameitem.setText(0, struct_basename)
self.menu3D_Slicer.setEnabled(True)
self.refocus_camera()
@Slot()
def on_actionLoad_MASk_triggered(self):
"""
Opens a dialog to allow the user to choose the mask file.
"""
#Creating filedialog to search for the structural file
filedialog=QtGui.QFileDialog()
filedialog.setNameFilter(str("((*.gz *.nii *.img)"))
fileMask, _= filedialog.getOpenFileName(self,"Open Mask file", os.getcwd(), str("(*.gz *.nii *.img)"))
if fileMask !="":
mask_basename = os.path.basename(fileMask)
self.prepare_interface_ROI('mask', nameroi = mask_basename)
self.tractome.loading_mask(fileMask, self.roi_color)
self.updateROItable(mask_basename, color = self.roi_color.name())
self.glWidget.updateGL()
@Slot()
def on_actionLoad_Tractography_triggered(self):
"""
Opens a dialog to allow the user to choose the tractography
file.
"""
filedialog=QtGui.QFileDialog()
filedialog.setNameFilter(str("(*.dpy *.trk)"))
fileTract, _= filedialog.getOpenFileName(self,"Open Tractography file", os.getcwd(), str("(*.dpy *.trk)"))
if fileTract !="":
tracks_basename = os.path.basename(fileTract)
self.create_update_Item('tractography')
self.tractome.loading_full_tractograpy(tracpath=fileTract)
self.set_clustering_values()
self.tractnameitem.setText(0, tracks_basename)
# connecting event that is fired when number of streamlines is changed after some action on the streamlinelabeler actor
self.tractome.streamlab.numstream_handler += self.changenumstreamlines_handler
self.tractome.streamlab.numrep_handler += self.changenumrepresentatives_handler
self.tractome.streamlab.remselect_handler +=self.changenumknnextend_handler
#add information to tab in Table
self.tblTract.item(0, 1).setText(tracks_basename)
trackcount = len(self.tractome.T)
self.tblTract.item(1, 1).setText(str(trackcount))
self.tblTract.item(2, 1).setText(str(len(self.tractome.streamlab.representative_ids)))
if hasattr(self.tractome, 'header'):
hdr = self.tractome.header
self.tblTract.item(3, 1).setText(
str(hdr['voxel_sizes'].tolist()))
self.tblTract.item(4, 1).setText(
str(hdr['dimensions'].tolist()))
self.tblTract.item(5, 1).setText(str(hdr['voxel_order']))
else:
self.tblTract.item(3, 1).setText('No info')
self.tblTract.item(4, 1).setText('No info')
self.tblTract.item(5, 1).setText('LAS')
self.grbCluster.setEnabled(True)
self.grbExtendcluster.setEnabled(True)
self.menuTractography.setEnabled(True)
def create_update_Item(self, object):
"""
Creates or updates the specified item in the TreeObject and
the corresponding actor in the Scene (if neccesary).
"""
if object == 'tractography':
#checking if there is already a tractography open to substitute it
try:
self.tractnameitem
self.tractome.clear_actor('Bundle Picker')
self.clear_all_session()
#if there is no tractography open
except AttributeError:
self.tractnameitem = QtGui.QTreeWidgetItem(self.treeObject)
self.chkbShowTract.setEnabled(True)
self.tblTract.setEnabled(True)
self.actionSave_Segmentation.setEnabled(True)
self.actionSave_as_trackvis_file.setEnabled(True)
self.menuROI.setEnabled(True)
if object == 'slicer':
try:
self.structnameitem
self.treeObject.clear()
self.tractome.clear_all()
self.clear_all_session()
except AttributeError:
#If this is the first opening we create the tree item
self.chkbShowStruct.setEnabled(True)
self.actionLoad_Tractography.setEnabled(True)
self.structnameitem = QtGui.QTreeWidgetItem(self.treeObject)
@Slot()
def on_actionLoad_Saved_Segmentation_triggered(self):
"""
Opens a dialog to allow the user to choose a file of a
previously saved session.
"""
filedialog=QtGui.QFileDialog()
filedialog.setNameFilter(str("(*.seg)"))
fileSeg, _ = filedialog.getOpenFileName(self,"Open Segmentation file", os.getcwd(), str("(*.seg)"))
if fileSeg !="":
#checking if there is already a tractography open to substitute it
try:
self.structnameitem
self.tractnameitem
self.treeObject.clear()
self.tractome.clear_all()
self.clear_all_session()
#if there is no tractography open
except AttributeError:
self.chkbShowStruct.setEnabled(True)
self.chkbShowTract.setEnabled(True)
self.tblTract.setEnabled(True)
self.menuROI.setEnabled(True)
self.grbCluster.setEnabled(True)
self.grbExtendcluster.setEnabled(True)
self.actionLoad_Tractography.setEnabled(True)
self.actionSave_Segmentation.setEnabled(True)
self.actionSave_as_trackvis_file.setEnabled(True)
self.structnameitem = QtGui.QTreeWidgetItem(self.treeObject)
self.tractnameitem = QtGui.QTreeWidgetItem(self.treeObject)
self.tractome.load_segmentation(fileSeg)
#add structural and tractography file names to the treeview
struct_basename = os.path.basename(self.tractome.structpath)
self.structnameitem.setText(0, struct_basename)
tracks_basename = os.path.basename(self.tractome.tracpath)
self.set_clustering_values()
self.tractnameitem.setText(0, tracks_basename)
# connecting event that is fired when number of streamlines is changed after some action on the streamlinelabeler actor
self.tractome.streamlab.numstream_handler += self.changenumstreamlines_handler
self.tractome.streamlab.numrep_handler += self.changenumrepresentatives_handler
self.tractome.streamlab.remselect_handler +=self.changenumknnextend_handler
#add information to tab in Table
self.tblTract.item(0, 1).setText(tracks_basename)
trackcount = len(self.tractome.streamlab.streamline_ids)
self.tblTract.item(1, 1).setText(str(trackcount))
self.tblTract.item(2, 1).setText(str(len(self.tractome.streamlab.representative_ids)))
try:
hdr = self.tractome.hdr
self.tblTract.item(3, 1).setText(str(hdr['voxel_size']))
self.tblTract.item(4, 1).setText(str(hdr['dim']))
self.tblTract.item(5, 1).setText(str(hdr['voxel_order']))
except AttributeError:
self.tblTract.item(3, 1).setText('No info')
self.tblTract.item(4, 1).setText('No info')
self.tblTract.item(5, 1).setText('LAS')
self.refocus_camera()
def clear_all_session(self):
"""
Clear all the objects related to ROIs
"""
self.list_chkROIS = []
self.list_ands = []
self.list_ors = []
self.tblROISlist.clear()
self.tblROI.setEnabled(False)
self.tblROISlist.setEnabled(False)
self.tabProps_4.setCurrentIndex(0)
@Slot()
def on_actionSave_as_trackvis_file_triggered(self):
"""
Save streamlines of actual session in .trk file
"""
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save Segmentation in .trk', os.getcwd(), str("(*.trk)"))
self.tractome.save_trk(filename)
@Slot()
def on_actionSave_Segmentation_triggered(self):
"""
Saves the current session.
"""
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save Segmentation', os.getcwd(), str("(*.seg)"))
self.tractome.save_segmentation(filename)
@Slot()
def on_actionClose_triggered(self):
"""
Close application
"""
self.close()
def disconnect_signals(self):
"""
Disconnect signal of spinboxes in ROI tables. If they are
connected when updating min_max values of spinbox, the
valueChanged signal is unnecessarily called.
"""
self.disconnect(self.spbrad, QtCore.SIGNAL("valueChanged(int)"), self.on_spbrad_valueChanged)
self.disconnect(self.dspbxcoord, QtCore.SIGNAL("valueChanged(double)"), self.on_dspbxcoord_valueChanged)
self.disconnect(self.dspbycoord, QtCore.SIGNAL("valueChanged(double)"), self.on_dspbycoord_valueChanged)
self.disconnect(self.dspbzcoord, QtCore.SIGNAL("valueChanged(double)"), self.on_dspbzcoord_valueChanged)
def connect_signals(self):
"""
Reconnect signals of spinboxes in ROI tables, after min_max
values have been updated
"""
self.connect(self.spbrad, QtCore.SIGNAL("valueChanged(int)"), self.on_spbrad_valueChanged)
self.connect(self.dspbxcoord, QtCore.SIGNAL("valueChanged(double)"), self.on_dspbxcoord_valueChanged)
self.connect(self.dspbycoord, QtCore.SIGNAL("valueChanged(double)"), self.on_dspbycoord_valueChanged)
self.connect(self.dspbzcoord, QtCore.SIGNAL("valueChanged(double)"), self.on_dspbzcoord_valueChanged)
@Slot()
def on_actionCreate_Sphere_triggered(self):
"""
Create a ROI and plot sphere
"""
maxcoord = self.tractome.max_coordinates()
xmax = maxcoord[0]
ymax = maxcoord[1]
zmax = maxcoord[2]
self.grbROImethod.setEnabled(True)
self.rdbInsSphere.toggle()
cantrois = 0
if hasattr(self, 'list_chkROIS'):
cantrois = len(self.list_chkROIS)
number =cantrois + 1 #to define the name of the ROI depending on the number of available ROIs
nameroi = 'ROI'+ str(number)
self.prepare_interface_ROI('sphere', coords=maxcoord, nameroi = nameroi)
self.tractome.create_ROI_sphere(nameroi, xmax/2, ymax/2, zmax/2, 2, self.roimethod, self.roi_color.getRgbF(), self.roi_color.name())
#add info of the ROI to ROI table
self.updateROItable(nameroi, xmax/2, ymax/2, zmax/2, 2, self.roi_color.name())
self.tabProps_4.setCurrentIndex(1)
self.glWidget.updateGL()
# View related actions
@Slot()
def on_actionHide_Representative_H_triggered(self):
"""
Hide/Show selected representatives
"""
self.tractome.streamlab.process_keys(QtCore.Qt.Key_H, None)
self.glWidget.updateGL()
@Slot()
def on_actionSelect_All_Representatives_A_triggered(self):
"""
Select/Unselect all representatives
"""
self.tractome.streamlab.process_keys(QtCore.Qt.Key_A, None)
self.glWidget.updateGL()
@Slot()
def on_actionInvert_triggered(self):
"""
Invert selection of representatives
"""
self.tractome.streamlab.process_keys(QtCore.Qt.Key_I, None)
self.glWidget.updateGL()
@Slot()
def on_actionExpan_Selection_E_triggered(self):
"""
Show/Hide streamlines belonging to selected representatives.
"""
self.tractome.streamlab.process_keys(QtCore.Qt.Key_E, None)
self.glWidget.updateGL()
@Slot()
def on_actionRemove_Selected_Back_Space_triggered(self):
"""
Remove selected representatives.
"""
self.tractome.streamlab.process_keys(QtCore.Qt.Key_Backspace, None)
self.glWidget.updateGL()
@Slot()
def on_actionBack_B_triggered(self):
"""
Go one step back in history.
"""
self.tractome.streamlab.process_keys(QtCore.Qt.Key_B, None)
self.glWidget.updateGL()
@Slot()
def on_actionForward_F_triggered(self):
"""
Go one step forward in history.
"""
self.tractome.streamlab.process_keys(QtCore.Qt.Key_F, None)
self.glWidget.updateGL()
@Slot()
def on_actionPick_Representative_P_triggered(self):
"""
Show informatio about the "Pick representative" action.
"""
message = "This action cannot be executed from the Menu. In order to pick a representative please go to the screen, point with the mouse the desired representative and press the key P."
msgBox = QtGui.QMessageBox.information(self, "Tractome Message", message)
@Slot()
def on_actionShow_All_Slices_0_triggered(self):
"""
Hide/Show all slices of 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_0, None)
self.glWidget.updateGL()
@Slot()
def on_actionShow_1_triggered(self):
"""
Hide/Show Axial slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_1, None)
self.glWidget.updateGL()
@Slot()
def on_actionMove_Left_Left_triggered(self):
"""
Move left Axial slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_Left, None)
self.glWidget.updateGL()
@Slot()
def on_actionMove_Right_Right_triggered(self):
"""
Move right Axial slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_Right, None)
self.glWidget.updateGL()
@Slot()
def on_actionShow_2_triggered(self):
"""
Hide/Show Saggital slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_2, None)
self.glWidget.updateGL()
@Slot()
def on_actionMoveFront_Up_triggered(self):
"""
Move forward Saggital slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_PageUp, None)
self.glWidget.updateGL()
@Slot()
def on_actionMoveBack_Down_triggered(self):
"""
Move back Saggital slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_PageDown, None)
self.glWidget.updateGL()
@Slot()
def on_actionShow_3_triggered(self):
"""
Hide/Show Coronal slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_3, None)
self.glWidget.updateGL()
@Slot()
def on_actionMove_Up_Up_triggered(self):
"""
Move up Coronal slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_Up, None)
self.glWidget.updateGL()
@Slot()
def on_actionMove_Down_Down_triggered(self):
"""
Move down Coronal slice in 3DSlicer
"""
self.tractome.guil.process_keys(QtCore.Qt.Key_Down, None)
self.glWidget.updateGL()
def prepare_interface_ROI(self, roi_type, coords=None, nameroi = None):
"""
Set values and status of all interface elementes related to
ROI.
"""
self.tblROI.setEnabled(True)
self.tblROISlist.setEnabled(True)
self.show_hide_rows(roi_type == 'mask')
try:
self.list_chkROIS
except AttributeError:
self.list_chkROIS = []
self.list_ands = []
self.list_ors = []
# add some fixed information to ROI table
if roi_type == 'sphere':
maxcoord = coords
self.radmax = np.amax(maxcoord)
# self.grbROImethod.setEnabled(True)
# setting some fixed values in the table
self.dspbxcoord.setRange(0, maxcoord[0])
self.dspbycoord.setRange(0,maxcoord[1])
self.dspbzcoord.setRange(0, maxcoord[2])
self.spbrad.setRange(1, self.radmax)
self.connect_signals()
cantrois = len(self.list_chkROIS)
self.activeROI = cantrois # to know which is the ROI shown in the table, in case some information needs to be changed
# define color
if cantrois < len(self.colorlist):
self.roi_color = self.colorlist[self.activeROI]
else:
poscolor = self.activeROI%len(self.colorlist)
self.roi_color = self.colorlist[poscolor]
# add item to tractography in tree
roinameitem = QtGui.QTreeWidgetItem(self.tractnameitem)
roinameitem.setText(0, nameroi) #should we add the whole file path?
# roinameitem.setSelected(True)
self.treeObject.expandAll()
# create checkbox for applying ROI, add to list and to table for applied ROIs
newchkroi = QtGui.QCheckBox()
newchkroi.setText(nameroi)
self.connect(newchkroi, QtCore.SIGNAL("stateChanged(int)"), self.on_chkroi_stateChanged)
self.list_chkROIS.append(newchkroi)
# create rdbuttons for operators and add checkbox for ROI
cantchk = cantrois
sizetblROIs = self.tblROISlist.geometry()
if cantchk==0:
self.tblROISlist.insertRow(0)
self.tblROISlist.setCellWidget(0, 0, newchkroi)
else:
self.tblROISlist.insertRow((2*cantchk)-1)
# create groupbox
grb_roi_operators= QtGui.QGroupBox()
# create radio buttons
rdband = QtGui.QRadioButton("AND")
rdbor = QtGui.QRadioButton("OR")
rdbor.setText('OR')
# add radio button to groupbox
horizontalLayout_roiop = QtGui.QHBoxLayout()
horizontalLayout_roiop.addWidget(rdband)
horizontalLayout_roiop.addWidget(rdbor)
horizontalLayout_roiop.addStretch(1)
grb_roi_operators.setLayout(horizontalLayout_roiop)
self.connect(rdband, QtCore.SIGNAL("clicked(bool)"), self.on_rdb_clicked)
self.connect(rdbor, QtCore.SIGNAL("clicked(bool)"), self.on_rdb_clicked)
#
self.tblROISlist.setCellWidget((2*cantchk)-1, 0, grb_roi_operators)
self.list_ands.append(rdband)
self.list_ors.append(rdbor)
self.tblROISlist.insertRow(2*cantchk)
self.tblROISlist.setCellWidget(2*cantchk, 0, newchkroi)
self.tblROISlist.resizeRowsToContents()
#resizing objects
sizeandrdb = rdband.geometry()
sizeorrdb = rdbor.geometry()
rdband.setGeometry(sizeandrdb.left(), sizeandrdb.top(), 5, sizeandrdb.height())
rdbor.setGeometry(sizeorrdb.left(), sizeorrdb.top(), 5, sizeorrdb.height())
#resizing checkbox
sizecheckbox = newchkroi.geometry()
newchkroi.setGeometry(sizecheckbox.left(), sizecheckbox.top(), sizetblROIs.width(), sizecheckbox.height())
def updateROItable(self, name,coordx=None, coordy=None, coordz=None, radius=None, color=None):
"""
Information of ROI is inserted in table when new ROI is
created or when ROI selection changes in treeview.
"""
#show info of ROI in the table
self.tblROI.item(0, 1).setText(name)
if coordx is not None:
self.disconnect_signals()
self.dspbxcoord.setValue(coordx)
self.dspbycoord.setValue(coordy)
self.dspbzcoord.setValue(coordz)
self.spbrad.setValue(radius)
self.connect_signals()
self.btncolor.setStyleSheet( u'background-color:%s' % color)
def show_hide_rows(self, hide):
"""
Hides or shows rows from TableROI, depending on the type of
ROI is selected on the tree.
"""
for i in range(3, self.tblROI.rowCount()):
self.tblROI.setRowHidden(i, hide)
self.tblROI.resizeRowsToContents()
def on_chkroi_stateChanged(self, checked):
"""
Computing streamlines to show according to ROIs that are
checked and their operators.
"""
last_chkd = 0
for pos in range(0, len(self.list_chkROIS)):
if self.list_chkROIS[pos].isChecked():
self.tractome.activation_ROIs(pos, True)
if pos!=(len(self.list_chkROIS)-1) and ((self.list_ands[pos].isChecked()==False) and (self.list_ors[pos].isChecked()==False)):
self.list_ands[pos].setChecked(True)
else:
self.tractome.activation_ROIs(pos, False, operator = 'and')
if pos!=(len(self.list_chkROIS)-1):
if self.list_ands[pos].isChecked():
self.list_ands[pos].setAutoExclusive(False)
self.list_ands[pos].setChecked(False)
self.list_ands[pos].setAutoExclusive(True)
if self.list_ors[pos].isChecked():
self.list_ors[pos].setAutoExclusive(False)
self.list_ors[pos].setChecked(False)
self.list_ors[pos].setAutoExclusive(True)
self.tractome.compute_streamlines_ROIS()
self.glWidget.updateGL()
def on_rdb_clicked(self, clicked):
"""
Computing streamlines to show according to ROIs that are
checked and their operators.
"""
for pos in range(0, len(self.list_ands)):
if self.list_ands[pos].isChecked():
self.tractome.activation_ROIs(pos, True, operator = 'and')
if self.list_ors[pos].isChecked():
self.tractome.activation_ROIs(pos, True, operator = 'or')
self.tractome.compute_streamlines_ROIS()
self.glWidget.updateGL()
@Slot(QtGui.QTableWidgetItem)
def on_tblROI_itemChanged(self, item):
"""
Will change name of ROI if this is edited in the table.
"""
treeitem = self.tractnameitem.child(self.activeROI)
if item is self.tblROI.item(0, 1):
prev_name_roi = str(treeitem.text(0))
index = self.treeObject.indexFromItem(treeitem, 0)
if index.isValid():
self.tractome.update_ROI(prev_name_roi, newname = item.text(), pos_activeroi = self.activeROI)
treeitem.setText(0, item.text())
@Slot()
def on_actionRe_Cluster_triggered(self):
"""
Re-cluster.
"""
self.spbRecluster.setEnabled(True)
self.hSlReCluster.setEnabled(True)
self.pbRecluster.setEnabled(True)
def set_clustering_values(self):
"""
"""
max, default = self.tractome.max_num_clusters()
self.spbRecluster. setValue(default)
self.spbRecluster.setRange(1, max)
self.hSlReCluster.setValue(default)
self.hSlReCluster.setMinimum(1)
self.hSlReCluster.setMaximum(min(150, max))
def initSpincamera(self, angle = 0.007 ):
"""
"""
if self._spinCameraTimerInit:
self.spinCameraTimer.timeout.disconnect()
def rotate_camera():
self.glWidget.world.camera.rotate_around_focal( angle, "yup" )
self.glWidget.updateGL()
self.spinCameraTimer.timeout.connect(rotate_camera)
self._spinCameraTimerInit = True
def spinCameraToggle(self):
"""
"""
if not self.spinCameraTimer.isActive():
self.spinCameraTimer.start()
else:
self.spinCameraTimer.stop()
def timerInit(self, interval = 30):
"""
"""
timer = QtCore.QTimer(self)
timer.setInterval( interval )
return timer
def add_scene(self, scene):
"""
"""
self.glWidget.world.add_scene(scene)
def set_camera(self, camera):
"""
"""
self.glWidget.world.camera = camera
def refocus_camera(self):
"""
"""
self.glWidget.world.refocus_camera()
def update_light_position(self, x, y, z):
"""
"""
if not self.glWidget.world.light is None:
self.glWidget.world.update_lightposition(x, y, z)
def screenshot(self, filename):
""" Store current OpenGL context as image.
"""
self.glWidget.updateGL()
self.glWidget.grabFrameBuffer().save( filename )
def keyPressEvent(self, event):
""" Handle all key press events.
"""
# print 'key pressed', event.key()
key = event.key()
# self.messages=empty_messages.copy()
# self.messages['key_pressed']=key
# self.glWidget.world.send_all_messages(self.messages)
# F1: fullscreen
# F2: next frame
# F3: previous frame
# F4: start rotating
# F12: reset camera
# Esc: close window