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() | ... | ... |