Commit 3f79dd82d0bbdf493074ba34557dd45ec40d1c16
1 parent
b41e19ac
Exists in
rotvol
Almost done
Showing
4 changed files
with
56 additions
and
59 deletions
Show diff stats
invesalius/control.py
... | ... | @@ -84,6 +84,8 @@ class Controller(): |
84 | 84 | |
85 | 85 | Publisher.subscribe(self.ShowBooleanOpDialog, 'Show boolean dialog') |
86 | 86 | |
87 | + Publisher.subscribe(self.ApplyReorientation, 'Apply reorientation') | |
88 | + | |
87 | 89 | |
88 | 90 | def OnCancelImport(self, pubsub_evt): |
89 | 91 | #self.cancel_import = True |
... | ... | @@ -631,3 +633,6 @@ class Controller(): |
631 | 633 | def ShowBooleanOpDialog(self, pubsub_evt): |
632 | 634 | dlg = dialogs.MaskBooleanDialog(prj.Project().mask_dict) |
633 | 635 | dlg.Show() |
636 | + | |
637 | + def ApplyReorientation(self, pubsub_evt): | |
638 | + self.Slice.apply_reorientation() | ... | ... |
invesalius/data/slice_.py
... | ... | @@ -94,7 +94,6 @@ class Slice(object): |
94 | 94 | self.n_border = const.PROJECTION_BORDER_SIZE |
95 | 95 | |
96 | 96 | self._spacing = (1.0, 1.0, 1.0) |
97 | - self.rotations = [0, 0, 0] | |
98 | 97 | self.center = [0, 0, 0] |
99 | 98 | |
100 | 99 | self.q_orientation = np.array((1, 0, 0, 0)) |
... | ... | @@ -580,10 +579,8 @@ class Slice(object): |
580 | 579 | if self._type_projection == const.PROJECTION_NORMAL: |
581 | 580 | number_slices = 1 |
582 | 581 | |
583 | - if np.any(self.rotations): | |
582 | + if np.any(self.q_orientation[1::]): | |
584 | 583 | cx, cy, cz = self.center |
585 | - rx, ry, rz = self.rotations | |
586 | - sx, sy, sz = self.spacing | |
587 | 584 | T0 = transformations.translation_matrix((-cz, -cy, -cx)) |
588 | 585 | # Rx = transformations.rotation_matrix(rx, (0, 0, 1)) |
589 | 586 | # Ry = transformations.rotation_matrix(ry, (0, 1, 0)) |
... | ... | @@ -597,7 +594,7 @@ class Slice(object): |
597 | 594 | |
598 | 595 | if orientation == 'AXIAL': |
599 | 596 | tmp_array = np.array(self.matrix[slice_number:slice_number + number_slices]) |
600 | - if np.any(self.rotations): | |
597 | + if np.any(self.q_orientation[1::]): | |
601 | 598 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 2, self.matrix.min(), tmp_array) |
602 | 599 | if self._type_projection == const.PROJECTION_NORMAL: |
603 | 600 | n_image = tmp_array.squeeze() |
... | ... | @@ -644,7 +641,7 @@ class Slice(object): |
644 | 641 | |
645 | 642 | elif orientation == 'CORONAL': |
646 | 643 | tmp_array = np.array(self.matrix[:, slice_number: slice_number + number_slices, :]) |
647 | - if np.any(self.rotations): | |
644 | + if np.any(self.q_orientation[1::]): | |
648 | 645 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 1, self.matrix.min(), tmp_array) |
649 | 646 | |
650 | 647 | if self._type_projection == const.PROJECTION_NORMAL: |
... | ... | @@ -694,7 +691,7 @@ class Slice(object): |
694 | 691 | n_image = np.array(self.matrix[:, slice_number, :]) |
695 | 692 | elif orientation == 'SAGITAL': |
696 | 693 | tmp_array = np.array(self.matrix[:, :, slice_number: slice_number + number_slices]) |
697 | - if np.any(self.rotations): | |
694 | + if np.any(self.q_orientation[1::]): | |
698 | 695 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 1, self.matrix.min(), tmp_array) |
699 | 696 | |
700 | 697 | if self._type_projection == const.PROJECTION_NORMAL: |
... | ... | @@ -1365,6 +1362,30 @@ class Slice(object): |
1365 | 1362 | self.buffer_slices[o].discard_vtk_mask() |
1366 | 1363 | Publisher.sendMessage('Reload actual slice') |
1367 | 1364 | |
1365 | + def apply_reorientation(self): | |
1366 | + temp_file = tempfile.mktemp() | |
1367 | + mcopy = np.memmap(temp_file, shape=self.matrix.shape, dtype=self.matrix.dtype, mode='w+') | |
1368 | + mcopy[:] = self.matrix | |
1369 | + | |
1370 | + cx, cy, cz = self.center | |
1371 | + T0 = transformations.translation_matrix((-cz, -cy, -cx)) | |
1372 | + R = transformations.quaternion_matrix(self.q_orientation) | |
1373 | + T1 = transformations.translation_matrix((cz, cy, cx)) | |
1374 | + M = transformations.concatenate_matrices(T1, R.T, T0) | |
1375 | + | |
1376 | + transforms.apply_view_matrix_transform(mcopy, self.spacing, M, 0, 'AXIAL', 2, mcopy.min(), self.matrix) | |
1377 | + | |
1378 | + del mcopy | |
1379 | + os.remove(temp_file) | |
1380 | + | |
1381 | + self.q_orientation = np.array((1, 0, 0, 0)) | |
1382 | + self.center = [(s * d/2.0) for (d, s) in zip(self.matrix.shape[::-1], self.spacing)] | |
1383 | + | |
1384 | + self.__clean_current_mask(None) | |
1385 | + self.current_mask.matrix[:] = 0 | |
1386 | + | |
1387 | + Publisher.sendMessage('Reload actual slice') | |
1388 | + | |
1368 | 1389 | def __undo_edition(self, pub_evt): |
1369 | 1390 | buffer_slices = self.buffer_slices |
1370 | 1391 | actual_slices = {"AXIAL": buffer_slices["AXIAL"].index, | ... | ... |
invesalius/data/styles.py
... | ... | @@ -1426,7 +1426,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1426 | 1426 | |
1427 | 1427 | self.picker = vtk.vtkWorldPointPicker() |
1428 | 1428 | |
1429 | - # self.AddObserver("KeyPressEvent", self.OnKeyPress) | |
1430 | 1429 | self.AddObserver("LeftButtonPressEvent",self.OnLeftClick) |
1431 | 1430 | self.AddObserver("LeftButtonReleaseEvent", self.OnLeftRelease) |
1432 | 1431 | self.AddObserver("MouseMoveEvent", self.OnMouseMove) |
... | ... | @@ -1435,37 +1434,19 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1435 | 1434 | self.viewer.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnDblClick) |
1436 | 1435 | |
1437 | 1436 | def SetUp(self): |
1438 | - self.viewer.slice_.current_mask.is_shown = False | |
1439 | 1437 | self.draw_lines() |
1438 | + Publisher.sendMessage('Show mask', (self.viewer.slice_.current_mask.index, False)) | |
1440 | 1439 | Publisher.sendMessage('Reload actual slice') |
1441 | 1440 | |
1442 | 1441 | def CleanUp(self): |
1443 | 1442 | for actor in self.actors: |
1444 | 1443 | self.viewer.slice_data.renderer.RemoveActor(actor) |
1445 | 1444 | |
1446 | - def OnKeyPress(self, evt, obj): | |
1447 | - key = self.viewer.interactor.GetKeyCode() | |
1448 | - if key == '+': | |
1449 | - delta = 1 | |
1450 | - elif key == '-': | |
1451 | - delta = -1 | |
1452 | - else: | |
1453 | - return | |
1454 | - | |
1455 | - rx, ry, rz = self.viewer.slice_.rotations | |
1456 | - orientation = self.viewer.orientation | |
1457 | - if orientation == 'AXIAL': | |
1458 | - rz += np.deg2rad(delta) | |
1459 | - elif orientation == 'CORONAL': | |
1460 | - ry += np.deg2rad(delta) | |
1461 | - elif orientation == 'SAGITAL': | |
1462 | - rx += np.deg2rad(delta) | |
1463 | - | |
1464 | - self.viewer.slice_.rotations = (rx, ry, rz) | |
1445 | + self.viewer.slice_.rotations = [0, 0, 0] | |
1446 | + self.viewer.slice_.q_orientation = np.array((1, 0, 0, 0)) | |
1465 | 1447 | self._discard_buffers() |
1466 | - | |
1467 | - self.viewer.slice_.current_mask.clear_history() | |
1468 | - Publisher.sendMessage('Reload actual slice') | |
1448 | + Publisher.sendMessage('Show mask', (self.viewer.slice_.current_mask.index, True)) | |
1449 | + Publisher.sendMessage('Reload actual slice %s' % self.viewer.orientation) | |
1469 | 1450 | |
1470 | 1451 | def OnLeftClick(self, obj, evt): |
1471 | 1452 | if self._over_center: |
... | ... | @@ -1480,16 +1461,9 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1480 | 1461 | self.picker.Pick(x, y, 0, self.viewer.slice_data.renderer) |
1481 | 1462 | x, y, z = self.picker.GetPickPosition() |
1482 | 1463 | |
1483 | - # if self.viewer.orientation == 'AXIAL': | |
1484 | - # self.p0 = np.array((y-cy, x-cx)) | |
1485 | - # elif self.viewer.orientation == 'CORONAL': | |
1486 | - # self.p0 = np.array((z-cz, x-cx)) | |
1487 | - # elif self.viewer.orientation == 'SAGITAL': | |
1488 | - # self.p0 = np.array((z-cz, y-cy)) | |
1489 | 1464 | self.p0 = self.get_image_point_coord(x, y, z) |
1490 | 1465 | self.to_rot = True |
1491 | 1466 | |
1492 | - | |
1493 | 1467 | def OnLeftRelease(self, obj, evt): |
1494 | 1468 | self.dragging = False |
1495 | 1469 | |
... | ... | @@ -1501,7 +1475,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1501 | 1475 | """ |
1502 | 1476 | This event is responsible to reorient image, set mouse cursors |
1503 | 1477 | """ |
1504 | - | |
1505 | 1478 | if self.dragging: |
1506 | 1479 | self._move_center_rot() |
1507 | 1480 | elif self.to_rot: |
... | ... | @@ -1599,19 +1572,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1599 | 1572 | |
1600 | 1573 | self.viewer.slice_.q_orientation = transformations.quaternion_multiply(self.viewer.slice_.q_orientation, transformations.quaternion_about_axis(angle, axis)) |
1601 | 1574 | |
1602 | - # print axis, angle, self.viewer.slice_.q_orientation | |
1603 | - print axis, angle | |
1604 | - | |
1605 | - if self.viewer.orientation == 'AXIAL': | |
1606 | - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | |
1607 | - self.viewer.slice_.rotations[2] = angle | |
1608 | - elif self.viewer.orientation == 'CORONAL': | |
1609 | - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | |
1610 | - self.viewer.slice_.rotations[1] = angle | |
1611 | - elif self.viewer.orientation == 'SAGITAL': | |
1612 | - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | |
1613 | - self.viewer.slice_.rotations[0] = angle | |
1614 | - | |
1615 | 1575 | az, ay, ax = transformations.euler_from_quaternion(self.viewer.slice_.q_orientation) |
1616 | 1576 | Publisher.sendMessage('Update reorient angles', (ax, ay, az)) |
1617 | 1577 | |
... | ... | @@ -1677,7 +1637,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1677 | 1637 | self.line1 = self._create_line(0, 0.5, 1, 0.5, color1) |
1678 | 1638 | self.line2 = self._create_line(0.5, 0, 0.5, 1, color2) |
1679 | 1639 | |
1680 | - | |
1681 | 1640 | def _discard_buffers(self): |
1682 | 1641 | for buffer_ in self.viewer.slice_.buffer_slices.values(): |
1683 | 1642 | buffer_.discard_vtk_image() | ... | ... |
invesalius/gui/dialogs.py
... | ... | @@ -1576,13 +1576,14 @@ class ReorientImageDialog(wx.Dialog): |
1576 | 1576 | |
1577 | 1577 | self._init_gui() |
1578 | 1578 | self._bind_events() |
1579 | + self._bind_events_wx() | |
1579 | 1580 | |
1580 | 1581 | def _init_gui(self): |
1581 | - self.anglex = wx.TextCtrl(self, -1, "0.0") | |
1582 | - self.angley = wx.TextCtrl(self, -1, "0.0") | |
1583 | - self.anglez = wx.TextCtrl(self, -1, "0.0") | |
1582 | + self.anglex = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) | |
1583 | + self.angley = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) | |
1584 | + self.anglez = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) | |
1584 | 1585 | |
1585 | - btnapply = wx.Button(self, -1, _("Apply")) | |
1586 | + self.btnapply = wx.Button(self, -1, _("Apply")) | |
1586 | 1587 | |
1587 | 1588 | sizer = wx.BoxSizer(wx.HORIZONTAL) |
1588 | 1589 | |
... | ... | @@ -1598,7 +1599,7 @@ class ReorientImageDialog(wx.Dialog): |
1598 | 1599 | sizer.Add(self.anglez, 0, wx.EXPAND | wx.ALL, 5) |
1599 | 1600 | sizer.AddSpacer(5) |
1600 | 1601 | |
1601 | - sizer.Add(btnapply, 0, wx.EXPAND | wx.ALL, 5) | |
1602 | + sizer.Add(self.btnapply, 0, wx.EXPAND | wx.ALL, 5) | |
1602 | 1603 | sizer.AddSpacer(5) |
1603 | 1604 | |
1604 | 1605 | self.SetSizer(sizer) |
... | ... | @@ -1607,10 +1608,21 @@ class ReorientImageDialog(wx.Dialog): |
1607 | 1608 | def _bind_events(self): |
1608 | 1609 | Publisher.subscribe(self._update_angles, 'Update reorient angles') |
1609 | 1610 | |
1611 | + def _bind_events_wx(self): | |
1612 | + self.btnapply.Bind(wx.EVT_BUTTON, self.apply_reorientation) | |
1613 | + self.Bind(wx.EVT_CLOSE, self.OnClose) | |
1614 | + | |
1610 | 1615 | def _update_angles(self, pubsub_evt): |
1611 | 1616 | anglex, angley, anglez = pubsub_evt.data |
1612 | 1617 | self.anglex.SetValue("%.2f" % np.rad2deg(anglex)) |
1613 | 1618 | self.angley.SetValue("%.2f" % np.rad2deg(angley)) |
1614 | 1619 | self.anglez.SetValue("%.2f" % np.rad2deg(anglez)) |
1615 | 1620 | |
1616 | - print anglex, angley, anglez | |
1621 | + def apply_reorientation(self, evt): | |
1622 | + Publisher.sendMessage('Apply reorientation') | |
1623 | + self.Close() | |
1624 | + | |
1625 | + def OnClose(self, evt): | |
1626 | + Publisher.sendMessage('Disable style', const.SLICE_STATE_REORIENT) | |
1627 | + Publisher.sendMessage('Enable style', const.STATE_DEFAULT) | |
1628 | + self.Destroy() | ... | ... |