VTK:图形基本操作进阶——表面重建技术(三角部分)

1.表面重建

通过三维扫描仪所获取的实际物体的空间点云数据仅仅表示物体的集合形状,而无法表达其内部的拓扑结构。拓扑结构对于实际图形处理以及可视化具有重要的意义。因此,这就需要利用表面重建技术将点云数据转换成面模型,通常为三角网络模型。除此之外,基于图像数据的面绘制技术也是一种应用非常广泛的表面重建技术。

vtk中实现三角剖分技术

三角剖分技术是一种应用非常广泛的面重建技术。三角剖分将一些散乱的点云数据剖分为一系列的三角形网格。最常用的三角剖分技术为Delaunay三角剖分。Delaunay三角剖分具有许多优良的性质,如最大化最小角特性,即在所有可能的三角剖分中,其所生成的的三角形的最小角的角度最大。所以,Delaunay三角剖分无论从哪个区域开始构建,最终生成的三角网格还是唯一的。
VTK的vtkDelaunay2D类实现了二维三角剖分。该类的输入数据为一个vtkPointSet或其子类表示的三维空间点集,其输出为一个三角网格vtkPolyData数据。虽然输入的是三维数据,但是算法仅适用XY平面数据进行平面三角剖分,而忽略Z方向数据。当然,也可以为vtkDelaunay2D设置一个投影变换从而在新的投影平面上进行三角剖分。注意的是,再不添加任何限制条件下,该类生成的平面三角网格为一个凸包。

演示vtkDelaunay2D,将其生成的数据用于数据模型地形数据:

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkInteractionStyle);

#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkDelaunay2D.h>
#include <vtkMath.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>

int main()
{
	unsigned int gridSize = 10;//10*10的点矩阵
	vtkSmartPointer<vtkPoints> points =
		vtkSmartPointer<vtkPoints>::New();
	for (unsigned int x = 0; x < gridSize; x++)
	{
		for (unsigned int y = 0; y < gridSize; y++)
		{
			points->InsertNextPoint(x, y, vtkMath::Random(0.0, 3.0));
		}
	}

	vtkSmartPointer<vtkPolyData> polydata =
		vtkSmartPointer<vtkPolyData>::New();
	polydata->SetPoints(points);

	vtkSmartPointer<vtkDelaunay2D> delaunay =//二维三角部分输入为三维空间点集,该类生成的平面三角网格为一个凸包。
		vtkSmartPointer<vtkDelaunay2D>::New();
	delaunay->SetInputData(polydata);
	delaunay->Update();

	vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter =
		vtkSmartPointer<vtkVertexGlyphFilter>::New();
	glyphFilter->SetInputData(polydata);
	glyphFilter->Update();

	vtkSmartPointer<vtkPolyDataMapper> pointsMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	pointsMapper->SetInputData(glyphFilter->GetOutput());
	vtkSmartPointer<vtkActor> pointsActor =
		vtkSmartPointer<vtkActor>::New();
	pointsActor->SetMapper(pointsMapper);
	pointsActor->GetProperty()->SetPointSize(3);
	pointsActor->GetProperty()->SetColor(1, 0, 0);

	vtkSmartPointer<vtkPolyDataMapper> triangulatedMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	triangulatedMapper->SetInputData(delaunay->GetOutput());
	vtkSmartPointer<vtkActor> triangulatedActor =
		vtkSmartPointer<vtkActor>::New();
	triangulatedActor->SetMapper(triangulatedMapper);

	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	renderer->AddActor(pointsActor);
	renderer->AddActor(triangulatedActor);
	renderer->SetBackground(0, 0, 0);

	vtkSmartPointer<vtkRenderWindow> renderWindow =
		vtkSmartPointer<vtkRenderWindow>::New();
	renderWindow->AddRenderer(renderer);
	renderWindow->SetSize(640, 640);
	renderWindow->Render();
	renderWindow->SetWindowName("PolyData Delaunay2D");

	vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	renderWindowInteractor->SetRenderWindow(renderWindow);
	renderWindowInteractor->Start();

	return 0;
}

先定义一个vtkPolyData数据,并生成一个10*10的地面网格点集points以及每个点生成一个随机数,表示每个点的海拔值;然后将该数据作为vtkDelaunay2D对象的输入实现三角部分,即可得到一个地面的网格数据。

在这里插入图片描述

2.局部数据三角部分(带约束的三角平分)

vtkDelaunay2D还支持加入边界限制。用户需要设置另一个vtkPolyData数据,其内部的线段、闭合或者非闭合的线段集合将作为边界条件控制三角部分的过程。其中,组成这些边界的点的索引必须与原始的点集数据一致。加入边界条件后,最后的部分结果可能不在满足Delaunay准则。
加入一个多边形边界来限制三角部分。

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkInteractionStyle);

#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkMath.h>
#include <vtkPointData.h>
#include <vtkPolyData.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkProperty.h>
#include <vtkPolygon.h>
#include <vtkCellArray.h>
#include <vtkDelaunay2D.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

int main()
{
	vtkSmartPointer<vtkPoints> points =
		vtkSmartPointer<vtkPoints>::New();

	unsigned int gridSize = 10;
	for (unsigned int x = 0; x < gridSize; x++)
	{
		for (unsigned int y = 0; y < gridSize; y++)
		{
			points->InsertNextPoint(x, y, vtkMath::Random(0.0, 3.0));
		}
	}

	vtkSmartPointer<vtkPolyData> polydata =
		vtkSmartPointer<vtkPolyData>::New();
	polydata->SetPoints(points);
	//多边形
	vtkSmartPointer<vtkPolygon> poly =
		vtkSmartPointer<vtkPolygon>::New();
	poly->GetPointIds()->InsertNextId(32);
	poly->GetPointIds()->InsertNextId(42);
	poly->GetPointIds()->InsertNextId(43);
	poly->GetPointIds()->InsertNextId(44);
	poly->GetPointIds()->InsertNextId(45);
	poly->GetPointIds()->InsertNextId(35);
	poly->GetPointIds()->InsertNextId(25);
	poly->GetPointIds()->InsertNextId(24);
	poly->GetPointIds()->InsertNextId(23);
	poly->GetPointIds()->InsertNextId(22);

	vtkSmartPointer<vtkCellArray> cell =
		vtkSmartPointer<vtkCellArray>::New();
	cell->InsertNextCell(poly); //设计拓扑结构
	//边界约束
	vtkSmartPointer<vtkPolyData> boundary =
		vtkSmartPointer<vtkPolyData>::New();
	boundary->SetPoints(points);
	boundary->SetPolys(cell); //只显示具有拓扑结构部分

	vtkSmartPointer<vtkDelaunay2D> delaunay =
		vtkSmartPointer<vtkDelaunay2D>::New();
	delaunay->SetInputData(polydata);
	delaunay->SetSourceData(boundary); //约束源
	delaunay->Update();
	///
	vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter =
		vtkSmartPointer<vtkVertexGlyphFilter>::New();
	glyphFilter->SetInputData(polydata);
	glyphFilter->Update();

	vtkSmartPointer<vtkPolyDataMapper> pointsMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	pointsMapper->SetInputData(glyphFilter->GetOutput());
	vtkSmartPointer<vtkActor> pointsActor =
		vtkSmartPointer<vtkActor>::New();
	pointsActor->SetMapper(pointsMapper);
	pointsActor->GetProperty()->SetPointSize(8);
	pointsActor->GetProperty()->SetColor(1, 0, 0);

	vtkSmartPointer<vtkPolyDataMapper> triangulatedMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	triangulatedMapper->SetInputData(delaunay->GetOutput());
	vtkSmartPointer<vtkActor> triangulatedActor =
		vtkSmartPointer<vtkActor>::New();
	triangulatedActor->SetMapper(triangulatedMapper);
	//
	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	renderer->AddActor(pointsActor);
	renderer->AddActor(triangulatedActor);
	renderer->SetBackground(0, 0, 0);

	vtkSmartPointer<vtkRenderWindow> rw =
		vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(renderer);
	rw->SetSize(640, 480);
	rw->SetWindowName("PolyData By ConstrainedDelaunay2D");

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

	return 0;
}

在这里插入图片描述
定义一个vtkPolyData类型的数据boundary,其点数据与上例中的points一致。其单元数据为一个多边形。通过vtkDelaunay2D的setSourceData()函数设置边界数据,该边界多边形内部的数据并未进行三角部分。对于边界多边形限制数据的内部或者外部,与多边形点的顺序有关。这一采用右手坐标系,从Z轴向下看去,如果多边形的点顺序为逆时针,则仅对多边形内部数据进行剖分;而如果为顺时针方向,则对多边形外部数据进行剖分,此时该边界多边形可以看成一个孔洞。

3.vtkelaunay3D实现三维三角部分

该类的使用方法与vtkdelaunay2D基本一致,不同的是,三维三角部分得到的结果并非三角网格,二是四面体网格。因此,其输出数据的类型为vtkUnstructuredGrid,在未加入边界条件的三维三角部分通常也为一个凸包。

4.vtkVertexGlyphFilter

This filter throws away all of the cells in the input and replaces them with a vertex on each point. The intended use of this filter is roughly equivalent to the vtkGlyph3D filter, except this filter is specifically for
data that has many vertices, making the rendered result faster and less cluttered than the glyph filter. This filter may take a graph or point set as input.(此筛选器丢弃输入中的所有单元格,并将它们替换为每个点上的顶点。 此滤镜的预期用途大致相当于 vtkGlyph3D 滤镜,只是此滤镜专门用于
具有许多顶点的数据,使呈现的结果比字形过滤器更快,更不混乱。此筛选器可以采用图形或点集作为输入。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简 。单

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值