目标:vtk + pyqt实现四视图。
之前不了解vtk,也不了解鼠标键盘交互。网上搜索了资料,发现博客里大都是C++的例子。
困扰几天,今天终于做出来一部分,分享一下。
参考官方教程:
第一步:python vtk 读取 dicom 文件
#!/usr/bin/env python3
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkIOImage import vtkDICOMImageReader
from vtkmodules.vtkInteractionImage import vtkImageViewer2
from vtkmodules.vtkRenderingCore import vtkRenderWindowInteractor
def main():
# 创建一个vtkNamedColors对象,用于为图像查看器窗口设置背景颜色
colors = vtkNamedColors()
# Read the DICOM file
input_filename = "digest_article/brain_020.dcm"
reader = vtkDICOMImageReader() # 创建一个vtkDICOMImageReader对象用于读取DICOM文件
reader.SetFileName(input_filename) # 将输入文件名指定给vtkDICOMImageReader实例
reader.Update() # 读取DICOM文件
# Visualize
image_viewer = vtkImageViewer2() # 创建一个vtkImageViewer2对象用于可视化
image_viewer.SetInputConnection(reader.GetOutputPort())
render_window_interactor = vtkRenderWindowInteractor() # 创建一个vtkRenderWindowInteractor对象图像查看器进行交互
image_viewer.SetupInteractor(render_window_interactor) # 设置vtkImageViewer2和vtkRenderWindowInteractor之间的交互
image_viewer.Render()
image_viewer.GetRenderer().SetBackground(colors.GetColor3d("SlateGray"))
image_viewer.GetRenderWindow().SetWindowName("ReadDICOM")
image_viewer.GetRenderer().ResetCamera()
image_viewer.Render()
render_window_interactor.Start()
if __name__ == "__main__":
main()
-
image_viewer.Render()
当对图像查看器进行了一些交互操作或更改了其属性(如窗口大小、背景颜色等),可以调用此方法立即执行并显示出来。 -
image_viewer.GetRenderer().ResetCamera()
用于重新设置图像查看器的渲染器(renderer)的相机(camera)。相机在渲染器中定义了图像的视角和位置。调用ResetCamera()
方法将自动根据渲染器中呈现的的范围和位置调整相机,使整个图像在渲染窗口中完全可见。
第二步:自定义交互器
VTK: vtkInteractorStyleImage Class Reference,不太懂具体细节
#!/usr/bin/env python3
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkIOImage import vtkDICOMImageReader
from vtkmodules.vtkInteractionImage import vtkImageViewer2
from vtkmodules.vtkRenderingCore import vtkRenderWindowInteractor
# 添加
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleImage
import vtk
# -------------------- 添加 start --------------------
class MyVtkInteractorStyleImage(vtkInteractorStyleImage):
def __init__(self, parent=None):
super().__init__()
# 为vtk交互事件添加一个观察者(Observer),触发"左键点击"事件,调用 self.LeftButtonPressEvent
self.AddObserver(vtk.vtkCommand.LeftButtonPressEvent, self.LeftButtonPressEvent)
def LeftButtonPressEvent(self, obj, event):
print("LeftButtonPressEvent")
# -------------------- 添加 end --------------------
def main():
colors = vtkNamedColors()
# Read the DICOM file
input_filename = "digest_article/brain_020.dcm"
reader = vtkDICOMImageReader()
reader.SetFileName(input_filename)
reader.Update()
# Visualize
image_viewer = vtkImageViewer2()
image_viewer.SetInputConnection(reader.GetOutputPort())
render_window_interactor = vtkRenderWindowInteractor()
image_viewer.SetupInteractor(render_window_interactor)
# -------------------- 添加 start --------------------
# 创建一个MyVtkInteractorStyleImage()对象来自定义vtk的交互方式
my_interactor_style = MyVtkInteractorStyleImage()
# 将render_window_interactor的交互方式(Interactor Style)设置为MyVtkInteractorStyleImage()
render_window_interactor.SetInteractorStyle(my_interactor_style)
render_window_interactor.Render()
# -------------------- 添加 end --------------------
image_viewer.Render()
image_viewer.GetRenderer().SetBackground(colors.GetColor3d("SlateGray"))
image_viewer.GetRenderWindow().SetWindowName("ReadDICOM")
image_viewer.GetRenderer().ResetCamera()
image_viewer.Render()
render_window_interactor.Start()
if __name__ == "__main__":
main()
左键点击图片,cmd输出"LeftButtonPressEvent"。
第三步:自定义切片交互器
事件1:键盘上下键
事件2:鼠标滚轮前滚
事件3:鼠标滚轮后滚
交互中需要设置Slice值, 可以通过vtkImageViewer2类实现。但在MyVtkInteractorStyleImage类中需要使用main函数中的image_viewer。
方法是在MyVtkInteractorStyleImage类中定义一个 set_image_viewer 函数,并在main函数中添加一句 ”my_interactor_style.set_image_viewer(image_viewer)“。
class MyVtkInteractorStyleImage(vtkInteractorStyleImage):
def __init__(self, parent=None):
super().__init__()
self.AddObserver(vtk.vtkCommand.KeyPressEvent, self.key_press_event)
self.AddObserver(vtk.vtkCommand.MouseWheelForwardEvent, self.mouse_wheel_forward_event)
self.AddObserver(vtk.vtkCommand.MouseWheelBackwardEvent, self.mouse_wheel_backward_event)
self.image_viewer = None
self.status_mapper = None
self.slice = 0
self.min_slice = 0
self.max_slice = 0
def set_image_viewer(self, image_viewer):
self.image_viewer = image_viewer
self.min_slice = image_viewer.GetSliceMin()
self.max_slice = image_viewer.GetSliceMax()
self.slice = self.min_slice
print(f'Slicer: Min = {self.min_slice}, Max= {self.max_slice}')
def move_slice_forward(self):
if self.slice < self.max_slice:
self.slice += 1
print(f'MoveSliceForward::Slice = {self.slice}')
self.image_viewer.SetSlice(self.slice)
self.image_viewer.Render()
def move_slice_backward(self):
if self.slice > self.min_slice:
self.slice -= 1
print(f'MoveSliceBackward::Slice = {self.slice}')
self.image_viewer.SetSlice(self.slice)
self.image_viewer.Render()
def key_press_event(self, obj, event):
# print("key_press_event")
key = self.GetInteractor().GetKeySym()
if key == 'Up':
self.move_slice_forward()
elif key == 'Down':
self.move_slice_backward()
def mouse_wheel_forward_event(self, obj, event):
# print("mouse_wheel_forward_event")
self.move_slice_forward()
def mouse_wheel_backward_event(self, obj, event):
# print("mouse_wheel_backward_event")
self.move_slice_backward()
完整代码:
#!/usr/bin/env python3
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingContextOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkIOImage import vtkDICOMImageReader
from vtkmodules.vtkInteractionImage import vtkImageViewer2
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleImage
from vtkmodules.vtkRenderingCore import (
vtkRenderWindowInteractor,
)
import vtk
# -------------------- 修改 start --------------------
class MyVtkInteractorStyleImage(vtkInteractorStyleImage):
def __init__(self, parent=None):
super().__init__()
self.AddObserver(vtk.vtkCommand.KeyPressEvent, self.key_press_event)
self.AddObserver(vtk.vtkCommand.MouseWheelForwardEvent, self.mouse_wheel_forward_event)
self.AddObserver(vtk.vtkCommand.MouseWheelBackwardEvent, self.mouse_wheel_backward_event)
self.image_viewer = None
self.status_mapper = None
self.slice = 0
self.min_slice = 0
self.max_slice = 0
def set_image_viewer(self, image_viewer):
self.image_viewer = image_viewer
self.min_slice = image_viewer.GetSliceMin()
self.max_slice = image_viewer.GetSliceMax()
self.slice = self.min_slice
print(f'Slicer: Min = {self.min_slice}, Max= {self.max_slice}')
def move_slice_forward(self):
if self.slice < self.max_slice:
self.slice += 1
print(f'MoveSliceForward::Slice = {self.slice}')
self.image_viewer.SetSlice(self.slice)
self.image_viewer.Render()
def move_slice_backward(self):
if self.slice > self.min_slice:
self.slice -= 1
print(f'MoveSliceBackward::Slice = {self.slice}')
self.image_viewer.SetSlice(self.slice)
self.image_viewer.Render()
def key_press_event(self, obj, event):
# print("key_press_event")
key = self.GetInteractor().GetKeySym()
if key == 'Up':
self.move_slice_forward()
elif key == 'Down':
self.move_slice_backward()
def mouse_wheel_forward_event(self, obj, event):
# print("mouse_wheel_forward_event")
self.move_slice_forward()
def mouse_wheel_backward_event(self, obj, event):
# print("mouse_wheel_backward_event")
self.move_slice_backward()
# -------------------- 修改 end --------------------
def main():
colors = vtkNamedColors()
# -------------------- 修改 start --------------------
# 读取dicom序列
input_folder = "digest_article"
reader = vtkDICOMImageReader()
reader.SetDirectoryName(input_folder)
reader.Update()
# -------------------- 修改 end --------------------
# Visualilze
image_viewer = vtkImageViewer2()
image_viewer.SetInputConnection(reader.GetOutputPort())
render_window_interactor = vtkRenderWindowInteractor()
image_viewer.SetupInteractor(render_window_interactor)
my_interactor_style = MyVtkInteractorStyleImage()
# -------------------- 添加 start --------------------
my_interactor_style.set_image_viewer(image_viewer)
# -------------------- 添加 end --------------------
render_window_interactor.SetInteractorStyle(my_interactor_style)
render_window_interactor.Render()
image_viewer.Render()
image_viewer.GetRenderer().ResetCamera()
image_viewer.GetRenderer().SetBackground(colors.GetColor3d('SlateGray'))
image_viewer.GetRenderWindow().SetSize(800, 800)
image_viewer.GetRenderWindow().SetWindowName('ReadDICOMSeries')
image_viewer.Render()
render_window_interactor.Start()
if __name__ == '__main__':
main()
标签:__,slice,python,dicom,vtk,event,viewer,image,self
From: https://www.cnblogs.com/yaksa777/p/17796201.html