VTK交互(三维图像切片切换)

VTK交互

vtk交互功能主要是通过 观察者/命令模式(Observer/Command)来实现。
其是指 一个 对象 可以有多个观察者(Observer),当该对象的状态发生改变时,所以依赖于它的观察者(Observer)对象都得到通知而被自动更新。
命令模式是属于对象行为模式,它把请求封装为一个对象,并提供一致性发送请求的接口,当一个事件发生时,它不直接把事件传递给事件的调用者,而是在命令和调用者之间增加一个中间者,将这种直接关系切断,同时将两者都隔离。事件调用者只是和接口打交道,不和具体事件实现交互。
vtk有两种方式来实现观察者/命令模式

  • 事件回调函数
  • vtkCommand派生具体子类

1、事件回调函数示例
(使用回调函数来实现 键盘 上键和下键 ,三维图像切片的切换)

#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkLookupTable.h>
#include <vtkDataSetMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCaptionRepresentation.h>
#include <vtkMetaImageReader.h>
#include <vtkImageViewer2.h>

#include <vtkAutoInit.h> 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);

#include <vtkCallbackCommand.h>

int minSlice = 0;
int maxSlice = 0;
int currentSlice = minSlice;
vtkSmartPointer<vtkImageViewer2> imageViewer;

void MyCallbackFunc(vtkObject* caller, unsigned long eid, void* clientdata, void* calldata)
{
    if (eid == vtkCommand::KeyPressEvent) {
        vtkRenderWindowInteractor* interactor = static_cast<vtkRenderWindowInteractor*>(caller);
        std::string key = interactor->GetKeySym();

        if (key == "Up") {
            std::cout << "Up arrow key pressed!  " << currentSlice<< std::endl;
            currentSlice--;
            imageViewer->SetSlice(currentSlice);
            imageViewer->Render();
        }
        if (key == "Down") {
            std::cout << "Down arrow key pressed!  " << currentSlice<< std::endl;
            currentSlice++;
            imageViewer->SetSlice(currentSlice);
            imageViewer->Render();
        }
    }
    
}

int main(int argc, char* argv[])
{
	// 1- read file
	vtkSmartPointer<vtkMetaImageReader> reader = vtkSmartPointer<vtkMetaImageReader>::New();
	reader->SetFileName("D:\\Projects\\visualStudio2019\\za\\qtVtkL01\\data\\brain.mhd");
	reader->Update();

    // 创建图像查看器
    imageViewer = vtkSmartPointer<vtkImageViewer2>::New();
    vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();

    imageViewer->SetInputConnection(reader->GetOutputPort());
    imageViewer->SetColorLevel(500);
    imageViewer->SetColorWindow(2000);
    imageViewer->SetSliceOrientationToXY();
   

    // 获取切片范围
    minSlice = imageViewer->GetSliceMin();
    maxSlice = imageViewer->GetSliceMax();
    currentSlice = minSlice + 40;

    imageViewer->SetSlice(currentSlice);
    imageViewer->Render();

    //Step1:设置事件回调函数
    vtkSmartPointer<vtkCallbackCommand> mouseCallback = vtkSmartPointer<vtkCallbackCommand>::New();
    mouseCallback->SetCallback(MyCallbackFunc); //

    //Step2:将vtkCallbackCommand对象添加到观察者列表。
    interactor->SetRenderWindow(imageViewer->GetRenderWindow()); //唤醒显示窗口
    // 为interactor 添加 observer ,并设置观察的事件
    interactor->AddObserver(vtkCommand::KeyPressEvent, mouseCallback);

    imageViewer->SetupInteractor(interactor);
    interactor->Initialize();
    interactor->Start();
  

	return EXIT_SUCCESS;
}

其步骤可以总结为三个步骤:

  1. 定义回调函数
    其函数形式只能为:
void long MyCallbackFunc(vtkObject* caller, unsigned long eid, void* clientdata, void* calldata);
caller // 调用事件的对象,调用AddObserver函数的对象,本例中为 interactor
eid // 所要监听的事件id,本例中为 vtkCommand::KeyPressEven
clientdata //是与VTKCallbackCommand实例相关的数据,简单地说,是指回调函数里需要访问主程序里面得数据时,由主程序向回调函数传递的数据
calldata // 是执行vtkObject::InvokeEvent()函数时,随着回调函数发送得数据,比如说,当调用ProgressEvent事件时,会自动发送当前的进度值作为callback
  1. 创建 vtkCallbackCommand 对象,并调用 SetCallback 设置回调函数
   vtkSmartPointer<vtkCallbackCommand> mouseCallback = vtkSmartPointer<vtkCallbackCommand>::New();
   mouseCallback->SetCallback(MyCallbackFunc); //
  1. 将 vtkCallbackCommand 对象添加到对象的观察者列表中
    interactor->SetRenderWindow(imageViewer->GetRenderWindow()); //唤醒显示窗口
    // 为interactor 添加 observer ,并设置观察的事件
    interactor->AddObserver(vtkCommand::KeyPressEvent, mouseCallback);

参考文章:https://www.cnblogs.com/ybqjymy/p/14244495.html

2、vtkCommand派生具体子类 示例

(使用vtkCommand派生子类来实现 键盘 上键和下键 ,三维图像切片的切换)

#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkLookupTable.h>
#include <vtkDataSetMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCaptionRepresentation.h>
#include <vtkMetaImageReader.h>
#include <vtkImageViewer2.h>

#include <vtkAutoInit.h> 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);

#include <vtkCallbackCommand.h>

int minSlice = 0;
int maxSlice = 0;
int currentSlice = minSlice;
vtkSmartPointer<vtkImageViewer2> imageViewer;

class myCallback : public vtkCommand
{
public:
    static myCallback* New() {
        return new myCallback;
    }

    virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData) {
        if (eventId == vtkCommand::KeyPressEvent) {
            vtkRenderWindowInteractor* interactor = static_cast<vtkRenderWindowInteractor*>(caller);
            std::string key = interactor->GetKeySym();

            if (key == "Up") {
                std::cout << "Up arrow key pressed!  " << currentSlice << std::endl;
                currentSlice--;
                imageViewer->SetSlice(currentSlice);
                imageViewer->Render();
            }
            if (key == "Down") {
                std::cout << "Down arrow key pressed!  " << currentSlice << std::endl;
                currentSlice++;
                imageViewer->SetSlice(currentSlice);
                imageViewer->Render();
            }
        }
    }

};

int main(int argc, char* argv[])
{
    // 1- read file
    vtkSmartPointer<vtkMetaImageReader> reader = vtkSmartPointer<vtkMetaImageReader>::New();
    reader->SetFileName("brain.mhd");
    reader->Update();

    // 创建图像查看器
    imageViewer = vtkSmartPointer<vtkImageViewer2>::New();
    vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();

    imageViewer->SetInputConnection(reader->GetOutputPort());
    imageViewer->SetColorLevel(500);
    imageViewer->SetColorWindow(2000);
    imageViewer->SetSliceOrientationToXY();


    // 获取切片范围
    minSlice = imageViewer->GetSliceMin();
    maxSlice = imageViewer->GetSliceMax();
    currentSlice = minSlice + 40;

    imageViewer->SetSlice(currentSlice);
    imageViewer->Render();

    //Step1:
    vtkSmartPointer<myCallback> Callback = vtkSmartPointer<myCallback>::New();

    //Step2:
    interactor->SetRenderWindow(imageViewer->GetRenderWindow()); //唤醒显示窗口
    // 为interactor 添加 observer ,并设置观察的事件
    interactor->AddObserver(vtkCommand::KeyPressEvent, Callback);

    imageViewer->SetupInteractor(interactor);
    interactor->Initialize();
    interactor->Start();
    
    return EXIT_SUCCESS;
}

其步骤也可以总结为三个:

  1. 从vtkCommand派生出子类,实现vtkCommand::Execute()虚函数 [事件发生要执行的操作写入此函数体内]
  2. 创建派生出子类的实例对象
  3. 调用观察者函数
interactor->AddObserver(vtkCommand::KeyPressEvent, Callback);

interactor通过AddObserve会监听键盘事件的发生与否,若发生,则会调用相关的Execute()函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值