Commit 6a01b805c62a713f7ca83cfd3a028680b9c0ca6b
1 parent
64eec96a
Exists in
rotvol
Rotating using quaternion
Showing
2 changed files
with
49 additions
and
15 deletions
Show diff stats
invesalius/data/slice_.py
@@ -97,6 +97,8 @@ class Slice(object): | @@ -97,6 +97,8 @@ class Slice(object): | ||
97 | self.rotations = [0, 0, 0] | 97 | self.rotations = [0, 0, 0] |
98 | self.center = [0, 0, 0] | 98 | self.center = [0, 0, 0] |
99 | 99 | ||
100 | + self.q_orientation = np.array((1, 0, 0, 0)) | ||
101 | + | ||
100 | self.number_of_colours = 256 | 102 | self.number_of_colours = 256 |
101 | self.saturation_range = (0, 0) | 103 | self.saturation_range = (0, 0) |
102 | self.hue_range = (0, 0) | 104 | self.hue_range = (0, 0) |
@@ -583,11 +585,12 @@ class Slice(object): | @@ -583,11 +585,12 @@ class Slice(object): | ||
583 | rx, ry, rz = self.rotations | 585 | rx, ry, rz = self.rotations |
584 | sx, sy, sz = self.spacing | 586 | sx, sy, sz = self.spacing |
585 | T0 = transformations.translation_matrix((-cz, -cy, -cx)) | 587 | T0 = transformations.translation_matrix((-cz, -cy, -cx)) |
586 | - Rx = transformations.rotation_matrix(rx, (0, 0, 1)) | ||
587 | - Ry = transformations.rotation_matrix(ry, (0, 1, 0)) | ||
588 | - Rz = transformations.rotation_matrix(rz, (1, 0, 0)) | ||
589 | - # R = transformations.euler_matrix(rz, ry, rx, 'rzyx') | ||
590 | - R = transformations.concatenate_matrices(Rx, Ry, Rz) | 588 | + # Rx = transformations.rotation_matrix(rx, (0, 0, 1)) |
589 | + # Ry = transformations.rotation_matrix(ry, (0, 1, 0)) | ||
590 | + # Rz = transformations.rotation_matrix(rz, (1, 0, 0)) | ||
591 | + # # R = transformations.euler_matrix(rz, ry, rx, 'rzyx') | ||
592 | + # R = transformations.concatenate_matrices(Rx, Ry, Rz) | ||
593 | + R = transformations.quaternion_matrix(self.q_orientation) | ||
591 | T1 = transformations.translation_matrix((cz, cy, cx)) | 594 | T1 = transformations.translation_matrix((cz, cy, cx)) |
592 | M = transformations.concatenate_matrices(T1, R.T, T0) | 595 | M = transformations.concatenate_matrices(T1, R.T, T0) |
593 | 596 |
invesalius/data/styles.py
@@ -43,6 +43,7 @@ from skimage import filter | @@ -43,6 +43,7 @@ from skimage import filter | ||
43 | import watershed_process | 43 | import watershed_process |
44 | 44 | ||
45 | import utils | 45 | import utils |
46 | +import transformations | ||
46 | 47 | ||
47 | ORIENTATIONS = { | 48 | ORIENTATIONS = { |
48 | "AXIAL": const.AXIAL, | 49 | "AXIAL": const.AXIAL, |
@@ -1479,13 +1480,13 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1479,13 +1480,13 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1479 | self.picker.Pick(x, y, 0, self.viewer.slice_data.renderer) | 1480 | self.picker.Pick(x, y, 0, self.viewer.slice_data.renderer) |
1480 | x, y, z = self.picker.GetPickPosition() | 1481 | x, y, z = self.picker.GetPickPosition() |
1481 | 1482 | ||
1482 | - if self.viewer.orientation == 'AXIAL': | ||
1483 | - self.p0 = np.array((y-cy, x-cx)) | ||
1484 | - elif self.viewer.orientation == 'CORONAL': | ||
1485 | - self.p0 = np.array((z-cz, x-cx)) | ||
1486 | - elif self.viewer.orientation == 'SAGITAL': | ||
1487 | - self.p0 = np.array((z-cz, y-cy)) | ||
1488 | - | 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 | + self.p0 = self.get_image_point_coord(x, y, z) | ||
1489 | self.to_rot = True | 1490 | self.to_rot = True |
1490 | 1491 | ||
1491 | 1492 | ||
@@ -1541,6 +1542,7 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1541,6 +1542,7 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1541 | 1542 | ||
1542 | def OnDblClick(self, evt): | 1543 | def OnDblClick(self, evt): |
1543 | self.viewer.slice_.rotations = [0, 0, 0] | 1544 | self.viewer.slice_.rotations = [0, 0, 0] |
1545 | + self.viewer.slice_.q_orientation = np.array((1, 0, 0, 0)) | ||
1544 | self._discard_buffers() | 1546 | self._discard_buffers() |
1545 | self.viewer.slice_.current_mask.clear_history() | 1547 | self.viewer.slice_.current_mask.clear_history() |
1546 | Publisher.sendMessage('Reload actual slice') | 1548 | Publisher.sendMessage('Reload actual slice') |
@@ -1582,20 +1584,49 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1582,20 +1584,49 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1582 | elif self.viewer.orientation == 'SAGITAL': | 1584 | elif self.viewer.orientation == 'SAGITAL': |
1583 | p1 = np.array((z-cz, y-cy)) | 1585 | p1 = np.array((z-cz, y-cy)) |
1584 | p0 = self.p0 | 1586 | p0 = self.p0 |
1587 | + p1 = self.get_image_point_coord(x, y, z) | ||
1588 | + | ||
1589 | + axis = np.cross(p0, p1) | ||
1590 | + axis = axis / np.linalg.norm(axis) | ||
1591 | + angle = np.arccos(np.dot(p0, p1)/(np.linalg.norm(p0)*np.linalg.norm(p1))) | ||
1592 | + | ||
1593 | + self.viewer.slice_.q_orientation = transformations.quaternion_multiply(self.viewer.slice_.q_orientation, transformations.quaternion_about_axis(angle, axis)) | ||
1594 | + | ||
1595 | + # print axis, angle, self.viewer.slice_.q_orientation | ||
1596 | + print axis, angle | ||
1585 | 1597 | ||
1586 | if self.viewer.orientation == 'AXIAL': | 1598 | if self.viewer.orientation == 'AXIAL': |
1587 | - angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | 1599 | + # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) |
1588 | self.viewer.slice_.rotations[2] = angle | 1600 | self.viewer.slice_.rotations[2] = angle |
1589 | elif self.viewer.orientation == 'CORONAL': | 1601 | elif self.viewer.orientation == 'CORONAL': |
1590 | - angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | 1602 | + # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) |
1591 | self.viewer.slice_.rotations[1] = angle | 1603 | self.viewer.slice_.rotations[1] = angle |
1592 | elif self.viewer.orientation == 'SAGITAL': | 1604 | elif self.viewer.orientation == 'SAGITAL': |
1593 | - angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | 1605 | + # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) |
1594 | self.viewer.slice_.rotations[0] = angle | 1606 | self.viewer.slice_.rotations[0] = angle |
1595 | 1607 | ||
1596 | self._discard_buffers() | 1608 | self._discard_buffers() |
1597 | self.viewer.slice_.current_mask.clear_history() | 1609 | self.viewer.slice_.current_mask.clear_history() |
1598 | Publisher.sendMessage('Reload actual slice') | 1610 | Publisher.sendMessage('Reload actual slice') |
1611 | + self.p0 = self.get_image_point_coord(x, y, z) | ||
1612 | + | ||
1613 | + def get_image_point_coord(self, x, y, z): | ||
1614 | + cx, cy, cz = self.viewer.slice_.center | ||
1615 | + if self.viewer.orientation == 'AXIAL': | ||
1616 | + z = cz | ||
1617 | + elif self.viewer.orientation == 'CORONAL': | ||
1618 | + y = cy | ||
1619 | + elif self.viewer.orientation == 'SAGITAL': | ||
1620 | + x = cx | ||
1621 | + | ||
1622 | + x, y, z = x-cx, y-cy, z-cz | ||
1623 | + | ||
1624 | + M = transformations.quaternion_matrix(self.viewer.slice_.q_orientation) | ||
1625 | + tcoord = np.array((z, y, x, 1)).dot(M) | ||
1626 | + tcoord = tcoord[:3]/tcoord[3] | ||
1627 | + | ||
1628 | + # print (z, y, x), tcoord | ||
1629 | + return tcoord | ||
1599 | 1630 | ||
1600 | def _create_line(self, x0, y0, x1, y1, color): | 1631 | def _create_line(self, x0, y0, x1, y1, color): |
1601 | line = vtk.vtkLineSource() | 1632 | line = vtk.vtkLineSource() |