【三维重建】三角网格中轴骨架线提取

news2024/11/15 7:07:47

三维网格中轴线提取

  • 方法介绍
  • 实现提取

三维网格中轴线提取是计算机图形学和三维建模领域中的一个重要技术,它对于理解三维形状的拓扑结构和几何特性具有重要意义。

方法介绍

以下是几种常见的三维网格中轴线提取方法:

  1. 基于距离变换的方法
    基本原理:首先计算三维网格中每个点到网格边界的距离,形成距离场。然后,根据距离场的分布,通过细化算法提取中轴线。这种方法的核心在于距离变换和细化操作的结合。
    步骤:
    对三维网格进行距离变换,计算每个点到最近边界的距离。
    对距离变换结果进行排序,优先处理距离较小的点。
    通过细化算法逐步剥离外层点,直至提取出中轴线。
  2. 基于中轴球的方法
    基本原理:为每个网格端点计算一个中轴球,中轴球的中心即为中轴点。通过计算所有网格端点的中轴球,最终生成中轴网格。
    步骤:
    估计网格上所有点的法向,以模拟平滑表面。
    将模型分割成体素,每个体素具有特定尺寸。
    计算每个网格端点的中轴球,包括中轴点和中轴半径。
    通过所有中轴点生成中轴网格。
  3. 基于局部曲面拟合的方法
    应用场景:特别适用于处理点云数据,如三维激光扫描数据。
    步骤:
    对原始点云数据进行预处理,包括配准和去噪。
    对点云进行横断面切片处理,得到多个切片点云。
    对每个切片点云进行局部曲面拟合,提取切片中心。
    将所有切片中心拟合得到整体的中轴线。
  4. 基于拓扑收缩的方法
    基本原理:通过定义一个收缩力函数,控制三维网格内表面的收缩过程,直至收缩成一维的中轴线。
    挑战:如何定义收缩力函数以平衡收缩和吸引约束,同时保留骨架线的拓扑性和中间轴的中心位置。
  5. 基于骨架提取的算法
    如Medial Axis Transform (MAT):这类算法通常涉及对三维网格进行骨架化处理,通过逐步剥离外层网格元素,最终得到中轴线或骨架结构。

实现提取

输入:半圆环网格

在这里插入图片描述

std::vector<Point> m_points;
std::vector<std::vector<int>> m_faces;
std::unordered_map<int, std::vector<int>> m_adjacency;
std::unordered_set<int> m_boundaryPoints;
std::unordered_set<int> m_skeletonPoints;
std::unordered_set<Edge, EdgeHash> m_skeletonEdges;

void buildAdjacencyList() {
    for (const auto& face : m_faces) {
        for (int i = 0; i < 3; ++i) {
            int v1 = face[i];
            int v2 = face[(i + 1) % 3];
            m_adjacency[v1].push_back(v2);
            m_adjacency[v2].push_back(v1);
        }
    }
}

void findBoundaryPoints() {
    std::unordered_set<Edge, EdgeHash> edges;
    for (const auto& face : m_faces) {
        for (int i = 0; i < 3; ++i) {
            Edge e(face[i], face[(i + 1) % 3]);
            if (edges.find(e) != edges.end()) {
                edges.erase(e);
            }
            else {
                edges.insert(e);
            }
        }
    }
    for (const auto& e : edges) {
        m_boundaryPoints.insert(e.v1);
        m_boundaryPoints.insert(e.v2);
    }
}
void grassfirePropagation() {
    // Distance initialization and boundary point queue
    std::vector<float> distanceFromBoundary(m_points.size(), std::numeric_limits<float>::max());
    std::queue<int> queue;

    // Initialize boundary points
    for (int idx : m_boundaryPoints) {
        distanceFromBoundary[idx] = 0;
        queue.push(idx);
    }

    // Distance update using BFS
    while (!queue.empty()) {
        int current = queue.front();
        queue.pop();

        for (int neighborIdx : m_adjacency[current]) {
            float newDistance = distanceFromBoundary[current] + distance(m_points[current], m_points[neighborIdx]);
            if (newDistance < distanceFromBoundary[neighborIdx]) {
                distanceFromBoundary[neighborIdx] = newDistance;
                queue.push(neighborIdx);
            }
        }
    }

    // Find local maxima (skeleton points)
    for (int i = 0; i < m_points.size(); ++i) {
        if (m_boundaryPoints.count(i) > 0) continue;  // Skip boundary points

        bool isLocalMaximum = true;
        for (int neighborIdx : m_adjacency[i]) {
            if (distanceFromBoundary[neighborIdx] > distanceFromBoundary[i]) {
                isLocalMaximum = false;
                break;
            }
        }
        if (isLocalMaximum) {
            m_skeletonPoints.insert(i);
        }
    }
}

在这里插入图片描述

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

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

相关文章

海康二次开发笔记10-独立Group导入、导出及执行

独立Group导入、导出及执行 1. 界面设计 2. 添加引用 Group相当于VM中的模块,因此在调用相关接口函数前,需要引用对应的动态库IMVSGroupCs,同时将复制本地的属性改为False using IMVSGroupCs;3. 添加VmSingleModuleSetConfigControl控件 拖入控件后,设置Dock为Fill 4. 选择G…

算法的学习笔记—把数字翻译成字符串

&#x1f600;前言 在日常生活中&#xff0c;我们经常会遇到各种编码和解码的问题。今天&#xff0c;我们将讨论一个有趣的问题&#xff1a;如何将一串数字翻译成字母&#xff0c;并计算出有多少种不同的翻译方法。 &#x1f3e0;个人主页&#xff1a;尘觉主页 文章目录 &#…

虚拟化设置和虚拟机相关的环境搭建

目录 0.首先声明 1.背景知识 ​编辑 2.虚拟化设置 3.安装vm15.5过程 4.安装虚拟系统 4.1下载centos7.6 4.2安装centos7.6 5.我的总结 6.我的体会 0.首先声明 我的这个教程参考的就是韩顺平老师的这个linux学习教程&#xff0c;但是这个韩老师的这个教程就是2020年的教…

算法如何应用,思路都在这

目录 01 问题定义 02 问题建模 03 特征工程 04 模型选择 05 模型融合 本文深入探讨了算法在不同领域的应用方法和背后的思考逻辑。作者夏师傅通过丰富的案例分析&#xff0c;揭示了算法如何助力产品决策、优化业务流程&#xff0c;并提供了实用的策略和技巧。无论您是技术专家还…

2024 年 Web 开发者必备的 30 款 CSS 工具

2024 年 Web 开发者必备的 30 款 CSS 工具 | 瑆箫博客 找到合适的 CSS 工具可能需要花费不少时间&#xff0c;但是这份 2024 年最棒的 30 款 CSS 工具清单&#xff0c;可以让你的选择变得轻松许多。无论你的 CSS 技能水平如何&#xff0c;这份清单都能提供调试、优化代码和提升…

Bazel 快速入门与核心知识

Bazel 快速入门与核心知识 Bazel 简介 Bazel 是一款与 Make、Maven 和 Gradle 类似的开源构建和测试工具。 它使用人类可读的高级构建语言。Bazel 支持多种语言的项目 (C/C, Java, Python, …)&#xff0c;可为多个平台构建输出。Bazel 支持跨多个代码库和大量用户的大型代码…

2024怎么选蓝牙耳机性价比品牌?四款小白必看优选王炸机型推荐!

如今国人对蓝牙耳机的选择日益重视&#xff0c;蓝牙耳机作为智能的手机备件&#xff0c;普及率也是一升再升&#xff0c;但市面上很多品牌虽然宣传自己音质好和佩戴感舒适&#xff0c;其实性能不佳&#xff0c;那么2024怎么选蓝牙耳机性价比品牌&#xff1f;身为资深的蓝牙耳机…

复变函数在大模型中的应用

1. 导入 说来惭愧&#xff0c;我研究生时的研究方向是复分析&#xff0c;但毕业近十年来几乎没用到它。 我还记得实习时做自我介绍时&#xff0c;我说我的研究方向是复分析。面试官不太了解&#xff0c;我便解释说&#xff0c;这是关于对 -1 开平方得到的虚数 i 的研究。 在…

信号的捕捉

1.信号的产生 信号递达:实际执行信号的处理动作称为信号的递达 信号未决:信号从产生到递达之间的状态 进程可以阻塞某个信号 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作 注意,忽略和阻塞是不同的,只要信号阻塞就不会被递达,而忽略是递达…

【Apache Doris】数据均衡问题排查指南

原文阅读&#xff1a;【巨人肩膀社区博客分享】【Apache Doris】数据均衡问题排查指南 一、前提概要 当集群处于以下几种情况时&#xff0c;可参考本文进行问题排查。 •BE节点之间的数据不均 •单个BE节点上的多个磁盘之间的数据不均 •BE节点的上线和下线进度卡死&#…

《高等代数》两条线行列式

说明&#xff1a;此文章用于本人复习巩固&#xff0c;如果也能帮助到大家那就更加有意义了。 注&#xff1a;两条线行列式的固定做法为按照第一列展开。

Kafka分布式集群部署实战:跨越理论,直击生产环境部署难题与解决方案,性能调优、监控与管理策略大揭秘,轻松上手分布式消息中间件

本文介绍kafka的集群如何部署和安装&#xff0c;1-4章理论知识&#xff0c;第5章详解集群的部署&#xff0c;部署Kafka之前需要先部署好分布式的Zookeeper&#xff0c;不喜欢理论的可以直接看第5章&#xff0c;欢迎大家一起探讨技术&#xff01; Zookeeper集群部署参考文章&…

VUE-组件间通信(三)全局事件总线

一、作用&#xff1a;任意组件间通信 二、实现 1、创建全局事件总线 new Vue({render: h > h(App),beforeCreate(){//创建全局事件总线Vue.prototype.$busthis} }).$mount(#app) 2、学生组件 触发事件 <template><div class"studentInfo"><h…

(备份)常用ASCII 8*8 点阵 以及查询显示字符的点阵

图片 #include "driver/spi_master.h" #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "string.h" #include "driver/i2c.h" #include "esp_rom_sys.h"…

【postman如何生成python代码】

postman如何生成python代码 https://jingyan.baidu.com/article/86fae3461577c27d48121ad1.html

【大模型系列篇】词向量 - 从Word2Vec到ELMo

&#x1f525;&#x1f525;&#x1f525;首先安利一个比较不错的忍不住就想一键三连的大模型科普: 大模型科普专栏 - AI老兵文哲&#xff08;哔哩哔哩&#xff09; 词向量&#xff08;又叫词嵌入&#xff09;已经成为NLP领域各种任务的必备一步&#xff0c;而且随着BERT、GPT等…

JS打造一款你自己的专用字体:使用p5.js与JavaScript实现

前言 在最近的生成艺术项目中遇到一个小问题&#xff1a;如何在作品中优雅地添加文本元素&#xff0c;同时避免使用网络字体&#xff0c;要么侵权要么花钱~~给项目增加不必要的负担&#xff0c;我决定不走寻常路&#xff0c;自己动手&#xff0c;丰衣足食&#xff0c;用JS打造…

C++11 新特性基础

前言 C11是继&#xff0c;C98/03之后的最大的一次更新&#xff0c;这次更新虽然花了很长的时间&#xff0c;但是真的推出了很多的干货&#xff01;本期内容开始我们将介绍C11常用的操作&#xff01; 目录 前言 一、C11介绍 二、统一的列表初始化 1、{}初始化 2、std::in…

【机器学习】循环神经网络(RNN)介绍

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 循环神经网络(RNN)介绍什么是RNN?RNN的基本原理递归神经网络单元前向传播反向传…

Ubuntu下安装和配置MQTT服务器Mosquitto

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的通信协议&#xff0c;设计用于物联网设备之间的低带宽、不稳定网络环境下的高效通信。MQTT允许设备通过发布&#xff08;publish&#xff09;和订阅&#xff08;subscribe&#xff09;模式进行消…