Commit a042b58e427ac48e1e6b4d1ec1bb5d9b3c71172a
Committed by
Thiago Franco de Moraes
1 parent
eac24f4f
Exists in
master
Dialog "go to" scanner coordinate system (#180)
* Created dialog goto sacnner coord * Get affine matrix from project or imported image -deals with wrongly affine shape and old inv projects * Update status GUI * Remove redundant sendmessage and show cross * cleaning...
Showing
6 changed files
with
137 additions
and
12 deletions
Show diff stats
invesalius/constants.py
invesalius/control.py
... | ... | @@ -58,7 +58,8 @@ class Controller(): |
58 | 58 | #None, others and opened Project = 0 |
59 | 59 | #DICOM = 1 |
60 | 60 | #TIFF uCT = 2 |
61 | - self.img_type = 0 | |
61 | + self.img_type = 0 | |
62 | + self.affine = None | |
62 | 63 | |
63 | 64 | #Init session |
64 | 65 | session = ses.Session() |
... | ... | @@ -108,6 +109,8 @@ class Controller(): |
108 | 109 | |
109 | 110 | Publisher.subscribe(self.OnSaveProject, 'Save project') |
110 | 111 | |
112 | + Publisher.subscribe(self.Send_affine, 'Get affine matrix') | |
113 | + | |
111 | 114 | def SetBitmapSpacing(self, spacing): |
112 | 115 | proj = prj.Project() |
113 | 116 | proj.spacing = spacing |
... | ... | @@ -368,6 +371,7 @@ class Controller(): |
368 | 371 | session = ses.Session() |
369 | 372 | session.CloseProject() |
370 | 373 | |
374 | + Publisher.sendMessage('Update status text in GUI', label=_("Ready")) | |
371 | 375 | ########################### |
372 | 376 | |
373 | 377 | def StartImportBitmapPanel(self, path): |
... | ... | @@ -862,11 +866,7 @@ class Controller(): |
862 | 866 | |
863 | 867 | hdr = group.header |
864 | 868 | if group.affine.any(): |
865 | - from numpy import hstack | |
866 | - from numpy.linalg import inv | |
867 | - affine = inv(group.affine) | |
868 | - affine[1, 3] = -affine[1, 3] | |
869 | - self.affine = hstack(affine) | |
869 | + self.affine = group.affine | |
870 | 870 | Publisher.sendMessage('Update affine matrix', |
871 | 871 | affine=self.affine, status=True) |
872 | 872 | hdr.set_data_dtype('int16') |
... | ... | @@ -889,6 +889,11 @@ class Controller(): |
889 | 889 | threshold_range=scalar_range) |
890 | 890 | return self.matrix, self.filename |
891 | 891 | |
892 | + def Send_affine(self): | |
893 | + if self.affine is not None: | |
894 | + Publisher.sendMessage('Update affine matrix', | |
895 | + affine=self.affine, status=True) | |
896 | + | |
892 | 897 | def LoadImagedataInfo(self): |
893 | 898 | proj = prj.Project() |
894 | 899 | ... | ... |
invesalius/data/surface.py
... | ... | @@ -337,7 +337,18 @@ class SurfaceManager(): |
337 | 337 | self.CreateSurfaceFromPolydata(polydata, name=name, scalar=scalar) |
338 | 338 | |
339 | 339 | def UpdateAffineMatrix(self, affine, status): |
340 | - self.affine = affine | |
340 | + try: | |
341 | + if status: | |
342 | + from numpy import hstack | |
343 | + from numpy.linalg import inv | |
344 | + affine = inv(affine) | |
345 | + affine[1, 3] = -affine[1, 3] | |
346 | + self.affine = hstack(affine) | |
347 | + else: | |
348 | + self.affine = None | |
349 | + except: | |
350 | + Publisher.sendMessage('Update affine matrix', | |
351 | + affine=None, status=False) | |
341 | 352 | |
342 | 353 | def UpdateconverttoInVflag(self, converttoInV): |
343 | 354 | self.converttoInV = converttoInV | ... | ... |
invesalius/gui/dialogs.py
... | ... | @@ -3685,3 +3685,94 @@ class GoToDialog(wx.Dialog): |
3685 | 3685 | def Close(self): |
3686 | 3686 | wx.Dialog.Close(self) |
3687 | 3687 | self.Destroy() |
3688 | + | |
3689 | + | |
3690 | +class GoToDialogScannerCoord(wx.Dialog): | |
3691 | + def __init__(self, title=_("Go to scanner coord...")): | |
3692 | + wx.Dialog.__init__(self, wx.GetApp().GetTopWindow(), -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.STAY_ON_TOP) | |
3693 | + self._init_gui() | |
3694 | + | |
3695 | + def _init_gui(self): | |
3696 | + self.goto_sagital = wx.TextCtrl(self, size=(50,-1)) | |
3697 | + self.goto_coronal = wx.TextCtrl(self, size=(50,-1)) | |
3698 | + self.goto_axial = wx.TextCtrl(self, size=(50,-1)) | |
3699 | + | |
3700 | + btn_ok = wx.Button(self, wx.ID_OK) | |
3701 | + btn_ok.SetHelpText("") | |
3702 | + btn_ok.SetDefault() | |
3703 | + | |
3704 | + btn_cancel = wx.Button(self, wx.ID_CANCEL) | |
3705 | + btn_cancel.SetHelpText("") | |
3706 | + | |
3707 | + btnsizer = wx.StdDialogButtonSizer() | |
3708 | + btnsizer.AddButton(btn_ok) | |
3709 | + btnsizer.AddButton(btn_cancel) | |
3710 | + btnsizer.Realize() | |
3711 | + | |
3712 | + sizer_create = wx.FlexGridSizer(3, 2, 10, 10) | |
3713 | + sizer_create.AddMany([(wx.StaticText(self, 1, _("Sagital coordinate:")), 1, wx.LEFT, 10), (self.goto_sagital, 1, wx.RIGHT, 10), | |
3714 | + (wx.StaticText(self, 1, _("Coronal coordinate:")), 1, wx.LEFT, 10), (self.goto_coronal, 1, wx.RIGHT, 10), | |
3715 | + (wx.StaticText(self, 1, _("Axial coordinate:")), 1, wx.LEFT, 10), (self.goto_axial, 1, wx.RIGHT, 10)]) | |
3716 | + | |
3717 | + main_sizer = wx.BoxSizer(wx.VERTICAL) | |
3718 | + | |
3719 | + main_sizer.Add((5, 5)) | |
3720 | + main_sizer.Add(sizer_create, proportion=3, flag=wx.CENTER, border=20) | |
3721 | + main_sizer.Add(btnsizer, proportion=1, flag=wx.CENTER|wx.TOP, border=5) | |
3722 | + main_sizer.Add((5, 5)) | |
3723 | + | |
3724 | + self.SetSizer(main_sizer) | |
3725 | + main_sizer.Fit(self) | |
3726 | + | |
3727 | + self.orientation = None | |
3728 | + self.affine = None | |
3729 | + | |
3730 | + self.__bind_events() | |
3731 | + | |
3732 | + btn_ok.Bind(wx.EVT_BUTTON, self.OnOk) | |
3733 | + Publisher.sendMessage('Get affine matrix') | |
3734 | + | |
3735 | + def __bind_events(self): | |
3736 | + Publisher.subscribe(self.SetNewFocalPoint, 'Cross focal point') | |
3737 | + Publisher.subscribe(self.UpdateAffineMatrix, 'Update affine matrix') | |
3738 | + | |
3739 | + def UpdateAffineMatrix(self, affine, status): | |
3740 | + self.affine = affine | |
3741 | + | |
3742 | + def SetNewFocalPoint(self, coord, spacing): | |
3743 | + Publisher.sendMessage('Update cross pos', coord=self.result*spacing) | |
3744 | + | |
3745 | + def OnOk(self, evt): | |
3746 | + from numpy.linalg import inv | |
3747 | + import invesalius.data.slice_ as slc | |
3748 | + try: | |
3749 | + #get affine from image import | |
3750 | + if self.affine is not None: | |
3751 | + affine = self.affine | |
3752 | + #get affine from project | |
3753 | + else: | |
3754 | + from invesalius.project import Project | |
3755 | + affine = Project().affine | |
3756 | + | |
3757 | + point = [float(self.goto_sagital.GetValue()), | |
3758 | + float(self.goto_coronal.GetValue()), | |
3759 | + float(self.goto_axial.GetValue())] | |
3760 | + | |
3761 | + # transformation from scanner coordinates to inv coord system | |
3762 | + affine = inv(affine) | |
3763 | + self.result = np.dot(affine[:3, :3], np.transpose(point[0:3])) + affine[:3, 3] | |
3764 | + self.result[1] = slc.Slice().GetMaxSliceNumber(const.CORONAL_STR) - self.result[1] | |
3765 | + | |
3766 | + Publisher.sendMessage('Update status text in GUI', label=_("Calculating the transformation ...")) | |
3767 | + | |
3768 | + Publisher.sendMessage('Set Update cross pos') | |
3769 | + Publisher.sendMessage("Toggle Cross", id=const.SLICE_STATE_CROSS) | |
3770 | + | |
3771 | + Publisher.sendMessage('Update status text in GUI', label=_("Ready")) | |
3772 | + except ValueError: | |
3773 | + pass | |
3774 | + self.Close() | |
3775 | + | |
3776 | + def Close(self): | |
3777 | + wx.Dialog.Close(self) | |
3778 | + self.Destroy() | ... | ... |
invesalius/gui/frame.py
... | ... | @@ -463,6 +463,8 @@ class Frame(wx.Frame): |
463 | 463 | self.OnRedo() |
464 | 464 | elif id == const.ID_GOTO_SLICE: |
465 | 465 | self.OnGotoSlice() |
466 | + elif id == const.ID_GOTO_COORD: | |
467 | + self.GoToDialogScannerCoord() | |
466 | 468 | |
467 | 469 | elif id == const.ID_BOOLEAN_MASK: |
468 | 470 | self.OnMaskBoolean() |
... | ... | @@ -700,6 +702,12 @@ class Frame(wx.Frame): |
700 | 702 | gt_dialog.ShowModal() |
701 | 703 | self.Refresh() |
702 | 704 | |
705 | + def GoToDialogScannerCoord(self): | |
706 | + gts_dialog = dlg.GoToDialogScannerCoord() | |
707 | + gts_dialog.CenterOnParent() | |
708 | + gts_dialog.ShowModal() | |
709 | + self.Refresh() | |
710 | + | |
703 | 711 | def OnMaskBoolean(self): |
704 | 712 | Publisher.sendMessage('Show boolean dialog') |
705 | 713 | |
... | ... | @@ -792,6 +800,7 @@ class MenuBar(wx.MenuBar): |
792 | 800 | sub(self.OnEnableState, "Enable state project") |
793 | 801 | sub(self.OnEnableUndo, "Enable undo") |
794 | 802 | sub(self.OnEnableRedo, "Enable redo") |
803 | + sub(self.OnEnableGotoCoord, "Update affine matrix") | |
795 | 804 | sub(self.OnEnableNavigation, "Navigation status") |
796 | 805 | |
797 | 806 | sub(self.OnAddMask, "Add mask") |
... | ... | @@ -859,6 +868,8 @@ class MenuBar(wx.MenuBar): |
859 | 868 | file_edit.Append(wx.ID_UNDO, _("Undo\tCtrl+Z")).Enable(False) |
860 | 869 | file_edit.Append(wx.ID_REDO, _("Redo\tCtrl+Y")).Enable(False) |
861 | 870 | file_edit.Append(const.ID_GOTO_SLICE, _("Go to slice ...\tCtrl+G")) |
871 | + file_edit.Append(const.ID_GOTO_COORD, _("Go to scanner coord ...\t")).Enable(False) | |
872 | + | |
862 | 873 | #app(const.ID_EDIT_LIST, "Show Undo List...") |
863 | 874 | ################################################################# |
864 | 875 | |
... | ... | @@ -1077,6 +1088,16 @@ class MenuBar(wx.MenuBar): |
1077 | 1088 | else: |
1078 | 1089 | self.FindItemById(wx.ID_REDO).Enable(False) |
1079 | 1090 | |
1091 | + def OnEnableGotoCoord(self, affine, status): | |
1092 | + """ | |
1093 | + Disable goto coord either if there is no affine matrix or affine is wrongly imported. | |
1094 | + :param status: Affine matrix status | |
1095 | + """ | |
1096 | + if status: | |
1097 | + self.FindItemById(const.ID_GOTO_COORD).Enable(True) | |
1098 | + else: | |
1099 | + self.FindItemById(const.ID_GOTO_COORD).Enable(False) | |
1100 | + | |
1080 | 1101 | def OnEnableNavigation(self, status): |
1081 | 1102 | """ |
1082 | 1103 | Disable mode menu when navigation is on. | ... | ... |
invesalius/gui/task_navigator.py
... | ... | @@ -478,8 +478,6 @@ class NeuronavigationPanel(wx.Panel): |
478 | 478 | ctrl.SetSelection(0) |
479 | 479 | print("Tracker not connected!") |
480 | 480 | else: |
481 | - Publisher.sendMessage('Update status text in GUI', | |
482 | - label=_("Ready")) | |
483 | 481 | ctrl.SetSelection(self.tracker_id) |
484 | 482 | print("Tracker connected!") |
485 | 483 | elif choice == 6: |
... | ... | @@ -513,10 +511,8 @@ class NeuronavigationPanel(wx.Panel): |
513 | 511 | dlg.NavigationTrackerWarning(self.tracker_id, self.trk_init[1]) |
514 | 512 | self.tracker_id = 0 |
515 | 513 | ctrl.SetSelection(self.tracker_id) |
516 | - else: | |
517 | - Publisher.sendMessage('Update status text in GUI', | |
518 | - label=_("Ready")) | |
519 | 514 | |
515 | + Publisher.sendMessage('Update status text in GUI', label=_("Ready")) | |
520 | 516 | Publisher.sendMessage('Update tracker initializer', |
521 | 517 | nav_prop=(self.tracker_id, self.trk_init, self.ref_mode_id)) |
522 | 518 | ... | ... |