def __init__(self, *args, **kwargs): super(PyView2D, self).__init__(*args, **kwargs) self.block_signal = False self.reader = vtkDICOMImageReader() self.reader2 = vtkDICOMImageReader() self.window = self.GetRenderWindow() self.window.BordersOff( ) #attempt to remove imageactor borders, can remove self.center = [0, 0, 0] self.current_image = vtk.vtkImageData() self.viewer_id = "default" self.viewer_setup() # flexible for future self.image_loaded = False self.viewer_initialized = False # self.read_image(image_path=None, orientation="axial") # flexible for future self.window_level = vtkImageMapToWindowLevelColors() self.img = self.map_img() self.roi = self.map_roi() self.px_coord_text_prop = vtkTextProperty() self.px_coord_text_mapper = vtkTextMapper() self.px_coord_text_actor = vtkActor2D() self.world_coord_text_prop = vtkTextProperty() self.world_coord_text_mapper = vtkTextMapper() self.world_coord_text_actor = vtkActor2D() self.usage_text_prop = vtkTextProperty() self.usage_text_mapper = vtkTextMapper() self.usage_text_actor = vtkActor2D() self.renderer = vtkRenderer() # self.add_text() self.renderer.AddActor(self.img) # self.renderer.AddActor(self.roi) # self.renderer.SetBackground(0.2, 0.3, 0.4) # ### Wasil added ### #QVTKRenderWindowInteractor relays Qt events to VTK # self.frame = Qt.QFrame() # do i need this # self.vtkWidget = QVTKRenderWindowInteractor(self.frame) # miu_viewer = PyView2D() # vtkWidget has its own RenderWindow # self.ren = vtk.vtkRenderer() # or # self.ren = miu_viewer.renderer # should have the actors already # self.vtkWidget.GetRenderWindow().AddRenderer(self.renderer) # self.vtkWidget.GetRenderWindow().SetSize(1000, 1000) # miu_viewer.window.Render() # or # self.vtkWidget.GetRenderWindow().Render() ########################## # have vtkRenderWindow # add VTKrenderer # self.window = vtkRenderWindow() self.window.AddRenderer(self.renderer) # # self.window.SetSize(1000, 1000) self.window.SetSize(300, 300) self.interactor_style = vtkInteractorStyleImage() self.interactor_style.SetInteractionModeToImageSlicing() # self.interactor = vtkRenderWindowInteractor() # # self.iren is the interactor (also from RenderWindow) self.interactor = self.GetRenderWindow().GetInteractor() self.interactor.SetInteractorStyle(self.interactor_style) # self.window.SetInteractor(self.interactor) # self.window_level.SetWindow(1000) self.window_level.SetLevel(200) self.window_level.Update() self.window.Render() ### moved this down to after image is loaded # self.interactor_style.AddObserver("MouseWheelForwardEvent", self.scroll_forward_callback) # self.interactor_style.AddObserver("MouseWheelBackwardEvent", self.scroll_backward_callback) # self.interactor_style.AddObserver("MouseMoveEvent", self.mouse_move_callback) # self.interactor_style.AddObserver("KeyPressEvent", self.key_press_callback) # self.interactor_style.AddObserver("LeftButtonPressEvent", self.left_press_callback) # self.window.AddObserver("ModifiedEvent", self.window_mod_callback) self.actions = { "Slicing": 0, "Cursor": 0, "CurrentPos": -1, "LastPos": -1, "DoubleClick": 0 }
def main(): VTK_DATA_ROOT = vtkGetDataRoot() folder = "/Users/nandana/Downloads/image_ex" #read dicom files from specified directory reader = vtkDICOMImageReader() reader.SetDirectoryName(folder) reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter") reader.SetDataExtent(0, 63, 0, 63, 1, 93) reader.SetDataSpacing(3.2, 3.2, 1.5) reader.SetDataOrigin(-150.0, 150.0, 3.0) reader.SetDataScalarTypeToUnsignedShort() reader.UpdateWholeExtent() # Calculate the center of the volume reader.Update() (xMin, xMax, yMin, yMax, zMin, zMax) = reader.GetExecutive().GetWholeExtent( reader.GetOutputInformation(0)) (xSpacing, ySpacing, zSpacing) = reader.GetOutput().GetSpacing() (x0, y0, z0) = reader.GetOutput().GetOrigin() center = [ x0 + xSpacing * 0.5 * (xMin + xMax), y0 + ySpacing * 0.5 * (yMin + yMax), z0 + zSpacing * 0.5 * (zMin + zMax) ] yd = ((yMax - yMin) + 1) * ySpacing """ # Matrices for axial, coronal, sagittal, oblique view orientations axial = vtkMatrix4x4() axial.DeepCopy((1, 0, 0, center[0], 0, 1, 0, center[1], 0, 0, 1, center[2], 0, 0, 0, 1)) coronal = vtkMatrix4x4() coronal.DeepCopy((1, 0, 0, center[0], 0, 0, 1, center[1], 0,-1, 0, center[2], 0, 0, 0, 1)) sagittal = vtkMatrix4x4 sagittal.DeepCopy((0, 0,-1, center[0], 1, 0, 0, center[1], 0,-1, 0, center[2], 0, 0, 0, 1)) oblique = vtkMatrix4x4() oblique.DeepCopy((1, 0, 0, center[0], 0, 0.866025, -0.5, center[1], 0, 0.5, 0.866025, center[2], 0, 0, 0, 1)) reslice = vtkImageReslice() outputPort = reader.GetOutputPort() #reslice.SetInputConnection(reader.GetOutputPort()) reslice.SetInputConnection(0, reader.GetOutputPort()) print(reader.GetOutput().GetExtent()) reslice.SetOutputExtent(reader.GetOutput().GetExtent()) reslice.SetOutputDimensionality(2) reslice.SetResliceAxes(coronal) reslice.SetInterpolationModeToLinear() """ # Visualize imageViewer = vtkResliceImageViewer() imageViewer.SetSliceOrientationToXY() #imageViewer.SetSlice(9) imageViewer.SetResliceModeToAxisAligned() imageViewer.SliceScrollOnMouseWheelOff() imageViewer.SetInputData(reader.GetOutput()) #imageViewer.Render() camera = imageViewer.GetRenderer().GetActiveCamera() print(camera.GetOrientationWXYZ()) # slice status message sliceTextProp = vtkTextProperty() sliceTextProp.SetFontFamilyToCourier() sliceTextProp.SetFontSize(20) sliceTextProp.SetVerticalJustificationToBottom() sliceTextProp.SetJustificationToLeft() sliceTextMapper = vtkTextMapper() msg = "Slice {} out of {}".format(imageViewer.GetSlice() + 1, \ imageViewer.GetSliceMax() + 1) sliceTextMapper.SetInput(msg) sliceTextMapper.SetTextProperty(sliceTextProp) sliceTextActor = vtkActor2D() sliceTextActor.SetMapper(sliceTextMapper) sliceTextActor.SetPosition(100, 10) # coordinate display coordTextProp = vtkTextProperty() coordTextProp.SetFontFamilyToCourier() coordTextProp.SetFontSize(20) coordTextProp.SetVerticalJustificationToBottom() coordTextProp.SetJustificationToLeft() coordTextMapper = vtkTextMapper() coordTextMapper.SetInput("Pixel Coordinates: (--, --)") coordTextMapper.SetTextProperty(coordTextProp) coordTextActor = vtkActor2D() coordTextActor.SetMapper(coordTextMapper) coordTextActor.SetPosition(500, 10) worldCoordTextProp = vtkTextProperty() worldCoordTextProp.SetFontFamilyToCourier() worldCoordTextProp.SetFontSize(20) worldCoordTextProp.SetVerticalJustificationToBottom() worldCoordTextProp.SetJustificationToLeft() worldCoordTextMapper = vtkTextMapper() worldCoordTextMapper.SetInput("World Coordinates: (--, --)") worldCoordTextMapper.SetTextProperty(worldCoordTextProp) worldCoordTextActor = vtkActor2D() worldCoordTextActor.SetMapper(worldCoordTextMapper) worldCoordTextActor.SetPosition(500, 30) # usage hint message usageTextProp = vtkTextProperty() usageTextProp.SetFontFamilyToCourier() usageTextProp.SetFontSize(14) usageTextProp.SetVerticalJustificationToTop() usageTextProp.SetJustificationToLeft() usageTextMapper = vtkTextMapper() usageTextMapper.SetInput( "- Slice with mouse wheel\n- Zoom with pressed right\n mouse button while dragging\n- Press i to toggle cursor line on/off" ) usageTextMapper.SetTextProperty(usageTextProp) usageTextActor = vtkActor2D() usageTextActor.SetMapper(usageTextMapper) usageTextActor.GetPositionCoordinate( ).SetCoordinateSystemToNormalizedDisplay() usageTextActor.GetPositionCoordinate().SetValue(0.05, 0.95) actor = imageViewer.GetImageActor() #image = vtkImageActor() #actor.GetMapper().SetInputData(reader.GetOutput()) image = imageViewer.GetInput() roiData = vtkImageData() roiImage = vtkImageActor() roiData.DeepCopy(image) extent = roiData.GetExtent() for i in range(extent[0], extent[1]): for j in range(extent[2], extent[3]): for k in range(extent[4], extent[5]): if image.GetScalarComponentAsDouble(i, j, k, 0) > -100: roiData.SetScalarComponentFromDouble(i, j, k, 0, 1) #roiData.SetScalarComponentFromDouble(0, i, j, k, 1) else: #just in case roiData.SetScalarComponentFromDouble(i, j, k, 0, 0.0) #roiData.SetScalarComponentFromDouble(0, i, j, k, 0.0) """ for i in range(extent[0], extent[1]): for j in range(extent[2], extent[3]): #for k in range(extent[4], extent[5]): #k = 0 roiData.SetScalarComponentFromDouble(i, j, k, 0, 0.0) #roiData.SetScalarComponentFromDouble(0, i, j, k, 0.0) """ print(extent) table = vtkLookupTable() table.SetNumberOfTableValues(2) table.SetRange(0.0, 1.0) table.SetTableValue(0, 0.0, 0.0, 0.0, 0.0) table.SetTableValue(1, 0.0, 1.0, 0.0, 1.0) table.Build() mapToColor = vtkImageMapToColors() mapToColor.SetLookupTable(table) mapToColor.PassAlphaToOutputOn() mapToColor.SetInputData(roiData) #actor.GetMapper().SetInputConnection(mapToColor.GetOutputPort()) roiImage.GetMapper().SetInputConnection(mapToColor.GetOutputPort()) imageViewer.SetInputData(image) interactorStyle = vtkInteractorStyleImage() interactor = vtkRenderWindowInteractor() imageViewer.SetupInteractor(interactor) interactor.SetInteractorStyle(interactorStyle) # add slice status message and usage hint message to the renderer imageViewer.GetRenderer().AddActor2D(coordTextActor) imageViewer.GetRenderer().AddActor2D(sliceTextActor) imageViewer.GetRenderer().AddActor2D(usageTextActor) imageViewer.GetRenderer().AddActor2D(worldCoordTextActor) imageViewer.GetRenderer().AddActor(roiImage) #imageViewer.GetRenderer().AddViewProp(stack) # initialize rendering and interaction #imageViewer.SetSlice(35) imageViewer.GetRenderWindow().SetSize(1000, 1000) imageViewer.GetRenderer().SetBackground(0.2, 0.3, 0.4) imageViewer.GetWindowLevel().SetWindow(1000) imageViewer.GetWindowLevel().SetLevel(-1000) imageViewer.Render() yd = (yMax - yMin + 1) * ySpacing xd = (xMax - xMin + 1) * xSpacing d = camera.GetDistance() camera.SetParallelScale(0.5 * xd) camera.SetFocalPoint(center[0], center[1], 0) camera.SetPosition(center[0], center[1], +d) actions = {} actions["Dolly"] = -1 actions["Cursor"] = 0 def middlePressCallback(obj, event): # if middle + ctrl pressed, zoom in/out # otherwise slice through image (handled by mouseMoveCallback) if (interactor.GetControlKey()): actions["Dolly"] = 0 interactorStyle.OnRightButtonDown() else: actions["Dolly"] = 1 def middleReleaseCallback(obj, event): if (actions["Dolly"] == 0): interactorStyle.OnRightButtonUp() elif (actions["Dolly"] == 1): actions["Dolly"] = 0 def mouseMoveCallback(obj, event): # if the middle button is pressed + mouse is moved, slice through image # otherwise, update world/pixel coords as mouse is moved if (actions["Dolly"] == 1): (lastX, lastY) = interactor.GetLastEventPosition() (curX, curY) = interactor.GetEventPosition() deltaY = curY - lastY if (deltaY > 0): imageViewer.IncrementSlice(1) elif (deltaY < 0): imageViewer.IncrementSlice(-1) msg = "Slice {} out of {}".format(imageViewer.GetSlice() + 1, \ imageViewer.GetSliceMax() + 1) sliceTextMapper.SetInput(msg) imageViewer.Render() else: (mouseX, mouseY) = interactor.GetEventPosition() bounds = actor.GetMapper().GetInput().GetBounds() testCoord = vtkCoordinate() testCoord.SetCoordinateSystemToDisplay() testCoord.SetValue(mouseX, mouseY, 0) (posX, posY, posZ) = testCoord.GetComputedWorldValue(imageViewer.GetRenderer()) inBounds = True if posX < bounds[0] or posX > bounds[1] or posY < bounds[ 2] or posY > bounds[3]: inBounds = False if inBounds: wMousePos = "World Coordinates: (" + "{:.2f}".format( posX) + ", " + "{:.2f}".format( posY) + ", " + "{:.2f}".format(posZ) + ")" pMousePos = "Pixel Coordinates: (" + "{:.2f}".format( mouseX) + ", " + "{:.2f}".format(mouseY) + ")" worldCoordTextMapper.SetInput(wMousePos) coordTextMapper.SetInput(pMousePos) imageViewer.Render() interactorStyle.OnMouseMove() def scrollForwardCallback(obj, event): # slice through image on scroll, update slice text imageViewer.IncrementSlice(1) msg = "Slice {} out of {}".format(imageViewer.GetSlice() + 1, \ imageViewer.GetSliceMax() + 1) sliceTextMapper.SetInput(msg) imageViewer.Render() def scrollBackwardCallback(obj, event): imageViewer.IncrementSlice(-1) msg = "Slice {} out of {}".format(imageViewer.GetSlice() + 1, \ imageViewer.GetSliceMax() + 1) sliceTextMapper.SetInput(msg) imageViewer.Render() def windowModifiedCallback(obj, event): # track render window width so coordinate text aligns itself # to the right side of the screen width = imageViewer.GetRenderWindow().GetSize()[0] coordTextActor.SetPosition(width - 550, 10) worldCoordTextActor.SetPosition(width - 550, 30) imageViewer.Render() def keyPressCallback(obj, event): # toggle cursor on/off when t key is pressed key = interactor.GetKeySym() if (key == "t"): if (actions["Cursor"] == 0): imageViewer.GetRenderWindow().HideCursor() actions["Cursor"] = 1 elif (actions["Cursor"] == 1): imageViewer.GetRenderWindow().ShowCursor() actions["Cursor"] = 0 interactorStyle.AddObserver("MiddleButtonPressEvent", middlePressCallback) interactorStyle.AddObserver("MiddleButtonReleaseEvent", middleReleaseCallback) interactorStyle.AddObserver("MouseMoveEvent", mouseMoveCallback) interactorStyle.AddObserver("MouseWheelForwardEvent", scrollForwardCallback) interactorStyle.AddObserver("MouseWheelBackwardEvent", scrollBackwardCallback) interactorStyle.AddObserver("KeyPressEvent", keyPressCallback) imageViewer.GetRenderWindow().AddObserver("ModifiedEvent", windowModifiedCallback) interactor.Start()
def __init__(self, parent=None, dcm_dir='', view_plane='Transverse'): """ 建立DICOM VTK 畫布 :param dcm_dir: 影像路徑 :param view_plane: 切面:預設'Transverse',可選'Coronal','Sagittal' """ QtWidgets.QMainWindow.__init__(self, parent) self.frame = QtWidgets.QFrame() self.vl = QtWidgets.QVBoxLayout() self.vtkWidget = QVTKRenderWindowInteractor(self) self.vl.addWidget(self.vtkWidget) if dcm_dir != '': self.dcm_series_path = Path(dcm_dir).expanduser() # set up VTK dicom reader self.dcmReader = vtkDICOMImageReader() self.dcmReader.SetDataByteOrderToLittleEndian() self.dcmReader.SetDirectoryName(str(self.dcm_series_path)) self.dcmRescaleSlope = self.dcmReader.GetRescaleSlope() self.dcmRescaleOffset = self.dcmReader.GetRescaleOffset() self.dcmReader.Update() # '------default with WW & WL-----' self.ww = 3500 # WW self.wl = 600 # WL # '----------viewer---------' self.dcmViewer = vtk.vtkImageViewer2() self.dcmViewer.SetInputConnection(self.dcmReader.GetOutputPort()) self.dcmViewer.SetColorLevel(500) self.dcmViewer.SetColorWindow(3500) self.dcmViewer.SetSize(600, 600) self.dcmViewer.UpdateDisplayExtent() # #!下面那一行確保不會多渲染出一個視窗物件! ## self.dcmViewer.SetRenderWindow( self.vtkWidget.GetRenderWindow()) # #!這一行確保不會多渲染出一個視窗物件! # # # #!上面那一行確保不會多渲染出一個視窗物件! ## # 下面三個方法可渲染不同人體不同的切面 self.viewPlane = view_plane if self.viewPlane == 'Coronal': self.dcmViewer.SetSliceOrientationToXZ() # 冠狀面 (Coronal plane) elif self.viewPlane == 'Sagittal': self.dcmViewer.SetSliceOrientationToYZ() # 縱切面 (Sagittal plane) else: self.dcmViewer.SetSliceOrientationToXY( ) # Default: 橫狀面 (Transverse plane) # '----------TextOverLay---------' # slice status message self.sliceTextProp = vtk.vtkTextProperty() self.sliceTextProp.SetFontFamilyToCourier() self.sliceTextProp.SetFontSize(60) self.sliceTextProp.SetVerticalJustificationToBottom() self.sliceTextProp.SetJustificationToLeft() # '---------set up Text Overlay mapper----------' self.sliceTextMapper = vtk.vtkTextMapper() self.current_slice = self.dcmViewer.GetSlice() print('cur_slice = ', self.current_slice, ' viewer.GetSliceMax() = ', self.dcmViewer.GetSliceMax()) msg = ( ' %d / %d ' % (self.dcmViewer.GetSlice() + 1, self.dcmViewer.GetSliceMax() + 1)) self.sliceTextMapper.SetInput(msg) # '---------set up Text Overlay Actor----------' self.sliceTextActor = vtk.vtkActor2D() self.sliceTextActor.SetMapper(self.sliceTextMapper) self.sliceTextActor.SetPosition(15, 10) # ########--Get RENDERER--############ self.renderer = self.dcmViewer.GetRenderer() self.renderer.AddActor2D(self.sliceTextActor) # ########--Set Up RENDER Window--############ self.renderWindow = self.vtkWidget.GetRenderWindow() self.renderWindow.AddRenderer(self.renderer) self.vtkWidget.GetRenderWindow().AddRenderer(self.renderer) # '--------- Interactor ----------' self.inter = self.renderWindow.GetInteractor() # ----!Stay in 2D View!----- self.inter.SetInteractorStyle( vtkInteractionStyle.vtkInteractorStyleImage()) # '----------add keyboard observer---------' self.vtkWidget.AddObserver(vtk.vtkCommand.KeyPressEvent, self.keyboard_callback_func) self.cam = self.renderer.GetActiveCamera() if self.viewPlane == 'Coronal': # self.cam.SetFocalPoint(0, 0, 0) # 设焦点 # self.cam.SetPosition(0, 0, -1) # Camera in Z so it display XY planes. # 设观察对象位 self.cam.SetViewUp( 0, 0, -1 ) # Up direction is the X not the y. #(0,0,-1) for Coronal plane # self.cam.ComputeViewPlaneNormal() # 自动 self.renderer.ResetCamera() self.frame.setLayout(self.vl) self.setCentralWidget(self.frame) self.show() self.inter.Initialize()
from vtkmodules.vtkCommonCore import vtkLookupTable from vtkmodules.vtkImagingColor import vtkImageMapToWindowLevelColors from vtkmodules.vtkImagingCore import vtkImageMapToColors, vtkImageReslice from vtkmodules.vtkRenderingCore import vtkImageActor, vtkRenderer, \ vtkRenderWindow, vtkRenderWindowInteractor, vtkCoordinate, vtkTextProperty, vtkTextMapper, vtkActor2D from vtkmodules.vtkInteractionStyle import vtkInteractorStyleImage from vtkmodules.vtkCommonDataModel import vtkImageData from math import floor, sqrt from timeit import default_timer as timer Z_SLICE = None VTK_DATA_ROOT = vtkGetDataRoot() folder = "/Users/nandana/Downloads/image_ex" # Start by loading some data. reader = vtkDICOMImageReader() reader.SetDirectoryName(folder) reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter") reader.SetDataExtent(0, 63, 0, 63, 1, 93) reader.SetDataSpacing(3.2, 3.2, 1.5) reader.SetDataOrigin(0.0, 0.0, 0.0) reader.SetDataScalarTypeToUnsignedShort() reader.UpdateWholeExtent() # Calculate the center of the volume reader.Update() (xMin, xMax, yMin, yMax, zMin, zMax) = reader.GetExecutive().GetWholeExtent(reader.GetOutputInformation(0)) (xSpacing, ySpacing, zSpacing) = reader.GetOutput().GetSpacing() (x0, y0, z0) = reader.GetOutput().GetOrigin()
def __init__(self): VTK_DATA_ROOT = vtkGetDataRoot() self.reader = vtkDICOMImageReader() self.folder = "/Users/nandana/Downloads/image_ex" self.reader.SetDirectoryName(self.folder) self.reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter") self.reader.SetDataExtent(0, 63, 0, 63, 1, 93) self.reader.SetDataSpacing(3.2, 3.2, 1.5) self.reader.SetDataOrigin(0.0, 0.0, 0.0) self.reader.SetDataScalarTypeToUnsignedShort() self.reader.UpdateWholeExtent() self.reader.Update() self.center = self.calculate_center() self.axial = vtkMatrix4x4() self.axial.DeepCopy((1, 0, 0, self.center[0], 0, 1, 0, self.center[1], 0, 0, 1, self.center[2], 0, 0, 0, 1)) self.coronal = vtkMatrix4x4() self.coronal.DeepCopy( (1, 0, 0, self.center[0], 0, 0, 1, self.center[1], 0, -1, 0, self.center[2], 0, 0, 0, 1)) self.sagittal = vtkMatrix4x4() self.sagittal.DeepCopy( (0, 0, -1, self.center[0], 1, 0, 0, self.center[1], 0, -1, 0, self.center[2], 0, 0, 0, 1)) self.oblique = vtkMatrix4x4() self.oblique.DeepCopy( (1, 0, 0, self.center[0], 0, 0.866025, -0.5, self.center[1], 0, 0.5, 0.866025, self.center[2], 0, 0, 0, 1)) self.img_reslice = vtkImageReslice() self.roi_reslice = vtkImageReslice() self.img_reslice.SetInputConnection(0, self.reader.GetOutputPort()) self.img_reslice.SetOutputDimensionality(2) self.img_reslice.SetInterpolationModeToLinear() self.roi_reslice.SetInputConnection(0, self.reader.GetOutputPort()) self.roi_reslice.SetOutputDimensionality(2) self.roi_reslice.SetInterpolationModeToLinear() self.set_orientation(self.axial) self.img_table = vtkLookupTable() self.roi_table = vtkLookupTable() self.window_level = vtkImageMapToWindowLevelColors() self.img_color = vtkImageMapToColors() self.roi_color = vtkImageMapToColors() self.img = self.map_img() self.roi = self.map_roi() self.px_coord_text_prop = vtkTextProperty() self.px_coord_text_mapper = vtkTextMapper() self.px_coord_text_actor = vtkActor2D() self.world_coord_text_prop = vtkTextProperty() self.world_coord_text_mapper = vtkTextMapper() self.world_coord_text_actor = vtkActor2D() self.usage_text_prop = vtkTextProperty() self.usage_text_mapper = vtkTextMapper() self.usage_text_actor = vtkActor2D() self.renderer = vtkRenderer() self.add_text() self.renderer.AddActor(self.img) self.renderer.AddActor(self.roi) self.renderer.SetBackground(0.2, 0.3, 0.4) self.window = vtkRenderWindow() self.window.AddRenderer(self.renderer) self.window.SetSize(1000, 1000) self.interactor_style = vtkInteractorStyleImage() self.interactor_style.SetInteractionModeToImageSlicing() self.interactor = vtkRenderWindowInteractor() self.interactor.SetInteractorStyle(self.interactor_style) self.window.SetInteractor(self.interactor) self.window_level.SetWindow(1000) self.window_level.SetLevel(200) self.window_level.Update() self.window.Render() self.interactor_style.AddObserver("MouseWheelForwardEvent", self.scroll_forward_callback) self.interactor_style.AddObserver("MouseWheelBackwardEvent", self.scroll_backward_callback) self.interactor_style.AddObserver("MouseMoveEvent", self.mouse_move_callback) self.interactor_style.AddObserver("KeyPressEvent", self.key_press_callback) self.interactor_style.AddObserver("LeftButtonPressEvent", self.left_press_callback) self.window.AddObserver("ModifiedEvent", self.window_mod_callback) self.actions = { "Slicing": 0, "Cursor": 0, "CurrentPos": -1, "LastPos": -1, "DoubleClick": 0 }
def load_image(self, file): # (1) Read File # (2) Get min, max, window-level # (3) Update views # (1) if self.demo_mode: print(file) print("......") self.reader = vtkDICOMImageReader() VTK_DATA_ROOT = vtkGetDataRoot() self.reader.SetDirectoryName(file) self.reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter") # UNIX FRIENDLY # self.reader.SetFilePrefix(VTK_DATA_ROOT + r"\Data\headsq\quarter") # WINDOWS FRIENDLY ### Extract # TODO: double check that the image attributes are correct when using vtkDICOMimageReader # self.reader.SetDataExtent(0, 63, 0, 63, 1, 93) # self.reader.SetDataSpacing(3.2, 3.2, 1.5) # self.reader.SetDataOrigin(0.0, 0.0, 0.0) self.reader.SetDataScalarTypeToUnsignedShort() # self.reader.UpdateWholeExtent() self.reader.Update() imageData = self.reader.GetOutput() self.image = imageData image_info = dict(image_data=imageData, spacing=imageData.GetSpacing(), origin=imageData.GetOrigin()) minv, maxv = (-1024, 1024) #close enough estimate else: if qia_loaded: print(file) self.image = qimage.read(file) ### QIA version image_info = dict(image_data=self.image, spacing=self.image.get_spacing(), origin=self.image.get_origin()) dims = image_info["image_data"].get_size() else: #assume numpy array print("Not implemented yet") # load numpy array ### numpy version >>> for future compatibility # image_npy = np.array(self.image.get_array()) # image_npy = np.moveaxis(image_npy, 0, 2) #because I saved the numpy files (z, x, y) -_- # image_npy = np.rot90(image_npy, 3) # image_npy = np.flip(image_npy, 1) # image_info = dict(image_data=image_npy, spacing=self.image.get_spacing(), origin=self.image.get_origin()) # dims = image_info["image_data"].shape imageData = vtk.vtkImageData() print("dims", dims) #instantiating imageData obj imageData.SetDimensions(dims[0], dims[1], dims[2]) if vtk.VTK_MAJOR_VERSION <= 5: imageData.SetNumberOfScalarComponents(1) imageData.SetScalarTypeToDouble() else: imageData.AllocateScalars(vtk.VTK_DOUBLE, 1) # (2) Update the vtk obj image information imageData.SetSpacing(image_info["spacing"][0], image_info["spacing"][1], image_info["spacing"][2]) ### QIA Version imageData.SetExtent(0, dims[0]-1, 0, dims[1]-1, 1, dims[2]) # with QIA it goes from [ 1 to z_max ] instead of [0 to z_max - 1] imageData.SetOrigin(image_info["origin"][0], image_info["origin"][1], image_info["origin"][2]) #unsure if it's this one # imageData.SetOrigin(image_info["origin"][0], image_info["origin"][1], 0) #unsure if it's this one for z in range(dims[2]): z+=1 for y in range(dims[1]): for x in range(dims[0]): # print(x,y, z) # double check if x,y,z is the appropriate order after you get the numpy array # imageData.SetScalarComponentFromDouble(x, y, z, 0, image_info["image_data"][x,y,z] ) # numpy imageData.SetScalarComponentFromDouble(x, y, z, 0, image_info["image_data"].get_value((x,y,z)) ) # QIA minv, maxv = self.image.get_min_max() # (2) self.window_level.SetWindow(maxv-minv) self.window_level.SetLevel((maxv+minv)/2) self.window_level.Update() # (3) # TODO: Make blockSignals useful (to avoid reloading things if we click too often, etc.) for v in self.views: v.blockSignals(True) self.viewer_center = self.views[0].calculate_center(extent=imageData.GetExtent(), spacing=image_info["spacing"], origin=image_info["origin"]) print("viewer center", self.viewer_center) for v in self.views: v.update_image(imageData) if not v.viewer_initialized: # orientation = "axial" orientation = "sagittal" # before this, orientation has of the viewer has not been defined yet. # aka it doesn't set the viewer orientation until the first image has loaded v.init_view(orientation=orientation, center=self.viewer_center) else: # if viewer has been initialized already, then just update the center v.set_position(self.viewer_center) v.connect_window_level(self.window_level) #updating window level # v.resetCamera() ### TODO: Implement and activate for v in self.views: v.blockSignals(False) self.render()