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轴的信息。
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
VTK是一个强大的可视化工具库,可以用于三维图形渲染和处理。如果要在VTK中通过鼠标获取点云坐标,我们可以使用 vtkRenderWindowInteractor 类中的特定事件来捕获鼠标的位置信息: 1. 首先,创建一个 vtkRenderWindowInteractor 实例,并注册一个鼠标事件处理函数。 2. 在鼠标事件处理函数中,使用 GetMousePosition 方法获取鼠标当前的位置坐标。 3. 使用 vtkPicker 类获取鼠标所处位置的三维坐标。 以下是示例代码: ```c++ #include <vtkRenderWindowInteractor.h> #include <vtkRenderWindow.h> #include <vtkRenderer.h> #include <vtkGenericRenderWindowInteractor.h> #include <vtkPointPicker.h> #include <vtkSmartPointer.h> void MouseCallbackFunction(vtkObject* caller, long unsigned int vtkNotUsed(event), void* vtkNotUsed(clientData), void* vtkNotUsed(callData)) { vtkSmartPointer<vtkRenderWindowInteractor> iren = static_cast<vtkRenderWindowInteractor*>(caller); int* pos = iren->GetEventPosition(); vtkSmartPointer<vtkPointPicker> picker = vtkSmartPointer<vtkPointPicker>::New(); picker->Pick(pos[0], pos[1], 0, iren->GetRenderWindow()->GetRenderers()->GetFirstRenderer()); double* worldPosition = picker->GetPickPosition(); std::cout << "Picked world position (x,y,z) is: (" << worldPosition[0] << ", " << worldPosition[1] << ", " << worldPosition[2] << ")" << std::endl; } int main() { vtkSmartPointer<vtkGenericRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkGenericRenderWindowInteractor>::New(); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->SetWindowName("VTK Mouse Position Example"); renderWindow->SetSize(500, 500); renderWindowInteractor->SetRenderWindow(renderWindow); vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderWindow->AddRenderer(renderer); // create some simple 3D data (a single point in space) vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); double p[3] = { 1.0, 2.0, 3.0 }; points->InsertNextPoint(p); vtkSmartPointer<vtkPolyData> pointPolyData = vtkSmartPointer<vtkPolyData>::New(); pointPolyData->SetPoints(points); vtkSmartPointer<vtkVertexGlyphFilter> vertexFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New(); vertexFilter->SetInputData(pointPolyData); vertexFilter->Update(); vtkSmartPointer<vtkPolyDataMapper> pointMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); pointMapper->SetInputConnection(vertexFilter->GetOutputPort()); vtkSmartPointer<vtkActor> pointActor = vtkSmartPointer<vtkActor>::New(); pointActor->SetMapper(pointMapper); renderer->AddActor(pointActor); renderWindowInteractor->AddObserver(vtkCommand::MouseMoveEvent, MouseCallbackFunction); renderWindowInteractor->Initialize(); renderWindowInteractor->Start(); return EXIT_SUCCESS; } ``` 这个例子创建一个简单的单三维数据,并在界面上显示,然后用鼠标在该附近移动并输出当前鼠标位置的三维坐标。可以通过修改示例代码,将点云数据替换为自己的实际数据来实现获取鼠标位置对应的点云坐标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

简 。单

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值