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 | 97 | self.rotations = [0, 0, 0] |
98 | 98 | self.center = [0, 0, 0] |
99 | 99 | |
100 | + self.q_orientation = np.array((1, 0, 0, 0)) | |
101 | + | |
100 | 102 | self.number_of_colours = 256 |
101 | 103 | self.saturation_range = (0, 0) |
102 | 104 | self.hue_range = (0, 0) |
... | ... | @@ -583,11 +585,12 @@ class Slice(object): |
583 | 585 | rx, ry, rz = self.rotations |
584 | 586 | sx, sy, sz = self.spacing |
585 | 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 | 594 | T1 = transformations.translation_matrix((cz, cy, cx)) |
592 | 595 | M = transformations.concatenate_matrices(T1, R.T, T0) |
593 | 596 | ... | ... |
invesalius/data/styles.py
... | ... | @@ -43,6 +43,7 @@ from skimage import filter |
43 | 43 | import watershed_process |
44 | 44 | |
45 | 45 | import utils |
46 | +import transformations | |
46 | 47 | |
47 | 48 | ORIENTATIONS = { |
48 | 49 | "AXIAL": const.AXIAL, |
... | ... | @@ -1479,13 +1480,13 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1479 | 1480 | self.picker.Pick(x, y, 0, self.viewer.slice_data.renderer) |
1480 | 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 | 1490 | self.to_rot = True |
1490 | 1491 | |
1491 | 1492 | |
... | ... | @@ -1541,6 +1542,7 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1541 | 1542 | |
1542 | 1543 | def OnDblClick(self, evt): |
1543 | 1544 | self.viewer.slice_.rotations = [0, 0, 0] |
1545 | + self.viewer.slice_.q_orientation = np.array((1, 0, 0, 0)) | |
1544 | 1546 | self._discard_buffers() |
1545 | 1547 | self.viewer.slice_.current_mask.clear_history() |
1546 | 1548 | Publisher.sendMessage('Reload actual slice') |
... | ... | @@ -1582,20 +1584,49 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): |
1582 | 1584 | elif self.viewer.orientation == 'SAGITAL': |
1583 | 1585 | p1 = np.array((z-cz, y-cy)) |
1584 | 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 | 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 | 1600 | self.viewer.slice_.rotations[2] = angle |
1589 | 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 | 1603 | self.viewer.slice_.rotations[1] = angle |
1592 | 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 | 1606 | self.viewer.slice_.rotations[0] = angle |
1595 | 1607 | |
1596 | 1608 | self._discard_buffers() |
1597 | 1609 | self.viewer.slice_.current_mask.clear_history() |
1598 | 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 | 1631 | def _create_line(self, x0, y0, x1, y1, color): |
1601 | 1632 | line = vtk.vtkLineSource() | ... | ... |