当前位置: 首页 > news >正文

VTK使用交互器来从三维体数据中提取二维切片

VTK中鼠标消息是在交互类型对象(interactorstyle)中响应,因此通过为交互类型对象(interactorstyle)添加观察者(observer)来监听相应的消息,当消息触发时,由命令模式执行相应的回调函数

vtkImageInteractionCallback继承自vtkCommand类,并覆盖父类函数Execute()。
该类提供了两个接口:SetImageReslice和SetInteractor。
SetImageReslice用以设置vtkImageSlice对象,vtkImageSlice根据设置的变换矩阵提取三维图像切片。SetInteractor用以设置vtkRenderWindowInteractor,vtkRenderWindowInteractor类对象负责每次提取切片后刷新视图

class vtkImageInteractionCallback : public vtkCommand
{
public:static vtkImageInteractionCallback *New() //回调函数初始化函数{return new vtkImageInteractionCallback;}vtkImageInteractionCallback(){this->Slicing = 0;//切片提取标志位,为1时提取切片。用来检验鼠标左键是否已经按下this->ImageReslice = 0;//vtkImageSlice对象的变换矩阵,用来确定切面在三维图像中的位置this->Interactor = 0;}void SetImageReslice(vtkImageReslice *reslice){this->ImageReslice = reslice;}vtkImageReslice *GetImageReslice(){return this->ImageReslice;}void SetInteractor(vtkRenderWindowInteractor *interactor){this->Interactor = interactor;}vtkRenderWindowInteractor *GetInteractor(){return  this->Interactor;}virtual void Execute(vtkObject * ,unsigned long event,void *){//具体内容放下面}
private:int Slicing;vtkImageReslice *ImageReslice;vtkRenderWindowInteractor *Interactor;
};

   需要设置四个参数,窗位(ColorLevel)、窗宽(ColorWindow)、切片(Slice)和切片方向(Orientation)。按下鼠标左键拖动鼠标,可以调节图像的窗宽窗位,从而显示不同灰度范围内容;按下鼠标右键拖动鼠标可以放缩图像。当然这些交互操作可以由用户根据需要自己定义vtkInteractorStyle子类,并响应相应的操作。

( 窗宽是图像显示的灰度范围。一般显示器的灰度范围为256级,医学图像的灰度范围远远大于这个范围,所以显示器不足以显示所有的灰度级,需要使用窗宽来定义想要显示的灰度范围;
  一般情况下,可以将灰度值高于窗宽范围的最大值时,将像素值显示为白色值(255);将灰度值低于窗宽范围的最小值时,将像素值显示为黑色值(0);增大窗宽范围,可以显示更多不同灰度组织结构,但会减低组织之间的对比度;减小窗宽范围,可以减少所显示不同灰度组织结构,也就增大了组织结构之间的对比度;
  窗位是窗宽的中心位置;窗宽只是确定了像素上的可视化的范围,是一个具体值,单独依靠窗宽不能确定这个范围的上限是多少和下限是多少,需要配合使用窗位来确定;比如上一代码中:窗宽为2000,只能说明窗宽的范围是2000,不能说明是从0到2000,还是-1000到1000,设置窗位为500时,窗宽2000,就能表示可视灰度范围为-500到1500;)

  而显示三维图像时,还需要确定当前显示切片和方向。vtkImageViewer2提供了SetSlice()函数设置切片号,SetSliceOrientationToXY()则将切片的方向设置为垂直XY平面方向。此外还可以设置为垂直YZ或者XZ平面方向,其对应函数分别为SetSliceOrientationToYZ()和SetSliceOrientationToXZ()。默认情况下切片方向为垂直于XY平面即沿着Z轴方向,根据设置的切片号获取Z轴方向的具体切片进行显示。

下面重点看Execute函数,该函数提供了具体的切片提取功能。在该函数里面,主要监听了三个消息:
vtkCommand::LeftButtonPressEvent,
vtkCommand::LeftButtonReleaseEvent,
vtkCommand::MouseMoveEvent,
前两个消息分别是鼠标左键的按下和弹起消息。当鼠标左键按下时,就设置切片提取标志为1,而当弹起时,将标志置为0。这样在鼠标移动时,只有在确定切片提取标志为1时,执行切片提取功能。
vtkCommand::MouseMoveEvent即为鼠标移动消息。当检测到该消息时,首先检查切片提取标志,当为1时提取切片。提取切片时,需要为vtkImageSlice对象设置变换矩阵。这里在函数开始时,首先获取了鼠标滑动的前后两次点的位置lastPos和currPos。然后根据两点的Y坐标差deltaY,计算新的中心点center并变换至vtkImageSlice当前变换矩阵中,得到变换中心点,将其设置到原来的变换矩阵matrix中,并设置到vtkImageSlice中,最后执行interactor->Render()即可不断的根据鼠标移动刷新图像。

virtual void Execute(vtkObject * ,unsigned long event,void *)
{vtkRenderWindowInteractor *interactor = GetInteractor();int lastPos[2];interactor->GetLastEventPosition(lastPos);int currPos[2];interactor->GetEventPosition(currPos);if (event == vtkCommand::LeftButtonPressEvent)//如果当前事件是鼠标左键按下{this->Slicing = 1; //标志位。当鼠标左键按下时,就设置切片提取标志为1}else if (event == vtkCommand::LeftButtonReleaseEvent)/如果当前事件是鼠标右键按下{this->Slicing = 0; //标志位 }else if (event == vtkCommand::MouseMoveEvent)/如果当前事件是鼠标移动{if (this->Slicing)//检验鼠标左键已经按下{vtkImageReslice *reslice = this->ImageReslice;//设置当前切片图像位置的矩阵为this->ImageReslice;但在更新之前,不会将这个矩阵数据填充到reslice中去//记下鼠标Y向变化的幅值大小int deltaY = lastPos[1] - currPos[1];//计算鼠标滑动的前后两次点的位置lastPos和currPos。然后计算两点的Y坐标的差deltaYreslice->Update();//使用更新操作,为reslice获取当前切片图像位置的矩阵double sliceSpacing = reslice->GetOutput()->GetSpacing()[2];获取reslice矩阵中的参数vtkMatrix4x4 *matrix = reslice->GetResliceAxes();//定义需要使用的新的中心店center转换至vtkImageSlice当前变换矩阵中的转换矩阵,但这里没有更新,就没有填充//重新定位切片需要经过的中心点double point[4];double center[4];point[0] = 0;point[1] = 0;point[2] = sliceSpacing*deltaY;point[3] = 1.0;matrix->MultiplyPoint(point, center);//填充矩阵matrix->SetElement(0, 3, center[0]);//填充矩阵matrix->SetElement(1, 3, center[1]);//填充矩阵matrix->SetElement(2, 3, center[2]);//填充矩阵interactor->Render();}else//没有触发上述三个事件{vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast(interactor->GetInteractorStyle());if (style){style->OnMouseMove();}}}
}

Command对象定义完毕后,即可为交互对象InteractorStyle添加观察者,响应鼠标消息。
这里主要是定义了vtkImageInteractionCallback对象,并设置vtkImageSlice对象和vtkRenderWindowInteractor对象。然后为交互对象vtkInteractorStyle添加观察者来监控相应的消息。

vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =vtkSmartPointer<vtkRenderWindowInteractor>::New();//定义交互对象vtkSmartPointer<vtkInteractorStyleImage> imagestyle =vtkSmartPointer<vtkInteractorStyleImage>::New();//定义交互模式renderWindowInteractor->SetInteractorStyle(imagestyle);//设置交互模式renderWindowInteractor->SetRenderWindow(renderWindow);//连接交互器与显示窗口renderWindowInteractor->Initialize();//交互器初始化//****************建立 观察者-命令 模式****************//vtkSmartPointer<vtkImageInteractionCallback> callback =vtkSmartPointer<vtkImageInteractionCallback>::New();//设置回调函数callback->SetImageReslice(reslice);//为vtkImageSlice对象设置变换矩阵,确定矩阵对应的切片位置callback->SetInteractor(renderWindowInteractor);imagestyle->AddObserver(vtkCommand::MouseMoveEvent, callback);//鼠标移动对应的回调函数imagestyle->AddObserver(vtkCommand::LeftButtonPressEvent, callback);//按下鼠标左键对应的回调函数imagestyle->AddObserver(vtkCommand::LeftButtonReleaseEvent, callback);//按下鼠标右键对应的回调函数renderWindowInteractor->Start();

这里主要是三个消息:
vtkCommand::LeftButtonPressEvent,
vtkCommand::LeftButtonReleaseEvent,
vtkCommand::MouseMoveEvent,
当响应到这三个消息时,立即执行vtkImageInteractionCallback的Execute函数,以便实现切片的实时提取和更新。完成以后,运行程序,当鼠标在图像上移动时,会发现图像会跟着鼠标的移动而变化。

相关文章:

VTK使用交互器来从三维体数据中提取二维切片

VTK中鼠标消息是在交互类型对象&#xff08;interactorstyle&#xff09;中响应&#xff0c;因此通过为交互类型对象&#xff08;interactorstyle&#xff09;添加观察者&#xff08;observer&#xff09;来监听相应的消息&#xff0c;当消息触发时&#xff0c;由命令模式执行相…...

NCBI 数据下载

网上介绍的那几种直接下载NCBI数据的方法大都下载速度很慢&#xff0c;但是EBI (European Bioinformatics Institute) 下载很快&#xff0c;而且它的数据库和NCBI是共享的&#xff0c;所以我们可以直接从 EBI 下载。 1 、 确定要下载的 SRA 编号&#xff1b; 2 、 EBI (https…...

【Rust】基础语法

变量&#xff0c;基本类型&#xff0c;函数&#xff0c;注释和控制流&#xff0c;这些几乎是每种编程语言都具有的编程概念。 这些基础概念将存在于每个 Rust 程序中&#xff0c;及早学习它们将使你以最快的速度学习 Rust 的使用。 变量 首先必须说明&#xff0c;Rust 是强类…...

JVM基础:类的生命周期详解

JDK版本&#xff1a;jdk8 IDEA版本&#xff1a;IntelliJ IDEA 2022.1.3 文章目录 一. 生命周期概述二. 加载阶段(Loading)2.1 加载步骤2.2 查看内存中的对象 三. 连接阶段(Linking)3.1 连接之验证3.2 连接之准备3.3 连接阶段之解析 四. 初始化阶段(Initialization)4.1 单个类的…...

【Canvas技法】在Canvas按圆周绘制图形或是标注文字时,角度累加的方向为顺时针,起点为x轴正向

【图解说明】 【核心代码】 // 画圆弧及方向for(var i0;i<4;i){var startMath.PI/2*i;var endstartMath.PI/2;var x1180*Math.cos(start);var y1180*Math.sin(start);var x2180*Math.cos(end);var y2180*Math.sin(end);ctx.beginPath();ctx.arc(0,0,180,start,end,false);ct…...

计算机网络-TCP断开连接阶段错误应对机制

连接断开阶段 四次挥手机制&#xff1a;TCP连接的断开需要四次挥手&#xff0c;这是因为双方都需要独立地关闭数据传输。第二次和第三次挥手不能合并&#xff0c;因为在回复第二次挥手的时候&#xff0c;可能还有数据没有接收完成&#xff0c;所以需要先回复ACK报文&#xff0c…...

springboot动态使用DruidDataSource切换数据源(动态配置多个数据源)

1、添加依赖&#xff0c;在pom文件中添加 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>2.5.0</version></dependency><dependency><grou…...

P8786 [蓝桥杯 2022 省 B] 李白打酒加强版

【dfs题解】---只有50分 (头一回自己用dfs做出来了dp的hard等级的大题&#xff0c;从来没有拿50分这么高兴过哈哈哈哈哈) #include <bits/stdc.h> using namespace std; int n,m; long long ans0; const long long mol1e97; void dfs(int h,int d,int sum) {if(h<0|…...

没有网没有移动存储的情况下两台电脑如何互相传输数据

无网无移动存储情况下两台电脑数据互传探秘 一、直连网线传输数据二、局域网文件共享其他 在信息化时代的今天&#xff0c;电脑作为重要的数据处理工具&#xff0c;在日常生活和工作中扮演着不可或缺的角色。然而&#xff0c;有时我们会遇到一些特殊情况&#xff0c;如没有网络…...

如何用putty通过ssh连接ubuntu

1. 下载和安装PuTTY 访问PuTTY官网下载PuTTY的最新版本。 2. 打开PuTTY 解压下载的文件后&#xff0c;找到PuTTY文件并双击打开。 3. 配置SSH连接 在ubuntu下安装ssh服务在安装ssh时&#xff0c;我一直遇到一个问题&#xff0c;原因是我的虚拟机连不上网&#xff0c;反复实…...

java如何实现rabbitmq的消息确认机制和消息持久化机制配置和示例

在Java中&#xff0c;使用RabbitMQ的客户端库&#xff08;通常是AMQP客户端库&#xff0c;如RabbitMQ的Java客户端&#xff09;可以方便地实现消息确认机制和消息持久化机制。以下是如何实现这两个机制的示例。 1、消息确认机制 RabbitMQ支持两种类型的确认&#xff1a;生产者…...

react 组件:Suspense

允许在子组件完成加载前展示后备方案。 children&#xff1a;真正的 UI 渲染内容。如果 children 在渲染中被挂起&#xff0c;Suspense 边界将会渲染 fallback。 fallback&#xff1a;真正的 UI 未渲染完成时代替其渲染的备用 UI&#xff0c;它可以是任何有效的 React 节点。后…...

2024-4-5修改vscode的代理

今天在vs code 上面配置go环境的时候出现了以下的报错&#xff1a; 2024-04-05 16:18:00.786 [info] Installing golang.org/x/tools/goplslatest FAILED 2024-04-05 16:18:00.786 [info] { “code”: 1, “killed”: false, “signal”: null, “cmd”: “E:\Go\bin\go.exe in…...

python字符切片的规则

跟range一样有三个参数&#xff0c;分别是x:y:z&#xff0c;代表的含义分别为左边界&#xff0c;右边界&#xff08;注意该范围是左闭右开的&#xff0c;也就是说取不到右值&#xff09;和步长。 1. 切片是从左往右还是从右往左&#xff0c;看的是步长的正负&#xff0c;如果步…...

C++ 的内存安全与效率

在C编程中&#xff0c;内存安全和效率是两个至关重要的考虑因素。 内存安全涉及确保程序在分配和使用内存时不会发生错误&#xff0c;如内存泄漏、悬挂指针、越界访问、空指针解引用等&#xff1b; 效率则关注如何有效地使用内存资源&#xff0c;减少不必要的内存分配和释放操…...

Go 实战|使用 Wails 构建轻量级的桌面应用:仿微信登录界面 Demo

概述 本文探讨 Wails 框架的使用&#xff0c;从搭建环境到开发&#xff0c;再到最终的构建打包&#xff0c;本项目源码 GitHub 地址&#xff1a;https://github.com/mazeyqian/go-run-wechat-demo 前言 Wails 是一个跨平台桌面应用开发框架&#xff0c;他允许开发者利用 Go …...

c++取经之路(其五)——类和对象拷贝构造函数

概念&#xff1a;拷贝构造函数&#xff0c;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c;在用已存在的类类型对象创建新对象时由编译器自动调用。 特征&#xff1a; 1. 拷贝构造函数是构造函数的一个重载形式 如&#xff1a; 2. 拷贝…...

YOLOv8最新改进系列:融合最新顶会提出的HCANet网络中卷积和注意力融合模块(CAFM),有效提升小目标检测性能,大幅度拉升目标检测效果!遥遥领先!

YOLOv8最新改进系列&#xff1a;YOLOv8最新改进系列:融合最新顶会提出的HCANet网络中卷积和注意力融合模块(CAFM)&#xff0c;有效提升小目标检测性能&#xff0c;大幅度拉升目标检测效果&#xff01;遥遥领先&#xff01; B站全文戳这里&#xff01; 详细的改进教程以及源码…...

【计算机毕业设计】网上宠物商店管理系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…...

详解Qt添加外部库

在Qt项目中添加外部库是一项常见任务&#xff0c;无论是静态库还是动态库都需要正确的配置才能让项目顺利编译链接。以下是详细步骤和不同场景下的配置方法&#xff1a; 方法一&#xff1a;手动编辑.pro文件 添加头文件路径&#xff1a; 在Qt项目中的.pro文件中使用INCLUDEPAT…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...