VTK学习笔记八

轮廓提取

  • 操作的是标量数据对象
  • 将数据集中标量值等于指定的值的部分提取出来;
  • 对于3D数据,提取出来的是一个等值面
  • 对于2D数据而言,提取出来的是一个等值线
  • 典型应用包括气象图中的等温线,地形图中的等高线
  • 对于医学图像而言,不同的标量值代表不同的组织或结构,可以提取人的皮肤或骨头
  • 使用过滤器vtkContourFilter来实现轮廓提取,可以接收任意类型的数据类型作为输入
  • vtkContourFilter还需要设置需要抽取的标量值,SetValue()和GenerateValues()

DEMO1 将polyData渲染成黑白图像后,对图像边界轮廓进行提取

其原理是将源对象数据设置成纯黑色,背景设置成纯白色,然后离屏渲染出一副黑白图像,在这幅图像上提取标量值为255的等值线,最终生成源对象当前视图的轮廓对象

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 


int main(int argc, char *argv[])
{
	vtkSmartPointer data3d;

	//创建程序源对象——球体
	vtkSmartPointer source = vtkSmartPointer::New();
	//设置球体的中心坐标
	source->SetCenter(0.0, 0.0, 5.0);
	//设置球体的半径
	source->SetRadius(2.0);
	//设置球体纬度方向上的点数
	source->SetPhiResolution(20.);
	//设置球体经度方向上的点数
	source->SetThetaResolution(20.);
	//手动触发流水线,执行生成源对象操作
	source->Update();

	//从程序源对象中获取多边形数据集polyData
	data3d = source->GetOutput();


	double bounds_data[6], center_data[3];
	//获取源对象的边界[Xmin,Xmax,Ymin,Ymax,Zmin,Zmax]
	data3d->GetBounds(bounds_data);
	//获取源对象的中心点[Xmin,Xmax,Ymin,Ymax,Zmin,Zmax]
	data3d->GetCenter(center_data);

	//将几何对象设置到映射器中
	vtkSmartPointer mapper_data = vtkSmartPointer::New();
	mapper_data->SetInputData(data3d);    

	vtkSmartPointer actor_data = vtkSmartPointer::New();
	actor_data->SetMapper(mapper_data);
	//将待渲染的演员对象设置成黑色
	actor_data->GetProperty()->SetColor(0,0,0);

	vtkSmartPointer tmp_rend = vtkSmartPointer::New();
	//将渲染背景渲染成白色
	tmp_rend->SetBackground(1,1,1);

	tmp_rend->AddActor(actor_data);
	tmp_rend->ResetCamera();
	//开启平行光投影
	tmp_rend->GetActiveCamera()->SetParallelProjection(1);

	vtkSmartPointer tmp_rW = vtkSmartPointer::New();
	//设置成离屏渲染
	tmp_rW->SetOffScreenRendering( 1 );
	tmp_rW->AddRenderer(tmp_rend);

	tmp_rW->Render();

	vtkSmartPointer windowToImageFilter = vtkSmartPointer::New();
	//获取离屏渲染的窗口图像
	windowToImageFilter->SetInput(tmp_rW);
#if VTK_MAJOR_VERSION >= 8 || VTK_MAJOR_VERSION == 8 && VTK_MINOR_VERSION >= 90
	windowToImageFilter->SetScale(2); // image quality
#else
	//设置当前渲染窗口的方法倍数
	windowToImageFilter->SetMagnification(2); //image quality
#endif
	//手动触发流水线
	windowToImageFilter->Update();

	// 提取图像黑白交界的轮廓
	vtkSmartPointer ContFilter = vtkSmartPointer::New();
	ContFilter->SetInputConnection(windowToImageFilter->GetOutputPort());
	//提取标量值为255的轮廓线,0表示第1条轮廓
	ContFilter->SetValue(0,255);
	ContFilter->Update();

	//获取轮廓数据集——POLYDATA
	vtkSmartPointer contour = ContFilter->GetOutput();

	double bounds_contour[6], center_contour[3];
	double trans_x=0., trans_y=0., trans_z=0., ratio_x=0., ratio_y=0.;
	contour->GetBounds(bounds_contour);

	//源对象XY方向的边界与轮廓对象XY方向边界的比值
	ratio_x = (bounds_data[1]-bounds_data[0])/(bounds_contour[1]-bounds_contour[0]);
	ratio_y = (bounds_data[3]-bounds_data[2])/(bounds_contour[3]-bounds_contour[2]);

	//调整边界对象的比例以适应源对象的边界
	vtkSmartPointertransform1 = vtkSmartPointer::New();
	transform1->Scale( ratio_x, ratio_y, 1.);

	vtkSmartPointer tfilter1 = vtkSmartPointer::New();
	tfilter1->SetInputData(contour);
	tfilter1->SetTransform(transform1);
	tfilter1->Update();

	contour = tfilter1->GetOutput();

    //平移轮廓对象以对齐程序源对象的中心
	contour->GetCenter(center_contour);
	trans_x = center_data[0]-center_contour[0];
	trans_y = center_data[1]-center_contour[1];
	trans_z = center_data[2]-center_contour[2];

	vtkSmartPointer transform2 = vtkSmartPointer::New();
	transform2->Translate( trans_x, trans_y, trans_z);

	vtkSmartPointer tfilter2 = vtkSmartPointer::New();
	tfilter2->SetInputData(contour);
	tfilter2->SetTransform(transform2);
	tfilter2->Update();

	contour = tfilter2->GetOutput();

	// 分两个viewport分别渲染程序源对象和轮廓对象

	// 重新设置程序源对象的颜色
	actor_data->GetProperty()->SetColor(0.9,0.9,0.8);

	// Create a mapper and actor of the silhouette
	vtkSmartPointer mapper_contour = vtkSmartPointer::New();
	mapper_contour->SetInputData(contour);

	vtkSmartPointer actor_contour = vtkSmartPointer::New();
	actor_contour->SetMapper(mapper_contour);
	actor_contour->GetProperty()->SetLineWidth(2.);

	// 2 renderers and a render window
	vtkSmartPointer renderer1 = vtkSmartPointer::New();
	renderer1->AddActor(actor_data);

	vtkSmartPointer renderer2 = vtkSmartPointer::New();
	renderer2->AddActor(actor_contour);

	vtkSmartPointer renderwindow = vtkSmartPointer::New();
	renderwindow->SetSize(400,400);

	renderwindow->AddRenderer(renderer1);
	renderer1->SetViewport(0., 0., 0.5, 1.);

	renderwindow->AddRenderer(renderer2);
	renderer2->SetViewport(0.5, 0., 1., 1.);

	vtkSmartPointer style = vtkSmartPointer::New();
	vtkSmartPointer iren = vtkSmartPointer::New();

	iren->SetRenderWindow( renderwindow);
	iren->SetInteractorStyle(style);

	renderwindow->Render();
	iren->Start();

	return EXIT_SUCCESS;
}

DEMO2 用一系列的裁剪平面来生成模型表面的轮廓线

其大致流程如下

  1. 取模型的中心点及z轴正半轴方向作为法向量构造一个vtkPlane对象
  2. 遍历模型所有的点,连接点与平面中心点构成向量,求该项量与平面法向量的点积,结果作为该点的属性值
  3. 将属性数组设置给模型的点集(注意ScalarVisibilityOff()一定加上,避免将属性当做颜色来处理了)
  4. 构建vtkContourFilter对象,将模型数据设置到数据源中,并根据属性的最大最小值GenerateValues生成指定的几个标量值
  5. 最终提取出指定的多个轮廓(其实就是获取了到平面距离为指定值的点集)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int main(int argc, char *argv[])
{
	vtkSmartPointer colors = vtkSmartPointer::New();

	//读取STL文件以创建读源对象 
	const char* inputFilename = "C:\\Users\\qiang.shen\\Desktop\\IronData\\XZW.stl";
	vtkSmartPointer reader = vtkSmartPointer::New();
	reader->SetFileName(inputFilename);
	//手动触发流水线,否则reader里面没有值
	reader->Update();

	//获取读源对象的轮廓[Xmin,Xmax, Ymin, Ymax, Zmin, Zmax]
	double bounds[6];
	reader->GetOutput()->GetBounds(bounds);
	std::cout << "Bounds: "
		<< bounds[0] << ", " << bounds[1] << " "
		<< bounds[2] << ", " << bounds[3] << " "
		<< bounds[4] << ", " << bounds[5] << std::endl;

	//创建一个平面程序源对象
	vtkSmartPointer plane = vtkSmartPointer::New();
	//平面对象是由点和法向量定义的,这里设置平面经过的源对象的中心点坐标
	plane->SetOrigin((bounds[1] + bounds[0]) / 2.0,
		(bounds[3] + bounds[2]) / 2.0,
		(bounds[5] + bounds[4]) / 2.0);
	//设置平面对象的法向量;
	plane->SetNormal(0,0,1);

	//创建一个double型的标量数组
	vtkSmartPointer scalars = vtkSmartPointer::New();
	//获取源对象的点数
	int numberOfPoints = reader->GetOutput()->GetNumberOfPoints();
	//分配numberOfPoints属性数据的空间
	scalars->SetNumberOfTuples(numberOfPoints);
	//获取源对象的点集
	vtkSmartPointer pts = reader->GetOutput()->GetPoints();
	std::vector aa;
	for (int i = 0; i < numberOfPoints; ++i)
	{
		double point[3];
		//获取点的坐标
		pts->GetPoint(i, point);
		//EvaluateFunction 评估点的平面方程(本质是求点point与平面中心点连接的向量在平面法向量上的投影)
		double evaValue = plane->EvaluateFunction(point);
		aa.push_back(evaValue);
		scalars->SetTuple1(i, evaValue);
	}
	reader->GetOutput()->GetPointData()->SetScalars(scalars);
	auto range = reader->GetOutput()->GetPointData()->GetScalars()->GetRange();

	// Create cutter
	vtkSmartPointer cutter = vtkSmartPointer::New();
	cutter->SetInputConnection(reader->GetOutputPort());
	cutter->ComputeScalarsOff();
	cutter->ComputeNormalsOff();
	int numberOfCuts = 10;
	//生成给定的标量值
	cutter->GenerateValues(numberOfCuts, 0.99 * range[0], 0.99 * range[1]);//设置需要抽取的标量值

	vtkSmartPointer cutterMapper = vtkSmartPointer::New();
	cutterMapper->SetInputConnection( cutter->GetOutputPort());
	//避免点的属性值被当做颜色来处理了
	cutterMapper->ScalarVisibilityOff();

	// Create cut actor
	vtkSmartPointer cutterActor = vtkSmartPointer::New();
	cutterActor->GetProperty()->SetColor(colors->GetColor3d("Banana").GetData());
	cutterActor->GetProperty()->SetLineWidth(2);
	cutterActor->SetMapper(cutterMapper);

	// Create model actor
	vtkSmartPointer modelMapper = vtkSmartPointer::New();
	modelMapper->SetInputConnection( reader->GetOutputPort());
	modelMapper->ScalarVisibilityOff();

	vtkSmartPointer modelActor = vtkSmartPointer::New();
	modelActor->GetProperty()->SetColor(colors->GetColor3d("Flesh").GetData());
	modelActor->SetMapper(modelMapper);

	// Create renderers and add actors of plane and model
	vtkSmartPointer renderer = vtkSmartPointer::New();
	renderer->AddActor(cutterActor);
	renderer->AddActor(modelActor);

	// Add renderer to renderwindow and render
	vtkSmartPointer renderWindow = vtkSmartPointer::New();
	renderWindow->AddRenderer(renderer);
	renderWindow->SetSize(600, 600);

	vtkSmartPointer interactor = vtkSmartPointer::New();
	interactor->SetRenderWindow(renderWindow);

	renderer->SetBackground(colors->GetColor3d("Burlywood").GetData());
	renderer->GetActiveCamera()->SetPosition(0, -1, 0);
	renderer->GetActiveCamera()->SetFocalPoint(0, 0, 0);
	renderer->GetActiveCamera()->SetViewUp(0, 0, 1);
	renderer->GetActiveCamera()->Azimuth(30);
	renderer->GetActiveCamera()->Elevation(30);

	renderer->ResetCamera();
	renderWindow->Render();

	interactor->Start();

	return EXIT_SUCCESS;
}

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