【VTK】VTK+QT打开dicom图像并实时显示鼠标坐标位置和像素值

最近在学习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();
}

程序实现结果

【VTK】VTK+QT打开dicom图像并实时显示鼠标坐标位置和像素值_第1张图片

 

参考自:

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/

你可能感兴趣的:(VTK学习)