vtk粗配准及其变换


开发环境:

  1. Windows 11 家庭中文版
  2. Microsoft Visual Studio Community 2019
  3. VTK-9.3.0.rc0
  4. vtk-example
  5. 参考代码
  6. 目的:学习与总结

demo解决问题:基于标记点,两个点集在配准后的平均距离最小,要求输入两个点数必须相等,序号一致的点集,做线性变换。

关键类:vtkTransform、vtkTransformFilter、vtkLandmarkTransform

知识点
1. vtkMath::Add,此处仅用于创建两个点集合,target、sourse。参考链接
2. ShallowCopy:vtk的浅拷贝,共享对象。参考链接
3. transform相关的文章两篇:参考链接1、参考链接2
1)GetMatrix和GetUserMatrix的区别: getTransform和getUserTransform中加User与不加User的区别:不加User是当前actor相对与世界坐标的位置的变化矩阵的get、set;加User是指基于变换中的某一个阶段结果基础上再进行变换的矩阵获取,例如进行了两次变换,第二次变换就是基于第一次的结果基础上变换来的
2)vtkMatrix4x4与vtkTransform的区别: vtkMatrix4x4关注的是矩阵的数学运算(invert、multiply…)、矩阵获取(MatrixFromRotation、缩放与平移矩阵比较好推算)、元素设置(SetElement),重点在于矩阵数据结构本身;vtkTransform重点在于比较直接的视觉操作(缩放scale、旋转rotate、平移translate),多级变换的管理(Concatenate),可以看下官方接口说明:vtkMatrix4x4、vtkTransform
4. vtkLandmarkTransform:用于粗配准(初步对齐)参考链接
1)AlignFrames(frame2, frame1, transform);//把frame2向frame1靠拢

	landmarkTransform->SetSourceLandmarks(sourcePoints);landmarkTransform->SetTargetLandmarks(targetPoints)landmarkTransform->SetModeToRigidBody();landmarkTransform->Update();

2) 获取变换矩阵后传出,给外面的frame2使用

    vtkMatrix4x4* M = landmarkTransform->GetMatrix();transform->SetMatrix(M);

3) 通过显示结果或者输出文件观察线形变换后的位姿

  void ApplyTransform(vtkTransform* transform, std::string filename){vtkNew<vtkPolyData> polydata;CreatePolydata(polydata);vtkNew<vtkTransformFilter> transformFilter;transformFilter->SetInputData(polydata);transformFilter->SetTransform(transform);transformFilter->Update();vtkNew<vtkXMLPolyDataWriter> writer;writer->SetFileName(filename.c_str());writer->SetInputConnection(transformFilter->GetOutputPort());writer->Write();}

#include <vtkLandmarkTransform.h>
#include <vtkMath.h>
#include <vtkNew.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkTransform.h>
#include <vtkTransformFilter.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkXMLPolyDataWriter.h>namespace {
struct Frame
{Frame(float o[3], float x[3], float y[3], float z[3]){this->SetOrigin(o);this->SetXDirection(x);this->SetYDirection(y);this->SetZDirection(z);std::cout << "Origin: " << this->origin[0] << " " << this->origin[1] << " "<< this->origin[2] << std::endl;std::cout << "xDirection: " << this->xDirection[0] << " "<< this->xDirection[1] << " " << this->xDirection[2] << std::endl;std::cout << "yDirection: " << this->yDirection[0] << " "<< this->yDirection[1] << " " << this->yDirection[2] << std::endl;std::cout << "zDirection: " << this->zDirection[0] << " "<< this->zDirection[1] << " " << this->zDirection[2] << std::endl;}void ApplyTransform(vtkTransform* transform, std::string filename){vtkNew<vtkPolyData> polydata;CreatePolydata(polydata);vtkNew<vtkTransformFilter> transformFilter;transformFilter->SetInputData(polydata);transformFilter->SetTransform(transform);transformFilter->Update();vtkNew<vtkXMLPolyDataWriter> writer;writer->SetFileName(filename.c_str());writer->SetInputConnection(transformFilter->GetOutputPort());writer->Write();}void CreatePolydata(vtkPolyData* polydata){/** https://blog.csdn.net/liushao1031177/article/details/120809118static void Add(const float a[3], const float b[3], float c[3]){for (int i = 0; i < 3; ++i){c[i] = a[i] + b[i];}}*/vtkNew<vtkPoints> points;points->InsertNextPoint(this->origin);float x[3];vtkMath::Add(this->origin, this->xDirection, x);points->InsertNextPoint(x);float y[3];vtkMath::Add(this->origin, this->yDirection, y);points->InsertNextPoint(y);float z[3];vtkMath::Add(this->origin, this->zDirection, z);points->InsertNextPoint(z);polydata->SetPoints(points);vtkNew<vtkVertexGlyphFilter> vertexGlyphFilter;//单独的点是看不到的,需要转换成符号vertexGlyphFilter->AddInputData(polydata);vertexGlyphFilter->Update();//https://zhuanlan.zhihu.com/p/138080564polydata->ShallowCopy(vertexGlyphFilter->GetOutput());}void Write(std::string filename){vtkNew<vtkPolyData> polydata;CreatePolydata(polydata);vtkNew<vtkXMLPolyDataWriter> writer;writer->SetFileName(filename.c_str());writer->SetInputData(polydata);writer->Write();}float origin[3];float xDirection[3];float yDirection[3];float zDirection[3];void SetOrigin(float o[3]){this->origin[0] = o[0];this->origin[1] = o[1];this->origin[2] = o[2];}void SetXDirection(float direction[3]){vtkMath::Normalize(direction);this->xDirection[0] = direction[0];this->xDirection[1] = direction[1];this->xDirection[2] = direction[2];}void SetYDirection(float direction[3]){vtkMath::Normalize(direction);this->yDirection[0] = direction[0];this->yDirection[1] = direction[1];this->yDirection[2] = direction[2];}void SetZDirection(float direction[3]){vtkMath::Normalize(direction);this->zDirection[0] = direction[0];this->zDirection[1] = direction[1];this->zDirection[2] = direction[2];}
};void AlignFrames(Frame sourceFrame, Frame destinationFrame,vtkTransform* transform);
} // namespaceint main(int, char*[])
{//工程应用中,此处frame中构造的点可在renderViewer中进行点拾取后记录float frame1origin[3] = {0, 0, 0};float frame1XDirection[3] = {1, 0, 0};float frame1YDirection[3] = {0, 1, 0};std::cout << frame1YDirection[0] << " " << frame1YDirection[1] << " "<< frame1YDirection[2] << std::endl;float frame1ZDirection[3] = {0, 0, 1};Frame frame1(frame1origin, frame1XDirection, frame1YDirection,frame1ZDirection);frame1.Write("frame1.vtp");float frame2origin[3] = {0, 0, 0};float frame2XDirection[3] = {.707f, .707f, 0};float frame2YDirection[3] = {-.707f, .707f, 0};float frame2ZDirection[3] = {0, 0, 1};Frame frame2(frame2origin, frame2XDirection, frame2YDirection,frame2ZDirection);frame2.Write("frame2.vtp");vtkNew<vtkTransform> transform;AlignFrames(frame2, frame1, transform); // Brings frame2 to frame1// std::cout << *transform << std::endl;frame2.ApplyTransform(transform, "transformed.vtp");return EXIT_SUCCESS;
}namespace {
void AlignFrames(Frame sourceFrame, Frame targetFrame, vtkTransform* transform)
{//https://blog.csdn.net/q610098308/article/details/125362653// This function takes two frames and finds the matrix M between them.//两个点集在配准后的平均距离最小,要求输入两个点数必须相等,序号一致的点集,做线性变换。它常用于粗略匹配,效率高。vtkNew<vtkLandmarkTransform> landmarkTransform;// Setup source pointsvtkNew<vtkPoints> sourcePoints;sourcePoints->InsertNextPoint(sourceFrame.origin);float sourceX[3];vtkMath::Add(sourceFrame.origin, sourceFrame.xDirection, sourceX);sourcePoints->InsertNextPoint(sourceX);float sourceY[3];vtkMath::Add(sourceFrame.origin, sourceFrame.yDirection, sourceY);sourcePoints->InsertNextPoint(sourceY);float sourceZ[3];vtkMath::Add(sourceFrame.origin, sourceFrame.zDirection, sourceZ);sourcePoints->InsertNextPoint(sourceZ);// Setup target pointsvtkNew<vtkPoints> targetPoints;targetPoints->InsertNextPoint(targetFrame.origin);float targetX[3];vtkMath::Add(targetFrame.origin, targetFrame.xDirection, targetX);targetPoints->InsertNextPoint(targetX);float targetY[3];vtkMath::Add(targetFrame.origin, targetFrame.yDirection, targetY);targetPoints->InsertNextPoint(targetY);float targetZ[3];vtkMath::Add(targetFrame.origin, targetFrame.zDirection, targetZ);targetPoints->InsertNextPoint(targetZ);landmarkTransform->SetSourceLandmarks(sourcePoints);landmarkTransform->SetTargetLandmarks(targetPoints);landmarkTransform->SetModeToRigidBody();landmarkTransform->Update();vtkMatrix4x4* M = landmarkTransform->GetMatrix();transform->SetMatrix(M);
}
} // namespace

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/131956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Redis 速通】Redis 在 Linux 上的单机服务快速搭建与部署(附完整流程步骤及命令代码)

Redis 单机版安装与部署 Written By: Xinyao Tian 概述 本文档主要描述了 Redis 的生产环境安装及配置方法。 主要步骤 编译及安装 进入 root 用户并上传 Redis 源码安装包 查看 Redis 源码安装包的上传情况: [rootcentos-host redis]# pwd /opt/redis [root centos-ho…

2023.11.6-分析 Gateway 和 VirtualService

2023.11.6-分析 Gateway 和 VirtualService 目录 本节实战 实战名称 正文 前面我们创建了一个 Gateway 和 VirtualService 对象&#xff0c;用来对外暴露应用&#xff0c;然后我们就可以通过 ingressgateway 来访问 Bookinfo 应用了。那么这两个资源对象是如何实现的呢&…

【0基础学Java第七课】-- 类和对象01

7. 类和对象 7.1 面向对象的初步认知7.1.1 什么是面向对象7.1.2 面向对象与面向过程 7.2 类定义和使用7.2.1 简单认识类7.2.2 类的定义格式7.2.3 定义一个狗类7.2.4 定义一个学生类 7.3 类的实例化7.3.1 什么是实列化7.3.2 引用只能指向对象&#xff0c;且不能同时指向多个对象…

数据库基础面试——索引

1.索引了解吗&#xff1f;简单介绍一下 索引是一种用于快速查询和检索数据的数据结构。 索引的作用 数据库中数据存储在磁盘&#xff0c;磁盘的顺序查询速度是很慢的&#xff0c;所以的顺序查找指的是读取磁盘中的数据⼀条⼀条的进⾏查找。索引就是为了避免顺序查询&#xf…

运动重定向:TeachNet

Vision-based Teleoperation of Shadow Dexterous Hand using End-to-End Deep Neural Network解析 摘要1. 简介2. Related Work2.1 基于视觉的无标记远程操作2.2 基于深度的3D手部姿势估计2.3 远程操作中的主从配对2.4 遥操作映射方法 3. 师生网络Joint angle lossConsistency…

Python基础入门例程43-NP43 判断布尔值(条件语句)

最近的博文&#xff1a; Python基础入门例程42-NP42 公式计算器&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程41-NP41 二进制位运算&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程40-NP40 俱乐部的成员&#xff08;运算符&#xff09;-CSDN博客…

springboot 连接西门子plc,读取对应的值,并修改到数据库

springboot 连接西门子plc&#xff0c;读取对应的值&#xff0c;并修改到数据库 需求&#xff1a;服务器连接plc&#xff0c;读取数据&#xff0c;之后写入到数据库&#xff0c;但是要求速度很快&#xff0c;而且plc中命令对应的值是不断变化的&#xff0c;这个变化&#xff0c…

Android Framework学习之Activity启动原理

Android Activity启动原理 Android 13.0 Activity启动原理逻辑流程图如下&#xff1a;

每天五分钟计算机视觉:搭建手写字体识别的卷积神经网络

本文重点 我们学习了卷积神经网络中的卷积层和池化层,这二者都是卷积神经网络中不可缺少的元素,本例中我们将搭建一个卷积神经网络完成手写字体识别。 卷积和池化的直观体现 手写字体识别 手写字体的图片大小是32*32*3的,它是一张 RGB 模式的图片,现在我们想识别它是从 …

Kubernetes rancher、prometheus、ELK的安装

目录 一、rancher的安装1. 添加 Helm Chart 仓库2. 为 Rancher 创建命名空间3. 选择 SSL 配置4. 安装 cert-manager 二、prometheus安装三、EFK安装 一、rancher的安装 有关rancher的安装其实官方网站给的步骤已经很详细了&#xff0c;可以直接按照步骤安装即可。 1. 添加 He…

【快速解决】Android Studio ERROR: Read timed out

目录 前言 回顾我查到过的解决方案&#xff08;这里是我自己解决时候的经历&#xff0c;赶时间的可以直接跳过看文章最后&#xff0c;快速进行解决&#xff09; 快速解决方案如下 总结 前言 当我们新建一个安卓项目出现Read timed out时候不要慌&#xff0c;这篇文章会打开…

前端的几种网络请求方式

网络请求 node编写接口 这里用到的几个包的作用 express&#xff1a;基于 Node.js 平台&#xff0c;快速、开放、极简的 Web 开发框架&#xff0c;官网&#xff1a;https://www.expressjs.com.cn/cors&#xff1a;用来解决跨域问题body-parser&#xff1a;可以通过 req.body…

AFL入门教学

1、AFL简介 AFL&#xff08;American Fuzzy Lop&#xff09;是一个面向安全的模糊测试工具&#xff0c;它使用了一个新的编译时插桩技术和遗传算法&#xff0c;可以自动发现触发目标二进程程序的测试用例&#xff0c;从而大大提高测试代码的功能覆盖率。 AFL官网&#xff1a;…

mac装不了python3.7.6

今天发现一个很奇怪的问题 但是我一换成 conda create -n DCA python3.8.12就是成功的 这个就很奇怪

20.有效的括号

原题链接&#xff1a;20.有效的括号 看到这种需要双双匹配的题目&#xff0c;就感觉可以使用栈来做 题目要求是&#xff1a; 1.左括号必须用相同类型的右括号闭合。 2.左括号必须以正确的顺序闭合。 3.每个右括号都有一个对应的相同类型的左括号。 还需要注意 栈为空的时候插…

RocketMQFoundation

RocketMQFoundation 一. RocketMQ 消息队列1.1 初始化1.1.1 下载 4.9.41.1.2 配置环境变量1.1.3 启动1.1.3.1 启动 mqnamesrv.cmd1.1.3.2 启动 mqbroker.cmd -n localhost:98761.1.3.3 封装启动命令1.1.3.4 占用内存过高1.1.4 rocketmq-dashboard 仪表盘 可视化界面1.1.4.1 启动…

Python基础入门例程40-NP40 俱乐部的成员(运算符)

最近的博文&#xff1a; Python基础入门例程39-NP39 字符串之间的比较&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程38-NP38 牛牛的逻辑运算&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程37-NP37 不低于与不超过&#xff08;运算符&#xff0…

c++中httplib使用

httplib文件链接:百度网盘 请输入提取码 提取码:kgnq json解析库:百度网盘 请输入提取码 提取码:oug0 一、获取token 打开postman, 在body这个参数中点击raw,输入用户名和密码 然后需要获取到域名和地址。 c++代码如下: #include "httplib.h" #in…

Linux环境基础开发工具使用(二)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、Linux项目自动化构建工具-make/Makefile1、背景2、实例代码3、依赖关系4、依赖方法5、原理…

pytorch3D Windows下安装经验总结

一、说明及准备工作 最近在安装pytorch3D的时候遇到了很多问题&#xff0c;查了很多博客&#xff0c;但发现讲的都不太全&#xff0c;所以特将自己的及收集到的安装过程经验总结如下。我是在Anaconda中虚拟环境下安装的。 1.1准备工作 官方安装教程如下&#xff1a;https://…