VTK_Learning_圖形基本操作進階_表面重建技術(三角剖分)

1.表面重建

通過三維掃描儀所獲取的實際物體的空間點雲數據僅僅表示物體的幾何形狀,而無法表達其內部的拓撲結構。拓撲結構對於實際圖形處理以及可視化具有更重要的意義。因此,這就需要利用表面重建技術獎點雲數據轉換成面模型,通常爲三角網格模型。除此之外,基於圖像數據的面繪製技術也是一種應用非常廣泛的表面重建技術。


2.VTK中實現三角剖分技術

三角剖分技術是一種應用非常廣泛的面重建技術。三角剖分將一些散亂的點雲數據剖分爲一系列的三角形網格。最常用的三角剖分技術爲Delaunay三角剖分。Delaunay三角剖分具有許多優良的性質,如最大化最小角特性,即在所有可能的三角剖分中,其所生成的的三角形的最小角的角度最大。所以,Delaunay三角剖分無論從哪個區域開始構建,最終生成的三角網格還是唯一的。
VTK的vtkDelaunay2D類實現了二維三角剖分。該類的輸入數據爲一個vtkPointSet或其子類表示的三維空間點集,其輸出爲一個三角網格vtkPolyData數據。雖然輸入的是三維數據,但是算法僅適用XY平面數據進行平面三角剖分,而忽略Z方向數據。當然,也可以爲vtkDelaunay2D設置一個投影變換從而在新的投影平面上進行三角剖分。需要注意的是,再不添加任何限制條件下,該類生成的平面三角網格爲一個凸包。
下例演示如何使用vtkDelaunay2D,將其生成的數據用於模型地形數據:
 

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
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;
	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對象的輸入實現三角剖分,即可得到一個地面的網格數據。

輸出結果如下所示:

3.局部數據三角剖分(帶約束的三角平分)

vtkDelaunay2D還支持加入邊界限制。用戶需要設置另外一個vtkPolyData數據,其內部的線段、閉合或者非閉合的線段集合將作爲邊界條件控制三角剖分的過程。其中,組成這些邊界的點的索引必須與原始點集數據一致。加入邊界條件後,最後的剖分結果可能不在滿足Delaunay準則。
下面的例子,是在上例的基礎上,加入一個多變形邊界來限制三角剖分:
 

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
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軸向下看去,如果多邊形的點順序爲逆時針,則僅對多邊形內部數據進行剖分;而如果爲順時針方向,則對多邊形外部數據進行剖分,此時該邊界多邊形可以看成一個孔洞。

4.vtkelaunay3D實現三維三角剖分

VTK的vtkDelaunay3D類可實現三維三角剖分。該類的使用方法與vtkDelaunay2D基本一致,不同的是,三維三角剖分得到的結果並非三角網格,而是四面體網絡。因此,其輸出數據的類型爲vtkUnstructuredGrid,在未加入邊界條件下的三維三角剖分通常也爲一個凸包。


5.簡述類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.
 

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