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

最近在学习VTK+QT+C++,学习之路真是艰苦。不过总算是努力就有收获,回到正题。

首先,在QT中放入QVTKWidget插件,这个之前又说,不赘述。新建一个QT应用程序,有三个可编辑的文件,即main.cxx、工程名.h、工程名.cxx。main文件几乎不需要编辑。

// main.cxx
#include <QApplication>
#if QT_VERSION < 0x050000
  #include <QCleanlooksStyle>
#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 <QMainWindow>
#include "ui_SimpleView.h"

#include <QFileDialog>
#include <QDir>
#include <qstring.h>
#include <qlineedit.h>
#include <QPushButton>

#include <vtkDataObjectToTable.h>
#include <vtkElevationFilter.h>
#include <vtkPolyDataMapper.h>
//#include <vtkQtTableView.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkVectorText.h>

#include <QtWidgets/QApplication>
#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 <vtkEventQtSlotConnect.h>
#include <vtkImageNoiseSource.h>
#include <vtkImageCast.h>

#include <QVTKWidget.h>

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<vtkImageViewer2>             myViewer;
	vtkSmartPointer<vtkRenderer>                 myRender;
	vtkSmartPointer<vtkDICOMImageReader>         reader;
	vtkSmartPointer<vtkPropPicker>               propPicker;



	vtkPropPicker*              Picker;          // Pointer to the picker
	vtkCornerAnnotation*        Annotation;      // Pointer to the annotation
	vtkSmartPointer<vtkEventQtSlotConnect>       m_Connections;

	// Designer form
	Ui_SimpleView *ui;
};

#endif // SimpleView_H

最后是SimpleView.cxx,重要的实现都在这里

#include "ui_SimpleView.h"
#include "SimpleView.h"
#include "vtkSmartPointer.h"
#include <vtkMath.h>
#include <typeinfo>
#define VTK_CREATE(type, name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()


// Constructor
SimpleView::SimpleView()
{

	this->ui = new Ui_SimpleView;
	this->ui->setupUi(this);

	// vtkImageViewer2 全局变量
	this->myViewer = vtkSmartPointer<vtkImageViewer2>::New();
	this->myRender = vtkSmartPointer<vtkRenderer>::New();
	this->reader = vtkSmartPointer<vtkDICOMImageReader>::New();

	this->m_Connections = vtkSmartPointer<vtkEventQtSlotConnect>::New();
	this->Picker = vtkSmartPointer<vtkPropPicker>::New();;
	this->Annotation = vtkSmartPointer<vtkCornerAnnotation>::New();
	this->propPicker = vtkSmartPointer<vtkPropPicker>::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<typename T> // 模板,初始化时才知道其类型
// 形参为图像,位置和信息
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<vtkCornerAnnotation> cornerAnnotation =
		vtkSmartPointer<vtkCornerAnnotation>::New();
	cornerAnnotation->SetLinearFontScaleFactor(2);
	cornerAnnotation->SetNonlinearFontScaleFactor(1);
	cornerAnnotation->SetMaximumFontSize(20);
	cornerAnnotation->SetText(0, "Off Image");
	cornerAnnotation->SetText(3, "<window>\n<level>");
	//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<VTK_TT>(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/

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
VTK是Visualization Toolkit的缩写,是一个开源的图形处理工具库,用于创建、处理和渲染三维图形。它提供了丰富的功能,可以用于各种应用程序,包括科学可视化、医学图像处理、机器人学等。 Qt是一种跨平台的应用程序开发框架,具有丰富的GUI(图形用户界面)组件和工具,可以用于创建各种类型的应用程序。它提供了直观、交互式的界面设计工具,使开发人员能够轻松地创建用户友好的应用程序。 DICOM是医学图像和通信标准的缩写,它是医学领域的一种通用文件格式和协议,用于存储、传输和共享医学图像和相关信息。DICOM文件通常包含来自医学成像设备(如CT扫描、MRI、X射线等)的图像数据及其相关的患者信息、检查参数等。 VTKQtDICOM常常一起使用,用于开发医学图像处理和分析的应用程序。通过使用VTKQt,开发人员可以轻松地创建具有丰富可视化效果的医学图像应用程序,并提供直观、智能化的界面。VTK提供了丰富的图形处理和可视化工具,可以对DICOM图像进行处理、分析和可视化。而Qt的GUI组件和界面设计工具使开发人员能够创建用户友好的应用程序界面,方便用户查看、编辑和分析DICOM图像。 总的来说,VTKQtDICOM的结合为医学图像处理和分析应用程序的开发提供了强大的工具和功能。它们的使用可以加快开发过程,提高应用程序的效率和用户友好性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值