VTK体绘制之3D纹理映射算法实现

3D纹理映射概述

基于Ray Casting算法在系统中的源代码实现,可知该算法实现过程中的计算量是相当大,并不利于实现实时渲染,尤其是当用户对可视化的三维模型进行旋转或缩放等交互性操作时。为改进优化这一相关问题,现阶段的体绘制算法三维重建中会借用计算机图像处理的硬件设备来实现重建绘制过程中的加速,即利用纹理映射来加速。该原理是将系统通过读取DICOM序列图像获得三维体数据,将三维体数据作为纹理进行装载到计算机图像处理的硬件缓存中,之后在利用计算机图像处理的硬件条件来实现图像合成操作,从而在此基础上来提高系统实现重建绘制的效率。通过这种方法得到的三维结构模型的渲染效果从本质上讲与Ray Casting算法实现的渲染效果相同。
在进行3D纹理映射算法的实现时需要特别注意的一点,受计算机图像硬件纹理空间限制,当系统通过读取DICOM序列图像获得的三维体数据传递至 vtkVolumeTextureMapper3D类中,系统会进行重采样,来确保当前处理的图像大小能够满足纹理空间的限制条件。目前市面上,能够实现基于VTK类库的3D纹理映射算法的计算机需要配备两种类型显卡:NVIDIA或者ATI。

基于VTK的3D纹理映射实现

3D纹理映射体绘制算法实现不同与Ray Casting体绘制算法中通过vtkFixedPointVolumeRayCastMapper类,是基于vtkVolumeTextureMapper3D类。
在这里插入图片描述
3D纹理映射体绘制算法基于vtkVolumeTextureMapper3D类实现,创建该类的智能指针,获取系统读取的DICOM序列图像三维体数据并进行处理。下一步与Ray Casting体绘制算法中体属性数据设置基本相同,基于vtkVolumeProperty类创建智能指针,定义体属性数据对象,通过类中静态函数ShadeOn()打开光照/阴影测试,通过静态函数SetScalarOpacity()、SetGradientOpacity()和SetColor()来依次添加灰度不透明度、梯度不透明度和颜色;基于vtkPiecewiseFunction类创建两个不同智能指针,用来设置灰度不透明度和梯度不透明度,通过多参数测试选取可视化效果最佳的参数实现对三维模型的渲染;基于vtkColorTransferFunction类设置颜色函数,同样通过多参数测试选取可视化效果最佳的参数实现对三维模型的渲染。最后使用vtkVolume类绑定颜色传输函数、灰度不透明度和梯度不透明设置函数完成数据渲染。具体设置可参考另一篇文章:三维重建VTK体绘制,Ray Casting和最大密度投影

实现代码

//体绘制


#include <vtkObjectFactory.h>
#include <vtkDataObjectToTable.h>
#include <vtkElevationFilter.h>
#include <vtkSphereSource.h>
#include <vtkCubeSource.h>
#include <vtkCylinderSource.h>
#include <vtkImageGaussianSmooth.h>
#include<vtkColorTransferFunction.h>
#include<vtkPiecewiseFunction.h>
#include<vtkImageShiftScale.h>
#include<vtkMetaImageReader.h>
#include<vtkStripper.h>
#include <vtkInteractorStyleImage.h>
#include <vtkActor2D.h>
#include <vtkTextProperty.h>
#include <vtkTextMapper.h>
#include <sstream>

#include"vtkCommand.h"
#include"vtkSliderWidget.h"
#include"vtkSliderRepresentation2D.h"

//test
#include <vtkFillHolesFilter.h>
#include <vtkConnectivityFilter.h>
#include <vtkDataSetMapper.h>
#include <vtkUnstructuredGrid.h>
#include <vtkCellData.h>
#include <vtkCellIterator.h>
#include <vtkGenericCell.h>
#include <vtkOutlineFilter.h>
#include <vtkNamedColors.h>
#include <vtkContourFilter.h>
#include <vtkPolyDataConnectivityFilter.h>
#include <vtkQuadricDecimation.h>
#include <vtkDecimatePro.h>


#include<vtkRenderWindowInteractor.h>
#include<vtkDICOMImageReader.h>
#include<vtkCamera.h>
#include<vtkActor.h>
#include<vtkRenderer.h>
#include<vtkVolumeProperty.h>
#include<vtkProperty.h>
#include<vtkPolyDataNormals.h>
#include<vtkImageShiftScale.h>
#include <vtkFixedPointVolumeRayCastMapper.h>
#include<vtkPiecewiseFunction.h>
#include<vtkColorTransferFunction.h>
#include<vtkRenderWindow.h>
#include<vtkImageCast.h>
#include<vtkOBJExporter.h>
#include<vtkOutlineFilter.h>
#include<vtkPolyDataMapper.h>
#include <vtkFixedPointVolumeRayCastMIPHelper.h>
#include<vtkInteractorStyleTrackballCamera.h>

#include<vtkMetaImageReader.h>
#include<vtkLODProp3D.h>
#include <vtkTransformTextureCoords.h>
#include <vtkTexture.h>
#include <vtkTextureMapToSphere.h>
#include <vtkTextureMapToCylinder.h>
#include <vtkTexturedSphereSource.h>
#include <vtkPlaneSource.h>
#include "vtkVolumeTextureMapper3D.h"


#include <vtkImageViewer2.h>
#include <vtkImageSliceMapper.h>
#include <vtkImageFlip.h>
#include <vtkImageGradient.h>
#include <vtkImageMagnitude.h>
#include <vtkImageShiftScale.h>
#include <vtkImageHybridMedian2D.h>

#include <vtkPolyDataMapper.h>
#include <vtkPolyData.h>

//Gpu光照映射
#include<vtkGPUVolumeRayCastMapper.h>
#include <vtkImageData.h>
#include<iostream>

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);//基于vtk-7.0,所以是OpenGL,若基于VTK-8.0则是OpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL);

#include "itkGDCMSeriesFileNames.h"
#include "itkVTKImageToImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkImageSeriesWriter.h"
#include "itkCurvatureFlowImageFilter.h"
#include "itkCastImageFilter.h"
#include "itksys/SystemTools.hxx"
#include "itkImageRegionIterator.h"
#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>  
#include <itkPNGImageIOFactory.h>  
#include <itkConnectedThresholdImageFilter.h>  
#include <itkImageSeriesReader.h>  
#include <itkGDCMImageIO.h>
#include "itkBinaryThresholdImageFilter.h"
#include "itkBinaryFillholeImageFilter.h"
#include "itkGrayscaleFillholeImageFilter.h"
#include "itkMeanImageFilter.h"
#include "itkGradientMagnitudeImageFilter.h"
#include "itkExtractImageFilter.h"
#include <itkImageToVTKImageFilter.h>
//#include<vtkRenderingVolumeOpenGL2ObjectFactory.h>
//#include<vtkRenderingOpenGL2ObjectFactory.h>

#include <vector>
#include <string>


using namespace std;
typedef short PixelType;
const unsigned int   Dimension = 2;
typedef itk::Image< PixelType, Dimension > Input2dImageType;
typedef itk::Image< PixelType, 3 > Input3dImageType;

typedef itk::Image< PixelType, Dimension > Output2dImageType;
typedef itk::Image< PixelType, 3 > Output3dImageType;

typedef itk::GDCMImageIO   ImageIOType;//GDCMImageIO读DICOM
ImageIOType::Pointer gdcmImageIO = ImageIOType::New();

using ReaderType3d = itk::ImageSeriesReader< Input3dImageType >;
ReaderType3d::Pointer reader3d = ReaderType3d::New();

typedef itk::ImageFileReader< Input2dImageType > ReaderType2d;
ReaderType2d::Pointer reader2d = ReaderType2d::New();

using NamesGeneratorType = itk::GDCMSeriesFileNames;
NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();

int main()
{
	reader3d->SetImageIO(gdcmImageIO);
	nameGenerator->SetUseSeriesDetails(true);
	nameGenerator->SetDirectory("D:\\Bishe\\Projects\\DICOM\\dicom\\lung");

	using SeriesIdContainer = std::vector< std::string >;
	const SeriesIdContainer& seriesUID = nameGenerator->GetSeriesUIDs();
	auto seriesItr = seriesUID.begin();
	auto seriesEnd = seriesUID.end();

	using FileNamesContainer = std::vector< std::string >;
	FileNamesContainer fileNames;
	std::string seriesIdentifier;
	while (seriesItr != seriesEnd)
	{
		seriesIdentifier = seriesItr->c_str();
		fileNames = nameGenerator->GetFileNames(seriesIdentifier);
		++seriesItr;
	}
	reader3d->SetFileNames(fileNames);
	reader3d->Update();
    
	try
	{
		reader3d->Update();
		reader3d->GetMetaDataDictionary();
		gdcmImageIO->GetMetaDataDictionary();// 读取头文件信息;

		//信息赋值
		char* name = new char[50];
		char* patientID = new char[50];
		char* time = new char[50];
		char* manufacture = new char[50];
		char* modility = new char[50];
		char* hospital = new char[50];
		char* sex = new char[50];
		char* age = new char[50];
		char* description = new char[100];

		int pixelType = gdcmImageIO->GetPixelType();
		int componentType = gdcmImageIO->GetComponentType();
		int fileType = gdcmImageIO->GetFileType();
		ImageIOType::ByteOrder byteOrder;
		byteOrder = gdcmImageIO->GetByteOrder();

		unsigned int dim = 0;
		gdcmImageIO->GetDimensions(dim);
		ImageIOType::SizeType imgsize;
		imgsize = gdcmImageIO->GetImageSizeInPixels();
		int componetSize = gdcmImageIO->GetComponentSize();
		int dimension = gdcmImageIO->GetNumberOfDimensions();
		int ori = 0;

		gdcmImageIO->GetOrigin(ori);
		int spa = 0;

		gdcmImageIO->GetPatientSex(sex);
		gdcmImageIO->GetPatientAge(age);
		gdcmImageIO->GetStudyDescription(description);
		gdcmImageIO->GetSpacing(spa);
		gdcmImageIO->GetPatientName(name);
		gdcmImageIO->GetModality(modility);
		gdcmImageIO->GetPatientID(patientID);
		gdcmImageIO->GetManufacturer(manufacture);
		gdcmImageIO->GetStudyDate(time);
		ImageIOType::TCompressionType compressType;
		compressType = gdcmImageIO->GetCompressionType();
		gdcmImageIO->GetInstitution(hospital);
		/*ImageType::SpacingType spacetype;
		spacetype = reader->GetOutput()->GetSpacing();
		ImageType::PointType origin;
		origin = reader3d->GetOutput()->GetOrigin();*/
        
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
		cout << "sex:" << sex << endl;
		cout << "description:" << description << endl;
		cout << "hospital:" << hospital << endl;
		cout << "modility:" << modility << endl;
		cout << "manfacture:" << manufacture << endl;
		cout << "dim:" << dim << endl;
		//cout << "origin:" << origin << endl;
		cout << "Time:" << time << endl;
		cout << "patientID:" << patientID << endl;

	}
	catch (const itk::ExceptionObject& excp)
	{
		cout << " Reading Exceptaion Caught" << endl;
		cout << excp.what() << endl;

		return EXIT_FAILURE;
	}


	typedef itk::ImageToVTKImageFilter< Input3dImageType> itkTovtkFilterType;
	itkTovtkFilterType::Pointer itkTovtkImageFilter = itkTovtkFilterType::New();
	itkTovtkImageFilter->SetInput(reader3d->GetOutput());//设置图像数据从ITK转向VTK
	itkTovtkImageFilter->Update();

	vtkSmartPointer< vtkImageFlip > reader = vtkSmartPointer< vtkImageFlip >::New();
	reader->SetInputData(itkTovtkImageFilter->GetOutput());

	reader->SetFilteredAxes(1);
	reader->Update();

	//定义绘制器;
	vtkRenderer* aRenderer = vtkRenderer::New();//指向指针;
	vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();
	renWin->AddRenderer(aRenderer);

	/*vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New();
	reader->SetDirectoryName("D:\\Bishe\\Projects\\DICOM\\dicom\\lung");
	reader->SetDataByteOrderToLittleEndian();*/

	vtkVolumeTextureMapper3D* volumeMapper = vtkVolumeTextureMapper3D::New();
	volumeMapper->SetInputConnection(reader->GetOutputPort());
	//volumeMapper->SetInputData(reader->GetOutput());

	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->AddPoint(100, 0.00);
	compositeOpacity->AddPoint(140, 0.40);
	compositeOpacity->AddPoint(180, 0.60);
	volumeProperty->SetScalarOpacity(compositeOpacity);

	vtkSmartPointer<vtkColorTransferFunction> color =
		vtkSmartPointer<vtkColorTransferFunction>::New();
	color->AddRGBPoint(0.000, 0.00, 0.00, 0.00);
	color->AddRGBPoint(64.00, 1.00, 0.52, 0.30);
	color->AddRGBPoint(190.0, 1.00, 1.00, 1.00);
	color->AddRGBPoint(220.0, 1.00, 1.00, 1.00);
	volumeProperty->SetColor(color);

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

	vtkOutlineFilter* outlineData = vtkOutlineFilter::New();//线框;
	vtkPolyDataMapper* mapOutline = vtkPolyDataMapper::New();
	mapOutline->SetInputConnection(outlineData->GetOutputPort());
	vtkActor* outline = vtkActor::New();
	outline->SetMapper(mapOutline);
	outline->GetProperty()->SetColor(0, 0, 0);//背景纯黑色;

	aRenderer->AddVolume(volume);
	aRenderer->AddActor(outline);
	aRenderer->SetBackground(1, 1, 1);
	aRenderer->ResetCamera();

	//重设相机的剪切范围;
	aRenderer->ResetCameraClippingRange();
	renWin->SetSize(800, 800);
	renWin->SetWindowName("测试");

	vtkRenderWindowInteractor* iren2 = vtkRenderWindowInteractor::New();
	iren2->SetRenderWindow(renWin);

	//设置相机跟踪模式
	vtkInteractorStyleTrackballCamera* style = vtkInteractorStyleTrackballCamera::New();
	iren2->SetInteractorStyle(style);

	renWin->Render();
	iren2->Initialize();

	iren2->Start();

	vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
	vtkSmartPointer<vtkPolyDataMapper> polyDatamapper = vtkSmartPointer<vtkPolyDataMapper>::New();


	vtkOBJExporter* porter = vtkOBJExporter::New();
	porter->SetFilePrefix("D:\\Bishe\\Projects\\DICOM\\dicom");
	porter->SetInput(renWin);
	porter->Write();

/*	std::string filename = "out.stl";
	vtkSmartPointer<vtkOBJWriter> porter = vtkSmartPointer<vtkOBJWriter>::New();
	porter->SetFileName(filename.c_str());
	porter->SetInputConnection(volumeMapper->GetOutputPort());
	//porter->SetInputData(polyData);
	porter->Write();
	porter->Update();*/


	return EXIT_SUCCESS;

}

效果图

在这里插入图片描述

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值