使用VTK进行体绘制(ImageData)显示器件

vtkVolumeMapper的不同混合模式

不同的模式下会呈现出不同的渲染效果。注意vtkGPUVolumeRayCastMapper和vtkFixedPointVolumeRayCastMapper支持的模式不同。

例如:

  1. Composite混合模式:

    • 默认模式,通过体积采样并使用alpha混合算法从前到后合成标量值。
    • 使用颜色传输函数和不透明度传输函数确定最终的颜色和不透明度。
  2. Maximum混合模式:

    • 使用采样光线上的最大标量值。
    • 通过颜色传输函数和不透明度传输函数确定最终的颜色和不透明度。
  3. Minimum混合模式:

    • 使用采样光线上的最小标量值。
    • 通过颜色传输函数和不透明度传输函数确定最终的颜色和不透明度。
  4. Additive混合模式:

    • 累积标量值,将每个值通过不透明度传输函数,并将值乘以其不透明度进行相加。
    • 结果图像始终是灰度的,即聚合的值不经过颜色传输函数。
    • 最终的值是通过不透明度传输函数和累积计算得到的。
  5. Average intensity混合模式:

    • 类似于Additive混合模式,但是在求和之前将标量值乘以从不透明度传输函数计算得到的不透明度,并在求和后除以通过体积采样的数量。
    • 可通过设置AverageIPScalarRange来控制标量范围。
    • 最终的图像始终是灰度的,即聚合的值不经过颜色传输函数。
  6. IsoSurface混合模式:(vtkFixedPointVolumeRayCastMapper不支持)

    • 使用用户定义的等值面值,在光线穿过等值面时显示标量值。
    • 支持与Composite混合模式相同的不透明度处理方式。

数据特点

数据文件(txt)举例:

3 6 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1

格式说明:

这样的一串数字,3 6 3分别表示z,y,x方向格点数,后面的3*6*3个数字就是从第0层开始每个点的属性值。

注意:

  1. 是 z * y * x ;
  2. 这里的0、1、2代表不同的材料,0为空气,1为硅基底,2为多晶硅;
  3. 3 6 3 之后的数字是按照 x轴,y轴,z轴,逐个、逐行、逐层的顺序存储。

算法

光线投射体绘制算法:一种基于图像序列的直接体绘制方法,其基本原理是从投影图像平面的每个像素沿着视线方向发射一条穿过体数据的射线,然后在射线上按照一定的步长进行等距采样,对每个采样点采用插值技术计算其体素值,根据颜色传输函数和不透明度传输函数来获取相应的颜色值和不透明度,最后利用光线吸收模型将颜色值进行累加,直至光线穿过体数据,即可得到当前平面像素的渲染颜色,生成最终显示图像。

两个重要函数(颜色传输函数、不透明度传输函数):

	// 设置颜色
	vtkSmartPointer<vtkColorTransferFunction> colorFunction = vtkSmartPointer<vtkColorTransferFunction>::New();
	// 设置透明度
	vtkSmartPointer<vtkPiecewiseFunction> opacityFunction = vtkSmartPointer<vtkPiecewiseFunction>::New();

volumeProperty->SetInterpolationTypeToLinear();

使用线性插值计算比较符合我们的显示需求。

全部代码

这里使用的是默认模式。

int maxPointsX, maxPointsY, maxPointsZ;
	std::vector<int> datas;
	readFile(datas, maxPointsZ, maxPointsY, maxPointsX);
	vtkSmartPointer<vtkImageData> imageData = vtkSmartPointer<vtkImageData>::New();
	imageData->SetDimensions(maxPointsX, maxPointsY, maxPointsZ);//设置网格的尺寸
	imageData->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
	imageData->SetSpacing(1.0, 1.0, 1.0);//设置间距
	unsigned char* voxelData = static_cast<unsigned char*>(imageData->GetScalarPointer());
	int k = 0;
	for (int i = 0; i < maxPointsZ; ++i) {
		for (int j = 0; j < maxPointsY; ++j) {
			for (int l = 0; l < maxPointsX; ++l) {
				voxelData[k] = datas[k];
				k++;
			}
		}
	}
	vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper =
		vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
	volumeMapper->SetInputData(imageData);
	//volumeMapper->SetBlendModeToAverageIntensity();
	//volumeMapper->SetBlendModeToMinimumIntensity();
	vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();

	// 设置透明度
	vtkSmartPointer<vtkPiecewiseFunction> opacityFunction = vtkSmartPointer<vtkPiecewiseFunction>::New();
	opacityFunction->AddPoint(0, 0.0);
	opacityFunction->AddPoint(1, 1.0);
	opacityFunction->AddPoint(2, 1.0);
	volumeProperty->SetScalarOpacity(opacityFunction);

	// 设置颜色
	vtkSmartPointer<vtkColorTransferFunction> colorFunction = vtkSmartPointer<vtkColorTransferFunction>::New();
	colorFunction->AddRGBPoint(0, 0.0, 0.0, 0.0);
	colorFunction->AddRGBPoint(1, 1, 0, 0);
	colorFunction->AddRGBPoint(2, 0, 1, 0);
	volumeProperty->SetColor(colorFunction);

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

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

	vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(ren);
	rw->SetSize(640, 480);
	rw->Render();
	rw->SetWindowName("VolumeRendering PipeLine");

	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	rwi->SetRenderWindow(rw);

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

	rw->Render();
	rwi->Start();
	return 0;

效果图

 

 在不同的光照角度下,会呈现不同的效果。这一点并不是很符合要求。可以尝试soSurface混合模式,使用等值面法进行渲染。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用vtk.js实现绘制,可以按照以下步骤: 1. 加载数据:使用`vtkXMLImageDataReader`或`vtkHttpDataSetReader`来读取数据。这些读取器可以从本地文件或远程URL加载数据。 2. 创建渲染器和场景:使用`vtkRenderer`和`vtkRenderWindow`创建渲染器和场景。 3. 创建绘制器:使用`vtkVolume`和`vtkVolumeMapper`创建绘制器。`vtkVolumeMapper`将数据映射到绘制器中,并使用`vtkColorTransferFunction`和`vtkPiecewiseFunction`定义颜色和不透明度。 4. 将绘制器添加到场景中:使用`vtkRenderer`的`AddViewProp`方法将绘制器添加到渲染器中。 5. 渲染场景:使用`vtkRenderWindow`的`Render`方法将场景渲染到屏幕上。 下面是一个使用vtk.js实现绘制的示例代码: ```javascript // 加载数据 const reader = vtkXMLImageDataReader.newInstance(); reader.setUrl('data.vti'); reader.loadData().then(() => { const imageData = reader.getOutputData(0); // 创建渲染器和场景 const renderer = vtkRenderer.newInstance(); const renderWindow = vtkRenderWindow.newInstance(); renderWindow.addRenderer(renderer); // 创建绘制器 const volumeMapper = vtkVolumeMapper.newInstance(); volumeMapper.setInputData(imageData); const volume = vtkVolume.newInstance(); volume.setMapper(volumeMapper); const ctfun = vtkColorTransferFunction.newInstance(); ctfun.addRGBPoint(0, 0.0, 0.0, 0.0); ctfun.addRGBPoint(255, 1.0, 1.0, 1.0); const ofun = vtkPiecewiseFunction.newInstance(); ofun.addPoint(0, 0.0); ofun.addPoint(255, 1.0); volume.getProperty().setRGBTransferFunction(0, ctfun); volume.getProperty().setScalarOpacity(0, ofun); // 将绘制器添加到场景中 renderer.addVolume(volume); // 渲染场景 renderWindow.render(); }); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值