首页 > 编程语言 >python vtk读取dicom序列+鼠标键盘交互

python vtk读取dicom序列+鼠标键盘交互

时间:2023-10-29 19:02:23浏览次数:45  
标签:__ slice python dicom vtk event viewer image self

目标: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() 方法将自动根据渲染器中呈现的的范围和位置调整相机,使整个图像在渲染窗口中完全可见。

image

第二步:自定义交互器

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

相关文章

  • 解决Python报错ImportError: No module named ‘xxxx‘问题
    BASE_DIR=os.path.dirname(os.getcwd())#用来从jupyter默认地址中脱离出来importsyssys.path.append(BASE_DIR)sys.path.append('E:\CV_Paper_fuxian\lesson\B_VGG')#把文件所在的相对路径要添加进去。才不会报错然后运行,就完美解决了。......
  • EDA工具使用+GIT操作+python编程+C语言编程+Riscv相关+TCL操作
    EDA工具使用Verdi覆盖率转网页urg-full64-dirsimv.vdbVerdi加载sessionverdi-ssrsessionFileVcs分部编译额外选项-partcomp:自动分块编译。-fastpartcomp:使用多核计算系统并行部分编译。-pcmakeprof:查看每部分编译占用的时间,方便对时间更久的进行拆分。-partc......
  • python eval,类似ast.literal_eval, 据说是速度快于eval,没有验证过
    expr_str="[1,2,3]"my_list=eval(expr_str)print(repr(my_list),type(my_list))#[1,2,3]print(repr(expr_str),type(expr_str))#'[1,2,3]'importast#用importast来代替以下这种操作eval可以提高速度my_list=ast.literal_eval(expr_str)print(my_list)......
  • Python使用pymysql和xlrd2将Excel数据导入MySQL数据库
    在数据处理和管理中,有时候需要将Excel文件中的数据导入到MySQL数据库中进行进一步的分析和操作。本文将介绍如何使用Python编程语言实现这个过程。导入所需库importxlrd2#导入xlrd2库,用于读取Excel文件importpymysql#导入pymysql库,用于连接和操作MySQL数据库fromdat......
  • python 安装包时 ERROR: Failed building wheel for webrtcvad
    报错信息:error:subprocess-exited-with-error×Buildingwheelforwebrtcvad(pyproject.toml)didnotrunsuccessfully.│exitcode:1╰─>[9linesofoutput]runningbdist_wheelrunningbuildrunningbuild_pycreatingbuildcre......
  • Python自动处理pptx:新建、另存、添加幻灯片、添加标题、插入文本图片图形、提取文本
    Python-pptx库是一个用于创建、更新和读取MicrosoftPowerPoint.pptx文件的Python库。它允许我们使用Python脚本自动化PowerPoint文件的创建、更新和读取操作,是一个非常方便自动化处理PPTX的工具。安装pipinstallpython-pptx创建frompptximportPresentationppt=Presentat......
  • Python中文分词、词频统计并制作词云图
    中文分词、词频统计并制作词云图是统计数据常用的功能,这里用到了三个模块快速实现这个功能。中文分词、词频统计importjiebafromcollectionsimportCounter#1.读取文本内容并进行分词withopen('demo.txt',mode='r',encoding='gbk')asf:report=f.read()words......
  • Python数据结构——栈
    栈(Stack)是一种基本的数据结构,它遵循“后进先出”(Last-In-First-Out,LIFO)的原则,即最后放入栈的元素最先出栈。栈常用于管理函数调用、表达式求值、括号匹配等问题。本文将详细介绍Python中栈数据结构的使用,并提供示例代码来说明。什么是栈?栈是一种线性数据结构,它由一组元素组成,支持两......
  • 一周学会python4变量
    4变量为了正常运行,Python程序需要变量和运算符等基本组件。包括变量和运算符在内的这些元素对于程序员新手来说很容易理解和应用,使他们能够开发出创建复杂软件所需的算法。本章涉及到了第8章函数的内容,如不能理解,可学习函数后再温习。4.1变量简介变量是在Python程序中存储和......
  • python面向对象-学习笔记(三、类方法、实例方法、静态方法)
    方法相关方法的概念描述一个目标的行为动作和函数相似封装了一系列行为动作。比如一个人怎么吃,怎么喝,怎么玩...都可以被调用最主要区别:调用方式方法的划分实例方法:默认第一个参数是一个实例类方法:默认第一个参数是类静态方法:没有默认参数注意划分的依据:方法的第一......