用vtk+Qt實現離散數據的體繪製

數據是三維矩陣保存其值,座標表示位置

以下是實現代碼(頭文件和main函數沒有貼上去)

#define vtkRenderingCore_AUTOINIT 4(vtkInteractionStyle,vtkRenderingFreeType,vtkRenderingFreeType,vtkRenderingOpenGL2)
#define vtkRenderingVolume_AUTOINIT 1(vtkRenderingVolumeOpenGL2)
#include <vtkAutoInit.h> 

#include "test_qt.h"
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkCylinderSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QFileDialog>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkStructuredPoints.h>
#include <vtkStructuredPointsReader.h>
#include <vtkVolumeRayCastCompositeFunction.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkVolumeRayCastMapper.h>
#include <vtkColorTransferFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkVolumeProperty.h>
#include <vtkAxesActor.h>
#include <vtkImageShiftScale.h>
#include <vtkImageCast.h>
#include <vtkFixedPointVolumeRayCastMapper.h>
#include <vtkInformation.h>
#include <vtkInteractorStyleTrackballActor.h>
#include <fstream>
#include <cmath>

test_qt::test_qt(QWidget *parent)
	: QMainWindow(parent)
{
	//ui.setupUi(this);
	setWindowTitle(tr("vtk show 3D"));
	setCentralWidget(&widget);

	//renderer = vtkSmartPointer<vtkRenderer>::New();
	//renderer->AddActor(cylinderActor);
	//renderer->SetBackground(1.0, 1.0, 1.0);

	resize(1200, 800);

	rightWidget = new QDockWidget("Navigation", this);
	rightWidget->setFeatures(QDockWidget::DockWidgetMovable);
	rightWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
	//leftWidget->setWindowFlags(Qt::FramelessWindowHint);
	addDockWidget(Qt::RightDockWidgetArea, rightWidget);

	minLabel = new QLabel(tr("min:"));
	minLineEdit = new QLineEdit(tr("4"));
	QGridLayout * minLabelLayout = new QGridLayout;
	minLabelLayout->addWidget(minLabel, 0, 0);
	minLabelLayout->addWidget(minLineEdit, 0, 1);

	minScrollBar = new QScrollBar(Qt::Horizontal);
	minScrollBar->setRange(0, 255);
	minScrollBar->setSingleStep(1);
	minScrollBar->setValue(4);
	connect(minScrollBar, SIGNAL(valueChanged(int)), this, SLOT(minChanged(int)));

	maxLabel = new QLabel(tr("max:"));
	maxLineEdit = new QLineEdit(tr("200"));
	QGridLayout * maxLabelLayout = new QGridLayout;
	maxLabelLayout->addWidget(maxLabel, 0, 0);
	maxLabelLayout->addWidget(maxLineEdit, 0, 1);

	maxScrollBar = new QScrollBar(Qt::Horizontal);
	maxScrollBar->setRange(0, 255);
	maxScrollBar->setSingleStep(1);
	maxScrollBar->setValue(200);
	connect(maxScrollBar, SIGNAL(valueChanged(int)), this, SLOT(maxChanged(int)));

	QVBoxLayout * layoutGray = new QVBoxLayout;
	layoutGray->addSpacing(10);
	layoutGray->addLayout(minLabelLayout);
	layoutGray->addWidget(minScrollBar);
	layoutGray->addSpacing(10);
	layoutGray->addLayout(maxLabelLayout);
	layoutGray->addWidget(maxScrollBar);
	layoutGray->addSpacing(10);

	grayGroupBox = new QGroupBox;
	grayGroupBox->setLayout(layoutGray);
	grayGroupBox->setTitle(tr("Gray level[0,255]"));

	transparencyScrollBar = new QScrollBar(Qt::Horizontal);
	transparencyScrollBar->setRange(0, 100);
	transparencyScrollBar->setSingleStep(1);
	transparencyScrollBar->setValue(3);
	connect(transparencyScrollBar, SIGNAL(valueChanged(int)), 
		this, SLOT(transparencyChanged(int)));

	transparencyLabel = new QLabel(tr("transparency:"));
	transparencyLineEdit = new QLineEdit(tr("0.03"));
	QGridLayout * transparencyLabelLayout = new QGridLayout;
	transparencyLabelLayout->addWidget(transparencyLabel, 0, 0);
	transparencyLabelLayout->addWidget(transparencyLineEdit, 0, 1);

	QVBoxLayout * layoutTrans = new QVBoxLayout;
	layoutTrans->addLayout(transparencyLabelLayout);
	layoutTrans->addWidget(transparencyScrollBar);

	transparencyGroupBox = new QGroupBox;
	transparencyGroupBox->setLayout(layoutTrans);
	transparencyGroupBox->setTitle(tr("Transparency[0,1]"));

	QGridLayout * layoutGroupBox = new QGridLayout;
	layoutGroupBox->addWidget(grayGroupBox);
	layoutGroupBox->addWidget(transparencyGroupBox);

	ParSetGroupBox = new QGroupBox;
	ParSetGroupBox->setLayout(layoutGroupBox);
	ParSetGroupBox->setTitle(tr("Parameter Setting"));

	xLabel = new QLabel(tr("x:"));
	yLabel = new QLabel(tr("y:"));
	zLabel = new QLabel(tr("z:"));

	xLineEdit = new QLineEdit(tr("480"));
	xLineEdit->setMaximumWidth(50);
	yLineEdit = new QLineEdit(tr("480"));
	yLineEdit->setMaximumWidth(50);
	zLineEdit = new QLineEdit(tr("16"));
	zLineEdit->setMaximumWidth(50);

	QHBoxLayout * xyzLayout = new QHBoxLayout;
	xyzLayout->addWidget(xLabel);
	xyzLayout->addWidget(xLineEdit);
	xyzLayout->addWidget(yLabel);
	xyzLayout->addWidget(yLineEdit);
	xyzLayout->addWidget(zLabel);
	xyzLayout->addWidget(zLineEdit);

	dxLabel = new QLabel(tr("dx:"));
	dyLabel = new QLabel(tr("dy:"));
	dzLabel = new QLabel(tr("dz:"));

	dxLineEdit = new QLineEdit(tr("5"));
	dxLineEdit->setMaximumWidth(50);
	dyLineEdit = new QLineEdit(tr("5"));
	dyLineEdit->setMaximumWidth(50);
	dzLineEdit = new QLineEdit(tr("50"));
	dzLineEdit->setMaximumWidth(50);

	QHBoxLayout * dxyzLayout = new QHBoxLayout;
	dxyzLayout->addWidget(dxLabel);
	dxyzLayout->addWidget(dxLineEdit);
	dxyzLayout->addWidget(dyLabel);
	dxyzLayout->addWidget(dyLineEdit);
	dxyzLayout->addWidget(dzLabel);
	dxyzLayout->addWidget(dzLineEdit);

	openBtn = new QPushButton(tr("Open"));
	connect(openBtn, SIGNAL(clicked()), this, SLOT(open()));

	QVBoxLayout * btnLayout = new QVBoxLayout;

	btnLayout->addLayout(xyzLayout);
	btnLayout->addLayout(dxyzLayout);
	btnLayout->addWidget(openBtn);

	readGroupBox = new QGroupBox;
	readGroupBox->setLayout(btnLayout);
	readGroupBox->setTitle(tr("Data Setting"));


	QVBoxLayout * rightlayout = new QVBoxLayout;
	rightlayout->addSpacing(150);
	rightlayout->addWidget(ParSetGroupBox);
	rightlayout->addSpacing(150);
	rightlayout->addWidget(readGroupBox);
	//rightlayout->addLayout(layout5);


	QWidget * widget1 = new QWidget;
	widget1->setLayout(rightlayout);
	rightWidget->setWidget(widget1);

	min_gray = 4;
	max_gray = 200;
	transparency = 0.03;
	dx = dy = 5;
	dz = 50;
	x = y = 480;
	z = 16;
	isOpen = false;

	vtkSmartPointer<vtkRenderer> ren1 = vtkSmartPointer<vtkRenderer>::New();
	ren1->SetBackground(1.0, 1.0, 1.0);
	
	auto window = widget.GetRenderWindow();

	window->AddRenderer(ren1);
	window->Render();
	
}

test_qt::~test_qt()
{

}

void test_qt::maxChanged(int v)
{
	maxLineEdit->setText(QString::number(v));
	max_gray = v;
	if (isOpen)
		update();
}

void test_qt::transparencyChanged(int v)
{
	transparencyLineEdit->setText(QString::number(v / 100.0f));
	transparency = v / 100.0f;
	if (isOpen)
		update();
}

void test_qt::minChanged(int v)
{
	minLineEdit->setText(QString::number(v));
	min_gray = v;
	if (isOpen)
		update();
}

void test_qt::open()
{
	QString filename = QFileDialog::getOpenFileName(this,
		tr("Open the file"),
		"",
		tr("*.dat"));
	if (!filename.isEmpty())
	{
		dx = dxLineEdit->text().toInt();
		dy = dyLineEdit->text().toInt();
		dz = dzLineEdit->text().toInt();

		x = xLineEdit->text().toInt();
		y = yLineEdit->text().toInt();
		z = zLineEdit->text().toInt();

		auto img = vtkSmartPointer<vtkImageData>::New();
		auto info = vtkSmartPointer<vtkInformation>::New();
		//auto info3 = img->GetInformation();//此處也可以從img裏面獲取information,如
		//果information爲空,則會創建一個新的,相當於調用New之後再SetInformation
		img->SetDimensions(x, y, z);
		img->SetSpacing(dx, dy, dz);
		img->SetOrigin(0, 0, 0);
		img->SetScalarType(VTK_UNSIGNED_CHAR, info);
		img->SetNumberOfScalarComponents(1, info);
		img->AllocateScalars(info);

		unsigned char *ptr = (unsigned char *)img->GetScalarPointer();
		ifstream infile(filename.toStdString(), std::ios::binary);
		float temp, max = 0;
		float *tempfloat = new float[x * y * z];

		for (int i = 0; i<x * y * z; i++)
		{
			infile.read((char*)&temp, sizeof(float));
			//temp = log(temp);
			if (max < temp)
				max = temp;
			tempfloat[i] = temp;
		}
		infile.close();
		for (int i = 0; i<x * y * z; i++)
			*ptr++ = tempfloat[i] / max * 255;
		delete[] tempfloat;

		volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
		volumeMapper->SetInputData(img);
		
		vtkSmartPointer<vtkVolumeProperty> volumeProperty 
			= vtkSmartPointer<vtkVolumeProperty>::New();
		volumeProperty->SetInterpolationTypeToLinear();
		//volumeProperty->ShadeOn();  //打開或者關閉陰影測試
		volumeProperty->SetAmbient(0.4);
		volumeProperty->SetDiffuse(0.6);
		volumeProperty->SetSpecular(0.2);

		vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity =
			vtkSmartPointer<vtkPiecewiseFunction>::New();
		compositeOpacity->ClampingOn();
		compositeOpacity->AddPoint(min_gray, 0);
		compositeOpacity->AddPoint(max_gray, transparency);
		
		volumeProperty->SetScalarOpacity(compositeOpacity); //設置不透明度傳輸函數


		vtkSmartPointer<vtkColorTransferFunction> color =
			vtkSmartPointer<vtkColorTransferFunction>::New();

		color->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
		color->AddRGBPoint(36.0, 1.0, 0.0, 0.0);
		color->AddRGBPoint(72.0, 1.0, 1.0, 0.0);
		color->AddRGBPoint(108.0, 0.0, 1.0, 0.0);
		color->AddRGBPoint(144.0, 0.0, 1.0, 1.0);
		color->AddRGBPoint(180.0, 0.0, 0.0, 1.0);
		color->AddRGBPoint(216.0, 1.0, 0.0, 1.0);
		color->AddRGBPoint(255.0, 1.0, 1.0, 1.0);
		/*
		color->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
		color->AddRGBPoint(36.0, 1.0, 0.0, 0.0);
		color->AddRGBPoint(72.0, 1.0, 1.0, 0.0);
		color->AddRGBPoint(108.0, 0.0, 1.0, 0.0);
		color->AddRGBPoint(144.0, 0.0, 1.0, 1.0);
		color->AddRGBPoint(180.0, 0.0, 0.0, 1.0);
		color->AddRGBPoint(216.0, 1.0, 0.0, 1.0);
		color->AddRGBPoint(255.0, 1.0, 1.0, 1.0);*/
		volumeProperty->SetColor(color);

		volume = vtkSmartPointer<vtkVolume>::New();
		volume->SetMapper(volumeMapper);
		volume->SetProperty(volumeProperty);

		ren = vtkSmartPointer<vtkRenderer>::New();
		ren->SetBackground(1.0, 1.0, 1.0);
		ren->AddVolume(volume);
		//ren->ResetCamera();

		auto window = widget.GetRenderWindow();
		
		window->AddRenderer(ren);
		window->Render();


		interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
		interactor->SetRenderWindow(window);

		auto style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
		interactor->SetInteractorStyle(style);

		interactor->Initialize();
		isOpen = true;
	}
}

void test_qt::update()
{
	vtkSmartPointer<vtkVolumeProperty> volumeProperty
		= vtkSmartPointer<vtkVolumeProperty>::New();
	volumeProperty->SetInterpolationTypeToLinear();
	//volumeProperty->ShadeOn();  //打開或者關閉陰影測試
	volumeProperty->SetAmbient(0.4);
	volumeProperty->SetDiffuse(0.6);
	volumeProperty->SetSpecular(0.2);

	vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity =
		vtkSmartPointer<vtkPiecewiseFunction>::New();
	compositeOpacity->ClampingOff();
	compositeOpacity->AddPoint(min_gray, 0);
	compositeOpacity->AddPoint(max_gray, transparency);

	volumeProperty->SetScalarOpacity(compositeOpacity); //設置不透明度傳輸函數


	vtkSmartPointer<vtkColorTransferFunction> color =
		vtkSmartPointer<vtkColorTransferFunction>::New();
	float temp = (max_gray - min_gray) / 7;
	color->AddRGBPoint(min_gray, 0.0, 0.0, 0.0);
	color->AddRGBPoint(min_gray + temp, 1.0, 0.0, 0.0);
	color->AddRGBPoint(min_gray + temp * 2, 1.0, 1.0, 0.0);
	color->AddRGBPoint(min_gray + temp * 3, 0.0, 1.0, 0.0);
	color->AddRGBPoint(min_gray + temp * 4, 0.0, 1.0, 1.0);
	color->AddRGBPoint(min_gray + temp * 5, 0.0, 0.0, 1.0);
	color->AddRGBPoint(min_gray + temp * 6, 1.0, 0.0, 1.0);
	color->AddRGBPoint(min_gray + temp * 7, 1.0, 1.0, 1.0);
	volumeProperty->SetColor(color);

	//vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New();
	volume->SetMapper(volumeMapper);
	volume->SetProperty(volumeProperty);

	//ren = vtkSmartPointer<vtkRenderer>::New();
	ren->SetBackground(1.0, 1.0, 1.0);
	ren->AddVolume(volume);
	//ren->ResetCamera();

	auto window = widget.GetRenderWindow();

	window->AddRenderer(ren);
	window->Render();


	interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	interactor->SetRenderWindow(window);

	auto style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	interactor->SetInteractorStyle(style);

	interactor->Initialize();
}

以下是運行效果,只給界面圖


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章