...
 
Commits (4)
"""
Module to show slice views of volumetric data.
"""
import os
import vtk
import numpy as np
from PySide2 import QtWidgets
......@@ -12,8 +13,8 @@ from sksurgeryvtk.widgets.QVTKRenderWindowInteractor \
#pylint:disable=too-many-instance-attributes
class VTKResliceWidget(QVTKRenderWindowInteractor):
""" Widget to show a single slice of DICOM Data.
:param reader: vtkDICOMImageReader
""" Widget to show a single slice of Volumetric Data.
:param reader: vtkReader class e.g. DICOM/Niftii/gipl
:param axis: x/y/z axis selection
:param parent: parent QWidget.
"""
......@@ -58,7 +59,7 @@ class VTKResliceWidget(QVTKRenderWindowInteractor):
if axis == "y":
self.renderer.GetActiveCamera().Elevation(90)
self.set_slice_position(0)
self.set_slice_position_mm(0)
self.renderer.ResetCamera(self.actor.GetBounds())
self.GetRenderWindow().AddRenderer(self.renderer)
......@@ -88,8 +89,8 @@ class VTKResliceWidget(QVTKRenderWindowInteractor):
self.actor.GetMapper().SetInputConnection(self.colours.GetOutputPort())
def set_slice_position(self, pos):
""" Set the slice position in the volume """
def set_slice_position_pixels(self, pos):
""" Set the slice position in the volume in pixels """
pos = int(pos)
......@@ -114,6 +115,15 @@ class VTKResliceWidget(QVTKRenderWindowInteractor):
self.renderer.ResetCamera(self.actor.GetBounds())
self.GetRenderWindow().Render()
def set_slice_position_mm(self, pos):
""" Set the slice position in the volume in mm """
if self.axis == 'x':
self.set_slice_position_pixels(pos / self.x_spacing)
if self.axis == 'y':
self.set_slice_position_pixels(pos / self.y_spacing)
if self.axis == 'z':
self.set_slice_position_pixels(pos / self.z_spacing)
def get_slice_position(self):
""" Return the current slice position. """
return self.position
......@@ -127,20 +137,20 @@ class VTKResliceWidget(QVTKRenderWindowInteractor):
if self.axis == 'z':
lower, upper = self.z_min, self.z_max
self.set_slice_position(lower + (upper - lower) // 2)
self.set_slice_position_mm(lower + (upper - lower) // 2)
def on_mouse_wheel_forward(self, obj, event):
#pylint:disable=unused-argument
""" Callback to change slice position using mouse wheel. """
current_position = self.get_slice_position()
self.set_slice_position(current_position + 1)
self.set_slice_position_pixels(current_position + 1)
def on_mouse_wheel_backward(self, obj, event):
#pylint:disable=unused-argument
""" Callback to change slice position using mouse wheel. """
current_position = self.get_slice_position()
self.set_slice_position(current_position - 1)
self.set_slice_position_pixels(current_position - 1)
def set_mouse_wheel_callbacks(self):
""" Add callbacks for scroll events. """
......@@ -153,9 +163,9 @@ class VTKResliceWidget(QVTKRenderWindowInteractor):
class VTKSliceViewer(QtWidgets.QWidget):
""" Othrogonal slice viewer showing Axial/Sagittal/Coronal views
:param dicom_dir: path to folder containig dicom data """
:param input_data: path to volume data """
def __init__(self, dicom_dir):
def __init__(self, input_data):
super().__init__()
......@@ -163,8 +173,14 @@ class VTKSliceViewer(QtWidgets.QWidget):
self.setLayout(self.layout)
# Start by loading some data.
self.reader = vtk.vtkDICOMImageReader()
self.reader.SetDirectoryName(dicom_dir)
if os.path.isdir(input_data):
self.reader = vtk.vtkDICOMImageReader()
self.reader.SetDirectoryName(input_data)
elif input_data.endswith(('.nii', '.nii.gz')):
self.reader = vtk.vtkNIFTIImageReader()
self.reader.SetFileName(input_data)
self.reader.Update()
self.frame = QtWidgets.QFrame()
......@@ -202,15 +218,26 @@ class VTKSliceViewer(QtWidgets.QWidget):
self.y_view.set_lookup_table_min_max(min, max)
self.z_view.set_lookup_table_min_max(min, max)
def update_slice_positions(self, x_pos, y_pos, z_pos):
def update_slice_positions_mm(self, x_pos, y_pos, z_pos):
""" Set the slice positions for each view.
:param x: slice 1 position
:param y: slice 2 position
:param z: slice 3 position
"""
self.x_view.set_slice_position_mm(x_pos)
self.y_view.set_slice_position_mm(y_pos)
self.z_view.set_slice_position_mm(z_pos)
self.fourth_panel.GetRenderWindow().Render()
def update_slice_positions_pixels(self, x_pos, y_pos, z_pos):
""" Set the slice positions for each view.
:param x: slice 1 position
:param y: slice 2 position
:param z: slice 3 position
"""
self.x_view.set_slice_position(x_pos)
self.y_view.set_slice_position(y_pos)
self.z_view.set_slice_position(z_pos)
self.x_view.set_slice_position_pixels(x_pos)
self.y_view.set_slice_position_pixels(y_pos)
self.z_view.set_slice_position_pixels(z_pos)
self.fourth_panel.GetRenderWindow().Render()
def reset_slice_positions(self):
......@@ -229,17 +256,17 @@ class MouseWheelSliceViewer(VTKSliceViewer):
Example usage:
qApp = QtWidgets.QApplication([])
dicom_path = 'tests/data/dicom/LegoPhantom_10slices'
input_data = 'tests/data/dicom/LegoPhantom_10slices'
slice_viewer = MouseWheelSliceViewer(dicom_path)
slice_viewer = MouseWheelSliceViewer(input_data)
slice_viewer.start()
qApp.exec_()
"""
def __init__(self, dicom_dir):
def __init__(self, input_data):
super().__init__(dicom_dir)
super().__init__(input_data)
self.x_view.set_mouse_wheel_callbacks()
self.y_view.set_mouse_wheel_callbacks()
......@@ -267,24 +294,24 @@ class TrackedSliceViewer(VTKSliceViewer):
#pylint:disable=invalid-name
""" Orthogonal slice viewer combined with tracker to
control slice position.
:param dicom_dir: Path to folder containing dicom data.
:param input_data: Path to file/folder containing volume data
:param tracker: scikit-surgery tracker object,
used to control slice positions.
Example usage:
qApp = QtWidgets.QApplication([])
dicom_path = 'tests/data/dicom/LegoPhantom_10slices'
input_data = 'tests/data/dicom/LegoPhantom_10slices'
tracker = ArUcoTracker()
slice_viewer = MouseWheelSliceViewer(dicom_path, tracker)
slice_viewer = MouseWheelSliceViewer(input_data, tracker)
slice_viewer.start()
qApp.exec_()
"""
def __init__(self, dicom_dir, tracker):
def __init__(self, input_data, tracker):
super().__init__(dicom_dir)
super().__init__(input_data)
self.tracker = tracker
self.update_rate = 20
......@@ -298,7 +325,7 @@ class TrackedSliceViewer(VTKSliceViewer):
tracking_data[0][1][3], \
tracking_data[0][2][3]
self.update_slice_positions(x, y, z)
self.update_slice_positions_mm(x, y, z)
def start(self):
#pylint:disable=attribute-defined-outside-init, no-member
......
......@@ -8,7 +8,7 @@ def test_slice_viewer(qtbot):
qtbot.addWidget(reslice)
reslice.update_slice_positions(1,1,1)
reslice.update_slice_positions_pixels(1,1,1)
def test_mouse_scroll_slice_viewer(qtbot):
......@@ -17,5 +17,5 @@ def test_mouse_scroll_slice_viewer(qtbot):
qtbot.addWidget(reslice)
reslice.update_slice_positions(1,1,1)
reslice.update_slice_positions_pixels(1,1,1)