Qt VTK交互(上下键滑动图像切片,点击按钮切换三维图像视图)
// main.cpp
#include "qtVtkL01.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qtVtkL01 w;
w.show();
return a.exec();
}
//qtVtkL01.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_qtVtkL01.h"
#include <vtkGenericOpenGLRenderWindow.h>
#include <QFileDialog>
#include <QDir>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkImageViewer2.h>
#include <QVTKWidget.h>
#include <vtkJPEGReader.h>
#include <vtkImageActor.h>
#include <vtkEventQtSlotConnect.h>
#include <vtkCommand.h>
#include <vtkConeSource.h>
#include <vtkPolyDataReader.h>
#include <vtkSTLReader.h>
#include <vtkPolyData.h>
#include <vtkDataSet.h>
#include <vtkPointData.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkCubeSource.h>
#include <vtkEventQtSlotConnect.h>
#include <QVTKWidget.h>
#include <QMenu>
#include <QAction>
#include <QPointer>
#include <QVTKOpenGLNativeWidget.h>
#include <QVBoxLayout>
#include <vtkOpenGLRenderWindow.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkSmartPointer.h>
#include <QWheelEvent>
#include <vtkCallbackCommand.h>
class qtVtkL01 : public QMainWindow
{
Q_OBJECT
public:
qtVtkL01(QWidget *parent = nullptr);
~qtVtkL01();
public slots:
void pushButton_Clicked();
private:
Ui::qtVtkL01Class ui;
QVTKOpenGLNativeWidget* vtkWidget;
//vtkSmartPointer<vtkRenderer> renderer;
//vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow;
//vtkSmartPointer<vtkRenderWindow> renderWindow;
//vtkSmartPointer<vtkRenderWindowInteractor> interactor;
vtkSmartPointer<vtkImageViewer2> imageViewer;
int currentSlice; // 当前切片索引
int minSlice; // 最小切片索引
int maxSlice; // 最大切片索引
int vision_flag = 1;
};
//qtVtkL01.cpp
#include "qtVtkL01.h"
#include <QVTKOpenGLNativeWidget.h>
#include <vtkMetaImageReader.h>
#include <vtkImageViewer2.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkImageSliceMapper.h>
#include <QSlider>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
class myCallback : public vtkCommand
{
public:
static myCallback* New() {
return new myCallback;
}
// 将
void setProperty(vtkSmartPointer<vtkImageViewer2> imageViewer, int currentSlice) {
m_imageViewer = imageViewer;
m_currentSlice = currentSlice;
minSlice = 0;
maxSlice = 200;
}
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") {
if (m_currentSlice < maxSlice) {
std::cout << "Up arrow key pressed! " << m_currentSlice << std::endl;
m_currentSlice++;
m_imageViewer->SetSlice(m_currentSlice);
//m_imageViewer->Render();
}
else {
m_currentSlice = maxSlice;
}
}
if (key == "Down") {
if (m_currentSlice > minSlice) {
std::cout << "Down arrow key pressed! " << m_currentSlice << std::endl;
m_currentSlice--;
m_imageViewer->SetSlice(m_currentSlice);
//m_imageViewer->Render();
}
else {
m_currentSlice = minSlice;
}
}
}
}
public:
vtkSmartPointer<vtkImageViewer2> m_imageViewer;
int m_currentSlice; // 当前切片索引
int minSlice; // 最小切片索引
int maxSlice; // 最大切片索引
};
qtVtkL01::qtVtkL01(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
setFixedWidth(1000);
setFixedHeight(700);
ui.pushButton->setFixedWidth(100);
ui.pushButton->setFixedHeight(30);
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(pushButton_Clicked()));
// 创建QVTKOpenGLWidget
ui.vtkWidget->resize(500, 350);
ui.vtkWidget->move(200, 150);
// 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();
imageViewer->SetInputConnection(reader->GetOutputPort());
imageViewer->SetColorLevel(500);
imageViewer->SetColorWindow(2000);
imageViewer->SetRenderWindow(ui.vtkWidget->GetRenderWindow());
imageViewer->SetSliceOrientationToXY();
// 获取切片范围
minSlice = imageViewer->GetSliceMin();
maxSlice = imageViewer->GetSliceMax();
currentSlice = minSlice;
imageViewer->SetSlice(currentSlice);
imageViewer->Render();
ui.vtkWidget->GetInteractor()->RemoveAllObservers();
vtkSmartPointer<myCallback> Callback = vtkSmartPointer<myCallback>::New();
Callback->setProperty(imageViewer, currentSlice);
ui.vtkWidget->GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, Callback);
//interactor = ui.vtkWidget->GetRenderWindow()->GetInteractor();
//vtkSmartPointer<vtkInteractorStyleTrackballCamera> interactorStyle = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
//
//interactor->SetInteractorStyle(interactorStyle);
//interactor->Initialize();
}
qtVtkL01::~qtVtkL01()
{}
void qtVtkL01::pushButton_Clicked() {
vision_flag++;
if (vision_flag == 1) {
imageViewer->SetSliceOrientationToXY();
//imageViewer->Render();
std::cout << "view xy" << std::endl;
}
if (vision_flag == 2) {
imageViewer->SetSliceOrientationToYZ();
//imageViewer->Render();
std::cout << "view yz" << std::endl;
}
if (vision_flag == 3) {
imageViewer->SetSliceOrientationToXZ();
//imageViewer->Render();
std::cout << "view xz" << std::endl;
}
if (vision_flag == 3) {
vision_flag = 0;
}
}
最终的显示效果图如下:
点击切换视图可以对显示的三维图像数据的视图进行切换,按键盘的上下键可以改变显示的图像切片
注意:
程序中vtkWidget
的类型为QVTKOpenGLNativeWidget
并且只使用了vtkImageViewer2
来对图像进行展示。
vtkImageViewer2
内部包括了vtkActor,vtkRender,vtkRenderWindow等对象,不需要我们逐步去构建。
同时,我们也不需要去构建vtkRenderWindowInteractor
,因为QVTKOpenGLNativeWidget
会自动为其内部的 vtkRenderWindow
创建一个默认的 vtkRenderWindowInteractor
。
我们可以直接通过 vtkWidget->GetRenderWindow()->GetInteractor()
获取交互器。
貌似直接使用 vtkWidget->GetInteractor()
也可以获取到它的交互器。
一些区别:
imageViewer->SetRenderWindow(ui.vtkWidget->GetRenderWindow());
ui.vtkWidget->SetRenderWindow(imageViewer->GetRenderWindow());
使用下面那行代码,vtk的窗口嵌入不到qt的窗口中。类似下图所示:
原因是: