拉普拉斯网格变形实现

news/2024/7/7 21:11:34/文章来源:https://www.cnblogs.com/nanjofish/p/18277158

因为课题需要,除了RBF还做了一个Laplace网格变形,其他大佬已经把原理写的很详细了,我就简单介绍一下公式,主要还是写写实现过程。过程同样参考了大佬的部分代码,而且实现的时候刚开始敲代码不久,所以有点乱QAQ。

首先,计算离散拉普拉斯坐标,网格上的点vi的拉普拉斯坐标δi为:

\[\delta_{i}=v_{i}-\sum_{j \in N(i)} \omega_{i j} v_{j} \]

式中,ωij为点vj相对vi的权值,如图所示,点vj就是点vi的邻接点。本文实现的权值有均匀权值和余切权值。

均匀权值的计算公式为:

\[\mathit{\omega {\tiny ij} }=\frac{1}{d{\tiny i} } \]

di就是邻接顶点的数量,代码也相对于余切权值简单不少,但是变形效果较差。

余切权值的计算公式为:

\[\mathit{\omega {\tiny ij} }=\frac{\cot \alpha {\tiny ij} +\cot \beta {\tiny ij} }{2 } \]

αijβij其实就是边ij的两个对角,如图所示:

然后,根据输入的待变形顶点点集,移动点点集和固定点点集,构建拉普拉斯矩阵,然后通过求解一个线性方程组就可以获取变形后的顶点位置:

\[Lv_{}^{\prime } = \Delta \]

其中,L就是拉普拉斯矩阵,v为变形后的顶点,Δ为拉普拉斯坐标矩阵,剩下的流程在代码里说明。

首先是构建权值矩阵:

void Laplace::calculateCotValue(Vector3d A, Vector3d B, Vector3d C,double &cotValue)
{Eigen::Vector3d Vab = B - A;Eigen::Vector3d Vac = C - A;double cosValue = Vab.dot(Vac) / (Vab.norm() * Vac.norm());double sinValue = (Vab.cross(Vac)).norm() / (Vab.norm() * Vac.norm());cotValue = cosValue / sinValue;
}
void Laplace::baseCotWeight(STLModel* p_STL)
{double smoothingFactor = 0.0001;  // 光顺因子/*-------------------------*///建立邻接表int Vert_num = this->m_DeforPoint.size();//参与变形的数量int Move_num = this->m_MoveIndex.size();//移动锚点的数量int Fix_num = this->m_FixPoint.size();//固定锚点的数量unordered_set<BaseStruct::PVERT> Jud;//用于判断变形点是否为所选择的点for (auto it : this->m_DeforPoint){Jud.insert(it);}Weight.resize(Vert_num, Vert_num);L.resize(Vert_num, Vert_num);Ls.resize(Vert_num, Vert_num);/*------------------邻接点赋值为wij,i点处赋值为1,其他非邻接赋值为0------------------*/typedef Eigen::Triplet<double> T_Cot;//创造三元组记录余切值std::vector<T_Cot> tripletList;for (int i = 0;i < Vert_num;i++){BaseStruct::PVERT temp_vert = this->m_DeforPoint[i];BaseStruct::PHEDGE start = temp_vert->pHEdgeOut->pHEdgeNext;BaseStruct::PHEDGE now = start;double sum_weight = 0.0; //权值总和map<unsigned int, double>vWeight;do{//确定点ABCPVERT Target = now->pHEdgePair->pVertEnd;double cotValue;double cotValue1;double cotValue2;Eigen::Vector3d A(now->pVertEnd->x, now->pVertEnd->y, now->pVertEnd->z);Eigen::Vector3d B(now->pHEdgePair->pVertEnd->x, now->pHEdgePair->pVertEnd->y, now->pHEdgePair->pVertEnd->z);Eigen::Vector3d C(now->pHEdgeNext->pVertEnd->x, now->pHEdgeNext->pVertEnd->y, now->pHEdgeNext->pVertEnd->z);Eigen::Vector3d D(now->pHEdgePair->pHEdgeNext->pVertEnd->x, now->pHEdgePair->pHEdgeNext->pVertEnd->y, now->pHEdgePair->pHEdgeNext->pVertEnd->z);calculateCotValue(B, A, C, cotValue1);calculateCotValue(B, A, D, cotValue2);cotValue = (0.5) * (cotValue1 + cotValue2 + epsilon);if (Jud.find(Target) != Jud.end()){vWeight.insert(pair<unsigned int, double>(now->pHEdgePair->pVertEnd->index, cotValue));sum_weight += cotValue;}now = now->pHEdgePair->pHEdgePre;} while (start != now);for (map< unsigned int, double>::iterator it = vWeight.begin();it!=vWeight.end();it++){double cotvalue =  it->second / sum_weight;tripletList.push_back(T_Cot(temp_vert->index, it->first, -cotvalue));}tripletList.push_back(T_Cot(temp_vert->index, temp_vert->index, 1));}	Weight.setFromTriplets(tripletList.begin(), tripletList.end());Ls = L = Weight;Ls.conservativeResize(Vert_num + Fix_num + Move_num, Vert_num);//添加锚点/*-------------------------------------------------------*///计算Ls和LsT、LsTLs/*-------------------------------------------------------*/for (int a = 0;a < this->m_FixPoint.size();a++){Ls.coeffRef(a + Vert_num, this->m_FixPoint[a]->index) = 1;}int a = 0;for (auto it : m_MoveIndex){Ls.coeffRef(a +Vert_num+Fix_num, it) = 1;a++;}LsT = Ls.transpose();LsTLs = LsT * Ls;

这段代码中,第二个for循环就是计算拉普拉斯矩阵的主要部分,这部分我用到的方法基于半边结构实现的,而且写的很乱,但是逻辑就是前面介绍的余切权值计算方法。计算完网格的拉普拉斯矩阵L后,再构建加入固定点和变形点的拉普拉斯矩阵Ls,最后求转置再相乘的原因是为了让其可逆,以便等等能够求解变形后的顶点坐标。

void Laplace::BuildLsTb(STLModel* p_STL)
{/*----------顶点、移动点、固定点数量-------------*/const int move_anchors_num = Move_anchor_coor.size(); const int Vext_num = this->m_DeforPoint.size();const int Fix_num = this->m_FixPoint.size();//固定锚点的数量/*-----------计算拉普拉斯坐标B-------------------*/vx.resize(Vext_num);vy.resize(Vext_num);vz.resize(Vext_num);//每一个顶点x,y,z坐标for (int i = 0;i < Vext_num;i++){vx.coeffRef(i) = this->m_DeforPoint[i]->x;vy.coeffRef(i) = this->m_DeforPoint[i]->y;vz.coeffRef(i) = this->m_DeforPoint[i]->z;}bx = L * vx; by = L * vy; bz = L * vz;//变形前的拉普拉斯坐标值bx.conservativeResize(Vext_num + Fix_num + move_anchors_num);by.conservativeResize(Vext_num + Fix_num + move_anchors_num);bz.conservativeResize(Vext_num + Fix_num + move_anchors_num);// 用形变后坐标对移动锚点坐标进行赋值int i = 0;for (auto it : this->m_FixPoint){bx.coeffRef(Vext_num + i) = it->x;by.coeffRef(Vext_num + i) = it->y;bz.coeffRef(Vext_num + i) = it->z;i++;}for (int i = 0;i < move_anchors_num;i++){bx.coeffRef(Vext_num + Fix_num + i) = Move_anchor_coor[i].x;by.coeffRef(Vext_num + Fix_num + i) = Move_anchor_coor[i].y;bz.coeffRef(Vext_num + Fix_num + i) = Move_anchor_coor[i].z;}LsTbx = LsT * bx;LsTby = LsT * by;LsTbz = LsT * bz;
}

这一段代码目的很明确,就是计算网格顶点变形前的拉普拉斯坐标,并构建坐标矩阵。

void Laplace :: LaplaceDeformation(STLModel* p_STL)
{LsTLs.makeCompressed();SparseLU<SparseMatrix<double>> LU;LU.analyzePattern(LsTLs);LU.factorize(LsTLs);LU.info();vx_New = LU.solve(LsTbx);vy_New = LU.solve(LsTby);vz_New = LU.solve(LsTbz);
}

然后计算变形后的坐标值,这里我把x,y,z三个值分别拿出来进行计算,根据计算公式,最后求解Ax=b这个线性方程组,求解结果就是每个顶点对应的新坐标值,最后将其赋值给变形点就完成了整个变形。

变形效果如图,变形前:

变形后:

效果还是不错的。

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

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

相关文章

文本三剑客之grep和awk

文本三剑客之grep和awk 目录文本三剑客之grep和awk 一、grep命令 grep命令的语法:grep[选项]...查找条件 目标文件命令 作用-m数字 多个匹配只取第一个-v 取反-i 忽略大小写-n 显示匹配的行号-c 统计匹配的行数-o 仅显示匹配到的字符串-A 数字 匹配后几行-B 数字 匹配前几行-C…

shell之条件测试语句

shell之条件测试语句 目录shell之条件测试语句一、test命令或[]中括号判断1、test命令2、[]中括号2.1 整数值比较[]2.2 实例操作2.2.1 查看系统内存是否超出预定值2.2.2 比较两个数的大小2.3 字符串比较2.3.1 案例:判断字符串是否相同2.3.2 案例:判断字符串是否为空2.4 逻辑测…

ikbc poker 2说明书

Poker II电子版说明书这是带6个dip开关,type-c接口,背后有理线槽支持侧向出线的一款poker。背后的金属铭牌型号为Poker Ⅱ。ikbc官网已经没有poker相关的内容了,说明书固件都无从下载。这份电子版说明书是找客服要的,这里存一下以作备份。原文档链接:ikbc_poker_II_说明书…

Django数据库

一、MySQL驱动程序安装 我们使用Django来操作MySQL,实际上底层还是通过python来操作的。因此我们想要用Django来操作MySQL,首先还是需要安装一个驱动程序。在Python3中,驱动程序有多种选择。比如pymysql以及mysqlclient等。这里我们就使用mysqlclient来操作。mysqlclient安装…

最后两次oop作业总结

1.前言 最后两次作业(即第七八次作业)大题目都是家居强电电路模拟程序,每次作业分别给了一个礼拜的时间去完成,题量较少,难度逐渐升高,以下为依次对两周题目集的知识点,题量和难度进行概述:第六次作业: 第六次作业只有一道题 家居强电电路模拟程序3,题目大概是输入设…

日志采集/分析

目录EFK1. 日志系统2. 部署ElasticSearch2.1 创建handless服务2.2 创建sts3. 部署kibana4. 部署ilogtail(docker-compose)4.1 编写docker-compose4.2 配置ilogtail采集4.3 查看容器采集的日志4.4 采集容器标准输出日志(可选)4.5 查看采集的容器日志5. 部署kafka5.1 kafka介绍…

AOD始终显示时间和信息(Dream)简析

AOD始终显示时间和信息(Dream)简析DreamManagerService启动在SystemServer的startOtherServices方法中会启动DreamManagerService服务这里是调用SystemServiceManager的startService方法显然,在SystemServiceManager的startService方法中首先将要启动的系统服务添加到其mSer…

操作系统——学习笔记(2)CPU虚拟化

学习黑皮书的一些呆瓜行为hhhhh

免费的攻击面管理平台-森罗

产品简介 森罗是有安科技推出的一款全新综合网络安全攻击面管理平台,集网络空间测绘与漏洞扫描于一体。森罗自带万象漏洞扫描器,与Nessus和Nuclei等许多产品一样,但它更现代,具有免等待的OOB测试策略、高级漏洞PoC IDE和强大的VDSL(漏洞域特定语言)引擎,使您能够轻松快速…

Fake权限验证小例子

前言 关于本地测试如何进行Fake权限验证 正文 在我们使用swagger调试本地接口的时候,我们常常因为每次需要填写token而耽误工作,不可能每次调试的时候都去本地测试环境请求一个token进行验证吧。上图可能是我们本地测试的时候需要填写的一个token位置,本地测试不方便。 那么…

41、linux-yum源管理-阿里云仓库配置

yum的管理1、清理原有的yum配置 把本地或者官方的/etc/yum.repos.d/路径下的所有repo配置文件移走确保/etc/yum.repos.d/这里没有其它文件2、下载配置阿里巴巴开源镜像站官网配置:https://developer.aliyun.com/mirror/在这个位置/etc/yum.repos.d/下载阿里云的yum源文件登陆…

vim基础使用

五、vim编辑器的使用 所有的Linux系统都默认有vi编译器,它就相当于Windows的记事本,当然,你也可以选择更好用的vim编译器,需要下载 yum install vim -y vim 有三种模式 使用vim filename wq!之后 这个命令如果filename不存在则 创建文件 [root@bogon opt]# vim zhanghaow…

【YOLOv8改进 - 注意力机制】NAM:基于归一化的注意力模块,将权重稀疏惩罚应用于注意力机制中,提高效率性能

**NAM: 提升模型效率的新颖归一化注意力模块,抑制非显著权重,结合通道和空间注意力,通过批量归一化衡量重要性。在Resnet和Mobilenet上的实验显示优于其他三种机制。源码见[GitHub](https://github.com/Christian-lyc/NAM)。**介绍摘要 识别较不显著的特征是模型压缩的关键。…

VP记录

我是真的红温了受打击了,他妈难受死了,遂记录这玩意儿,就算他妈没几个月就要退役。 ABC360 就是这场把我打击到了。之前15min切完ABCD,这回25min切B题,幽默🤡頑張って

视野修炼-技术周刊第90期 | 豆包AI IDE

① 豆包 MarsCode 正式发布 ② ECMAScript 2024 正式发布 ③ Mako 开源 - 蚂蚁的 Rust 力作 ④ CSDN批量搬运Github项目伪造开发者主页 ⑤ HTML 旋转图像实现示例 ⑥ 一组看着糙的组件库 ⑦ Chrome 126 中 DevTools 的新增功能 ⑧ 纯 CSS 实现环形文本欢迎来到第 90 期的【视野…

3.2

3.2 一键部署多台linux 1. 背景: 一般的机房的几十台甚至上百台电脑都需要统一部署操作系统。人工一个一个太费力,所以需要用到批量部署技术。 2. 实现原理:安装一台服务器后,通过交换机连接同一个网络方式还有结合自动应答文件的方式来实现。 ​ 网络拓扑图如下:这需要先…