VTK:图形基本操作进阶——点云配准技术(LandMark标记点算法和坐标系显示方法)

1.点配准

在计算机逆向工程中,通过三维扫描等实物数字化技术可以获取各种点云数据。但是受到测量环境和设备的影响,再一次测量的情况下,难以获得实物整体的点云数据,因此需要多次从不同的角度进行测量。但是不同测量数据之间可能会存在平移错误或旋转错位等问题。这就是使用点云配准技术来对测量点云数据进行局部配准的整合,以得到完整的模型数据。
另外,在外科手术导航技术中,图像标记技术与人体表面标记点的配准是一个关键步骤,对于手术定位的精度有着重要的影响。通常这需要使用基于标记点的配准技术。因此,点云配准及时对一组源云数据应用一个空间转换,使得变换后的数据与目标点云数据能够一一映射,使两组数据之间的平均距离误差最小。

2.LandMark配准实验

VTKLandMarkTransform实现了片几点配准算法,使得两个点集在配准后平均距离最小。通过SetSourceLandmarks()设置源标记点的位置,SetTargetLandmarks()函数设计目标标记点的位置。需要注意的是源标记点集和目标标记点集序号要对应。

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

#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkLandmarkTransform.h>
#include <vtkPolyData.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkAxesActor.h>
//研究一下坐标系显示位置
#include <vtkOrientationMarkerWidget.h>
int main()
{
	vtkSmartPointer<vtkPoints> sourcePoints =
		vtkSmartPointer<vtkPoints>::New();
	double sourcePoint1[3] = { 0.5, 0, 0 };
	sourcePoints->InsertNextPoint(sourcePoint1);
	double sourcePoint2[3] = { 0, 0.5, 0 };
	sourcePoints->InsertNextPoint(sourcePoint2);
	double sourcePoint3[3] = { 0, 0, 0.5 };
	sourcePoints->InsertNextPoint(sourcePoint3);

	vtkSmartPointer<vtkPoints> targetPoints =
		vtkSmartPointer<vtkPoints>::New();
	double targetPoint1[3] = { 0.0, 0.0, 0.55 };
	targetPoints->InsertNextPoint(targetPoint1);
	double targetPoint2[3] = { 0.0, 0.55, 0.0 };
	targetPoints->InsertNextPoint(targetPoint2);
	double targetPoint3[3] = { -0.55, 0.0, 0.0 };
	targetPoints->InsertNextPoint(targetPoint3);
	//利用Landmark算法求变换矩阵
	vtkSmartPointer<vtkLandmarkTransform> landmarkTransform =
		vtkSmartPointer<vtkLandmarkTransform>::New();
	landmarkTransform->SetSourceLandmarks(sourcePoints);
	landmarkTransform->SetTargetLandmarks(targetPoints);
	landmarkTransform->SetModeToRigidBody(); //执行刚体配准
	landmarkTransform->Update();
	
	//构造PolyData类型 进行图形可视化
    vtkSmartPointer<vtkPolyData> source =
		vtkSmartPointer<vtkPolyData>::New();
	source->SetPoints(sourcePoints);
	vtkSmartPointer<vtkPolyData> target =
		vtkSmartPointer<vtkPolyData>::New();
	target->SetPoints(targetPoints);
	//
		vtkSmartPointer<vtkVertexGlyphFilter> sourceGlyphFilter =
		vtkSmartPointer<vtkVertexGlyphFilter>::New();
	sourceGlyphFilter->SetInputData(source);
	sourceGlyphFilter->Update();

	vtkSmartPointer<vtkVertexGlyphFilter> targetGlyphFilter =
		vtkSmartPointer<vtkVertexGlyphFilter>::New();
	targetGlyphFilter->SetInputData(target);
	targetGlyphFilter->Update();
	
	//源数据施加配准变换矩阵
	vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter =
		vtkSmartPointer<vtkTransformPolyDataFilter>::New();
	transformFilter->SetInputData(sourceGlyphFilter->GetOutput());
	transformFilter->SetTransform(landmarkTransform);
	transformFilter->Update();
	//
	vtkSmartPointer<vtkPolyDataMapper> sourceMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	sourceMapper->SetInputConnection(sourceGlyphFilter->GetOutputPort());

	vtkSmartPointer<vtkActor> sourceActor =
		vtkSmartPointer<vtkActor>::New();
	sourceActor->SetMapper(sourceMapper);
	sourceActor->GetProperty()->SetColor(1, 1, 0);
	sourceActor->GetProperty()->SetPointSize(10);

	vtkSmartPointer<vtkPolyDataMapper> targetMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	targetMapper->SetInputConnection(targetGlyphFilter->GetOutputPort());

	vtkSmartPointer<vtkActor> targetActor =
		vtkSmartPointer<vtkActor>::New();
	targetActor->SetMapper(targetMapper);
	targetActor->GetProperty()->SetColor(0, 1, 0);
	targetActor->GetProperty()->SetPointSize(10);

	vtkSmartPointer<vtkPolyDataMapper> solutionMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	solutionMapper->SetInputConnection(transformFilter->GetOutputPort());

	vtkSmartPointer<vtkActor> solutionActor =
		vtkSmartPointer<vtkActor>::New();
	solutionActor->SetMapper(solutionMapper);
	solutionActor->GetProperty()->SetColor(1, 0, 0);
	solutionActor->GetProperty()->SetPointSize(10);

	vtkSmartPointer<vtkRenderer> render =
		vtkSmartPointer<vtkRenderer>::New();
	render->AddActor(sourceActor);
	render->AddActor(targetActor);
	render->AddActor(solutionActor);
	render->SetBackground(0, 0, 0);

	vtkSmartPointer<vtkRenderWindow> rw =
		vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(render);
	rw->SetSize(480, 480);
	rw->SetWindowName("Regisration by Landmark");
	//设置坐标系显示功能
	vtkSmartPointer<vtkAxesActor> axes =
		vtkSmartPointer<vtkAxesActor>::New();
	axes->SetScale(10);
	render->AddActor(axes);

	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	rwi->SetRenderWindow(rw);
	/************************************************************/
	vtkSmartPointer<vtkOrientationMarkerWidget> widget =
		vtkSmartPointer<vtkOrientationMarkerWidget>::New();
	widget->SetOutlineColor(0.9300, 0.5700, 0.1300);
	widget->SetOrientationMarker(axes);
	widget->SetInteractor(rwi); //加入鼠标交互
	widget->SetViewport(0.0, 0.0, 0.3, 0.3);  //设置显示位置
	widget->SetEnabled(1);
	widget->InteractiveOn();//开启鼠标交互
	/************************************************************/
	render->ResetCamera();
	rw->Render();
	rwi->Initialize();
	rwi->Start();

	return 0;
}

黄色散点代表代表配准点集;绿色散点代表金标准;红色散点代表施加变换矩阵后的源数据点集。
vtkVertexGliphFilter类显示点集!VTKTransformPolyDataFilter用来对源点标记点进行变换来显示配准后的点集,SetTransform()函数直接设置为vtkLandmarkTransform的变换结果。
在这里插入图片描述

2.VTKLandmarkTransform类

VTKLandmarkTraTransform类的使用比较简单,只要设定源标记点和目标标记点。SetModeToRigidBody()函数用于设置其配准变换类型为刚体变换,仅包括简单的平移和转换(6个自由的角度)。此外还有一个更为钢钒应用的函数——SetModeToSimilarity,设置为相似变换,包括平移、旋转和放缩变换(7个自由度)。以及SetModeToAffine()函数设置放射变换。默认情况,就采用相似变化进行配准。

3.vtkAxesActor类

在显示三维物体时,我们只希望知道当前对应的坐标位置或者方向,这样在旋转物体的时候,就能够很清楚地看见当前正对 //设置坐标系显示功能

vtkSmartPointer<vtkAxesActor> axes =
	vtkSmartPointer<vtkAxesActor>::New();
axes->SetScale(10);
render->AddActor(axes);视野的XY平面,或者是Y轴的信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

简 。单

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

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

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

打赏作者

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

抵扣说明:

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

余额充值