最近在学习VTK+QT+C++,学习之路真是艰苦。不过总算是努力就有收获,回到正题。
首先,在QT中放入QVTKWidget插件,这个之前又说,不赘述。新建一个QT应用程序,有三个可编辑的文件,即main.cxx、工程名.h、工程名.cxx。main文件几乎不需要编辑。
// main.cxx
#include
#if QT_VERSION < 0x050000
#include
#endif
#include "SimpleView.h"
extern int qInitResources_icons();
int main( int argc, char** argv )
{
// QT Stuff
QApplication app( argc, argv );
#if QT_VERSION >= 0x050000
QApplication::setStyle("fusion");
#else
QApplication::setStyle(new QCleanlooksStyle);
#endif
qInitResources_icons();
SimpleView mySimpleView;
mySimpleView.show();
return app.exec();
}
接下来是工程文件,我的是SimpleView.h
//SimpleView.h
#ifndef SimpleView_H
#define SimpleView_H
#include "vtkSmartPointer.h" // Required for smart pointer internal ivars.
#include
#include "ui_SimpleView.h"
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include "vtkImageViewer2.h"
#include "vtkInteractorStyleImage.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkImageActor.h"
#include "vtkDICOMImageReader.h"
#include "vtkGenericOpenGLRenderWindow.h"
#include "string"
#include "vtkCommand.h"
#include "vtkImageData.h"
#include "vtkPointData.h"
#include "vtkPropPicker.h"
#include "vtkCornerAnnotation.h"
#include "vtkAssemblyPath.h"
#include
#include
#include
#include
class Ui_SimpleView;
class vtkImageViewer2;
class vtkRenderer;
class vtkEventQtSlotConnect;
class vtkObject;
class vtkCommand;
class SimpleView : public QMainWindow,public Ui::SimpleView
{
Q_OBJECT
public:
// Constructor/Destructor
SimpleView();
~SimpleView();
public:
//void vtkValueMessageTemplate(vtkImageData* image, int* position);
public slots:
virtual void slotOpenFile();
virtual void slotExit();
//响应鼠标移动的消息,实时输出鼠标的当前位置
void updateCoords(void);
private:
//Members
vtkSmartPointer myViewer;
vtkSmartPointer myRender;
vtkSmartPointer reader;
vtkSmartPointer propPicker;
vtkPropPicker* Picker; // Pointer to the picker
vtkCornerAnnotation* Annotation; // Pointer to the annotation
vtkSmartPointer m_Connections;
// Designer form
Ui_SimpleView *ui;
};
#endif // SimpleView_H
最后是SimpleView.cxx,重要的实现都在这里
#include "ui_SimpleView.h"
#include "SimpleView.h"
#include "vtkSmartPointer.h"
#include
#include
#define VTK_CREATE(type, name) \
vtkSmartPointer name = vtkSmartPointer::New()
// Constructor
SimpleView::SimpleView()
{
this->ui = new Ui_SimpleView;
this->ui->setupUi(this);
// vtkImageViewer2 全局变量
this->myViewer = vtkSmartPointer::New();
this->myRender = vtkSmartPointer::New();
this->reader = vtkSmartPointer::New();
this->m_Connections = vtkSmartPointer::New();
this->Picker = vtkSmartPointer::New();;
this->Annotation = vtkSmartPointer::New();
this->propPicker = vtkSmartPointer::New();
//设置qvtkWidget的渲染器
this->ui->qvtkWidget->GetRenderWindow()->AddRenderer(this->myRender);
// Set up action signals and slots
connect(this->ui->actionOpenFile, SIGNAL(triggered()), this, SLOT(slotOpenFile()));
connect(this->ui->actionExit, SIGNAL(triggered()), this, SLOT(slotExit()));
//################################################################################
this->m_Connections->Connect(ui->qvtkWidget->GetRenderWindow()->GetInteractor(),
vtkCommand::MouseMoveEvent, this, SLOT(updateCoords()));
//################################################################################
};
//Destructor
SimpleView::~SimpleView()
{
// The smart pointers should clean up for up
}
void SimpleView::slotOpenFile(void)
{
QString FileInstruction;// 新建一个QString对象
FileInstruction = "Image Files(*.dcm);;ALL(*.*)";
QDir FileDir; //使用相对或绝对路径指向文件/目录
//this指定父组件
QString fileName = QFileDialog::getOpenFileName(this,"", FileDir.absolutePath(), FileInstruction);
// 判断路径是否正确
if (fileName.isEmpty() == true)
{
cout << "error path" << endl;
return;
}
//Display path
QFileInfo OpenFileInfo;
OpenFileInfo = QFileInfo(fileName);
QString OpenFilePath = OpenFileInfo.filePath();
//路径名显示在lineEdit中
ui->lineEdit->setText(OpenFilePath);
//Support Chinese path
QByteArray ba = fileName.toLocal8Bit();
const char* fileName_str = ba.data();
reader->SetFileName(fileName_str);// Set the filename for the file to read.
reader->Update();
// Visualize 将reader的输出作为myViewer的输入
myViewer->SetInputConnection(reader->GetOutputPort());
myViewer->UpdateDisplayExtent();
// Window是QT的,render是vtk的,设置myViewer与渲染器myRenderer的关联
myViewer->SetRenderWindow(ui->qvtkWidget->GetRenderWindow());
myViewer->SetRenderer(myRender);
//用QT界面里的interactor响应鼠标事件
myViewer->SetupInteractor(ui->qvtkWidget->GetRenderWindow()->GetInteractor());
myViewer->SetSliceOrientationToXY(); //默认就是这个方向的
//插值
myRender->ResetCamera();
// Set background color 设置的是背景,使用创建的myRender而不是获取myViewer的render(已关联)
myRender->GradientBackgroundOn();
myRender->SetBackground(0.6, 0.6, 0.5);
myRender->SetBackground2(0.3, 0.3, 0.2); //渐变背景渲染
myRender->DrawOn();
ui->qvtkWidget->GetRenderWindow()->Render();
}
// Template for image value reading
template // 模板,初始化时才知道其类型
// 形参为图像,位置和信息
void vtkValueMessageTemplate(vtkImageData* image, int* position, std::string& message)
{
T* tuple = ((T*)image->GetScalarPointer(position)); // 返回一个指向image的位置指针
int components = image->GetNumberOfScalarComponents(); // 获取点的标量分量的数量
for (int c = 0; c < components; ++c)
{
//cout << "pixel_value: " << pixel_value << endl;
message += vtkVariant(tuple[c]).ToString();
if (c != (components - 1))
{
message += ", ";
}
}
//cout << "pixel value: " << message.c_str() << endl;
}
void SimpleView::updateCoords(void)
{
// Picker to pick pixels
this->propPicker->PickFromListOn();
// Give the picker a prop to pick
vtkImageActor* imageActor = this->myViewer->GetImageActor();
propPicker->AddPickList(imageActor);
// disable interpolation, so we can see each pixel
imageActor->InterpolateOff();
// Annotate the image with window/level and mouse over pixel information
vtkSmartPointer cornerAnnotation =
vtkSmartPointer::New();
cornerAnnotation->SetLinearFontScaleFactor(2);
cornerAnnotation->SetNonlinearFontScaleFactor(1);
cornerAnnotation->SetMaximumFontSize(20);
cornerAnnotation->SetText(0, "Off Image");
cornerAnnotation->SetText(3, "\n");
//cornerAnnotation->GetTextProperty()->SetColor(1, 0, 0);
myRender->AddViewProp(cornerAnnotation);
this->Picker = propPicker;
//this->Annotation = cornerAnnotation;
// 利用ui界面的interactor 获取render的指针,用picker类获得鼠标的点
vtkRenderWindowInteractor *interactor = this->myViewer->GetRenderWindow()->GetInteractor();
vtkImageActor* actor = this->myViewer->GetImageActor();
vtkImageData *image2 = this->reader->GetOutput();
//if (image2.empty())
//{
// cout << "Picture has not loading !" << endl;
// return -1;
//}
vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast(interactor->GetInteractorStyle());
//Pick at the mouse location provided by the interactor
this->Picker->Pick(interactor->GetEventPosition()[0],
interactor->GetEventPosition()[1],0.0, this->myViewer->GetRenderer());
// There could be other props assigned to this picker, so
// make sure we picked the image actor
vtkAssemblyPath* path = this->Picker->GetPath();
bool validPick = false;
if (path)
{
vtkCollectionSimpleIterator sit;
path->InitTraversal(sit);
vtkAssemblyNode *node;
for (int i = 0; i < path->GetNumberOfItems() && !validPick; ++i)
{
node = path->GetNextNode(sit);
if (actor == vtkImageActor::SafeDownCast(node->GetViewProp()))
{
validPick = true;
}
}
}
if (!validPick)
{
//this->Annotation->SetText(0, "Off Image");
this->myViewer->GetRenderWindow()->GetInteractor()->Render();
// Pass the event further on
style->OnMouseMove();
return;
}
// Get the world coordinates of the pick
double pos[3];
this->Picker->GetPickPosition(pos);
int image_coordinate[3];
image_coordinate[0] = vtkMath::Round(pos[0]);
image_coordinate[1] = vtkMath::Round(pos[1]);
image_coordinate[2] = this->myViewer->GetSlice();
//cout << "image_coordinate: " << image_coordinate << endl;
vtkImageData* image = this->myViewer->GetInput();
std::string message = "";
switch (image->GetScalarType())
{
vtkTemplateMacro((vtkValueMessageTemplate(image,
image_coordinate,message)));
default:
return;
}
QString str1;
//str1.sprintf("x=%d : y=%d", image_coordinate[0], image_coordinate[1]);
// ui->statusbar->showMessage(str1);
ui->lineEdit_3->setText(QString::number(image_coordinate[0]));
ui->lineEdit_4->setText(QString::number(image_coordinate[1]));
//cout << "data type of lineEdit_3: " << typeid(QString::number(image_coordinate[0])).name() << endl;
//QString str2 = QString::fromStdString(message);
// message.c_str() //char const * __ptr64
// message
ui->lineEdit_2->setText(message.c_str());
//cout << "data type of lineEdit_2: " << typeid(message).name() << endl;
}
void SimpleView::slotExit() {
qApp->exit();
}
程序实现结果
参考自:
https://blog.csdn.net/www_doling_net/article/details/8547317
https://blog.csdn.net/www_doling_net/article/details/8668870
https://lorensen.github.io/VTKExamples/site/Cxx/Qt/EventQtSlotConnect/