c++ pcl点云变换骨架枝干添加树叶源码实例

news2024/12/23 8:13:31

程序示例精选
c++ pcl点云变换骨架枝干添加树叶源码实例
如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助!

前言

这篇博客针对《c++ pcl点云变换骨架枝干添加树叶源码实例》编写代码,代码整洁,规则,易读。 学习与应用推荐首选。


运行结果

运行结果 运行结果 ***

文章目录

一、所需工具软件
二、使用步骤
       1. 主要代码
       2. 运行结果
三、在线协助

一、所需工具软件

       1. VS2019, Qt
       2. C++

二、使用步骤

代码如下(示例):

/*
*	Copyright (C) 2019 by
*       Shenglan Du (dushenglan940128@163.com)
*       Liangliang Nan (liangliang.nan@gmail.com)
*       3D Geoinformation, TU Delft, https://3d.bk.tudelft.nl
*
*	This file is part of AdTree, which implements the 3D tree
*   reconstruction method described in the following paper:
*   -------------------------------------------------------------------------------------
*       Shenglan Du, Roderik Lindenbergh, Hugo Ledoux, Jantien Stoter, and Liangliang Nan.
*       AdTree: Accurate, Detailed, and Automatic Modeling of Laser-Scanned Trees.
*       Remote Sensing. 2019, 11(18), 2074.
*   -------------------------------------------------------------------------------------
*   Please consider citing the above paper if you use the code/program (or part of it).
*
*	AdTree is free software; you can redistribute it and/or modify
*	it under the terms of the GNU General Public License Version 3
*	as published by the Free Software Foundation.
*
*	AdTree is distributed in the hope that it will be useful,
*	but WITHOUT ANY WARRANTY; without even the implied warranty of
*	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*	GNU General Public License for more details.
*
*	You should have received a copy of the GNU General Public License
*	along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// save the smoothed skeleton into a PLY file (where each vertex has a radius)
void save_skeleton(Skeleton* skeleton, PointCloud* cloud, const std::string& file_name) {
	const ::Graph& sgraph = skeleton->get_smoothed_skeleton();
	if (boost::num_edges(sgraph) == 0) {
		std::cerr << "failed to save skeleton (no edge exists)" << std::endl;
		return;
	}

	// convert the boost graph to Graph (avoid modifying easy3d's GraphIO, or writing IO for boost graph)

	std::unordered_map<SGraphVertexDescriptor, easy3d::Graph::Vertex>  vvmap;
	easy3d::Graph g;

	auto vertexRadius = g.add_vertex_property<float>("v:radius");
	auto vts = boost::vertices(sgraph);
	for (SGraphVertexIterator iter = vts.first; iter != vts.second; ++iter) {
		SGraphVertexDescriptor vd = *iter;
		if (boost::degree(vd, sgraph) != 0) { // ignore isolated vertices
			const vec3& vp = sgraph[vd].cVert;
			auto v = g.add_vertex(vp);
			vertexRadius[v] = sgraph[vd].radius;
			vvmap[vd] = v;
		}
	}

	auto egs = boost::edges(sgraph);
	for (SGraphEdgeIterator iter = egs.first; iter != egs.second; ++iter) {
		SGraphEdgeDescriptor ed = *iter;    // the edge descriptor
		SGraphEdgeProp ep = sgraph[ed];   // the edge property

		SGraphVertexDescriptor s = boost::source(*iter, sgraph);
		SGraphVertexDescriptor t = boost::target(*iter, sgraph);
		g.add_edge(vvmap[s], vvmap[t]);
	}

	auto offset = cloud->get_model_property<dvec3>("translation");
	if (offset) {
		auto prop = g.model_property<dvec3>("translation");
		prop[0] = offset[0];
	}

	if (GraphIO::save(file_name, &g))
        std::cout << "model of skeletons saved to: " << file_name << std::endl;
    else
		std::cerr << "failed to save the model of skeletons into file" << std::endl;
}


// returns the number of processed input files.
int batch_reconstruct(std::vector<std::string>& point_cloud_files, const std::string& output_folder, bool export_skeleton) {
    int count(0);
    for (std::size_t i=0; i<point_cloud_files.size(); ++i) {
        const std::string& xyz_file = point_cloud_files[i];
        std::cout << "------------- " << i + 1 << "/" << point_cloud_files.size() << " -------------" << std::endl;
        std::cout << "processing xyz_file: " << xyz_file << std::endl;

        if (!file_system::is_directory(output_folder)) {
            if (file_system::create_directory(output_folder))
                std::cout << "created output directory '" << output_folder << "'" << std::endl;
            else {
                std::cerr << "failed creating output directory" << std::endl;
                return 0;
            }
        }

        // load point_cloud
        PointCloud *cloud = PointCloudIO::load(xyz_file);
        if (cloud) {
            std::cout << "cloud loaded. num points: " << cloud->n_vertices() << std::endl;

            // compute bbox
            Box3 box;
            auto points = cloud->get_vertex_property<vec3>("v:point");
            for (auto v : cloud->vertices())
                box.add_point(points[v]);

            // remove duplicated points
            const float threshold = box.diagonal() * 0.001f;
            const auto &points_to_remove = RemoveDuplication::apply(cloud, threshold);
            for (auto v : points_to_remove)
                cloud->delete_vertex(v);
            cloud->garbage_collection();
            std::cout << "removed too-close points. num points: " << cloud->n_vertices() << std::endl;
        }
        else {
            std::cerr << "failed to load point cloud from '" << xyz_file << "'" << std::endl;
            continue;
        }

        // reconstruct branches
        SurfaceMesh *mesh = new SurfaceMesh;
        const std::string &branch_filename = file_system::base_name(cloud->name()) + "_branches.obj";
        mesh->set_name(branch_filename);

        Skeleton *skeleton = new Skeleton();
        bool status = skeleton->reconstruct_branches(cloud, mesh);
        if (!status) {
            std::cerr << "failed in reconstructing branches" << std::endl;
            delete cloud;
            delete mesh;
            delete skeleton;
            continue;
        }

        // copy translation property from point_cloud to surface_mesh
        SurfaceMesh::ModelProperty<dvec3> prop = mesh->add_model_property<dvec3>("translation");
        prop[0] = cloud->get_model_property<dvec3>("translation")[0];

        // save branches model
        const std::string branch_file = output_folder + "/" + branch_filename;
        if (SurfaceMeshIO::save(branch_file, mesh)) {
            std::cout << "model of branches saved to: " << branch_file << std::endl;
            ++count;
        }
        else
            std::cerr << "failed to save the model of branches" << std::endl;

        if (export_skeleton) {
            const std::string& skeleton_file = output_folder + "/" + file_system::base_name(cloud->name()) + "_skeleton.ply";
            save_skeleton(skeleton, cloud, skeleton_file);
        }

        delete cloud;
        delete mesh;
        delete skeleton;
    }

    return count;
}


int main(int argc, char *argv[]) {
//    argc = 2;
//    argv[1] = "/Users/lnan/Projects/adtree/data";
//    argv[2] = "/Users/lnan/Projects/adtree/data-results";

    if (argc == 1) {
        TreeViewer viewer;
        viewer.run();
        return EXIT_SUCCESS;
    } else if (argc >= 3) {
        bool export_skeleton = false;
        for (int i = 0; i < argc; ++i) {
            if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-skeleton") == 0) {
                export_skeleton = true;
                break;
            }
        }

        if (export_skeleton) {
            std::cout << "You have requested to save the reconstructed tree skeleton(s) in PLY format into the output directory." << std::endl;
            std::cout << "The skeleton file(s) can be visualized using Easy3D: https://github.com/LiangliangNan/Easy3D" << std::endl;
        }
        else
            std::cout << "Tree skeleton(s) will not be saved (append '-s' or '-skeleton' in commandline to enable it)" << std::endl;

        std::string first_arg(argv[1]);
        std::string second_arg(argv[2]);
        if (file_system::is_file(second_arg))
            std::cerr << "WARNING: second argument cannot be an existing file (expecting a directory)." << std::endl;
        else {
            std::string output_dir = second_arg;
            if (file_system::is_file(first_arg)) {
                std::vector<std::string> cloud_files = {first_arg};
                return batch_reconstruct(cloud_files, output_dir, export_skeleton) > 0;
            } else if (file_system::is_directory(first_arg)) {
                std::vector<std::string> entries;
                file_system::get_directory_entries(first_arg, entries, false);
                std::vector<std::string> cloud_files;
                for (const auto &file_name : entries) {
                    if (file_name.size() > 3 && file_name.substr(file_name.size() - 3) == "xyz")
                        cloud_files.push_back(first_arg + "/" + file_name);
                }
                return batch_reconstruct(cloud_files, output_dir, export_skeleton) > 0;
            } else
                std::cerr
                        << "WARNING: unknown first argument (expecting either a point cloud file in *.xyz format or a\n"
                           "\tdirectory containing *.xyz point cloud files)." << std::endl;
        }
    }
    return EXIT_FAILURE;
}


运行结果
运行结果 运行结果

三、在线协助:

如需安装运行环境或远程调试,见文章底部个人 QQ 名片,由专业技术人员远程协助!

1)远程安装运行环境,代码调试
2)Visual Studio, Qt, C++, Python编程语言入门指导
3)界面美化
4)软件制作
5)云服务器申请
6)网站制作

当前文章连接:https://blog.csdn.net/alicema1111/article/details/132666851
个人博客主页:https://blog.csdn.net/alicema1111?type=blog
博主所有文章点这里:https://blog.csdn.net/alicema1111?type=blog

博主推荐:
Python人脸识别考勤打卡系统:
https://blog.csdn.net/alicema1111/article/details/133434445
Python果树水果识别:https://blog.csdn.net/alicema1111/article/details/130862842
Python+Yolov8+Deepsort入口人流量统计:https://blog.csdn.net/alicema1111/article/details/130454430
Python+Qt人脸识别门禁管理系统:https://blog.csdn.net/alicema1111/article/details/130353433
Python+Qt指纹录入识别考勤系统:https://blog.csdn.net/alicema1111/article/details/129338432
Python Yolov5火焰烟雾识别源码分享:https://blog.csdn.net/alicema1111/article/details/128420453
Python+Yolov8路面桥梁墙体裂缝识别:https://blog.csdn.net/alicema1111/article/details/133434445

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

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

相关文章

搞个微信小程序002:个人信息

新建一个用于&#xff0c;和001中一样&#xff0c;然后&#xff0c;就改掉两个文件&#xff1a; index.wxml: <view><!-- 头像区域 --><view class"top"><view class"user-img"><image src"/images/tx.png"><…

JIT耗时优化

优质博文&#xff1a;IT-BLOG-CN 一、背景 业务流量突增&#xff0c;机器直接接入大量流量QPS2000&#xff0c;JIT和GC会消耗太多CPU资源&#xff0c;导致1-2分钟时间内的请求超时导致异常&#xff0c;因此采用流量预热的方式&#xff0c;让机器逐步接入流量&#xff0c;需要预…

学习MAVEN

MAVEN的详细介绍和作用、意义 好的&#xff0c;小朋友们&#xff0c;我们今天来聊聊一个非常神奇的工具箱&#xff0c;它的名字叫做Maven! &#x1f31f; 1. **神奇的工具箱Maven**: Maven就像是一个神奇的工具箱&#x1f9f0;&#xff0c;它可以帮助大人们把他们的电脑工…

手撕 视觉slam14讲 ch13 代码(7)后端优化 Backend::Optimize()

在上一篇 手撕&#xff08;6&#xff09;中的InsertKeyframe()插入关键帧的函数里&#xff0c;有一个 Backend::UpdateMap() 函数 &#xff0c;从这里通过条件变量 map_update_ 来激活后端优化。 backend.h&#xff1a; // * 有单独优化线程&#xff0c;在Map更新时启动优化…

【JavaScript】深入浅出理解事件循环

1. 浏览器的进程模型 1.1 进程 程序运行需要有它自己专属的内存空间&#xff0c;可以把这块内存空间简单的理解为进程。 每个应用至少有一个进程&#xff0c;进程之间相互独立&#xff0c;即使要通信&#xff0c;也需要双方同意。 1.2 线程 有了进程后&#xff0c;就可以运…

《王道计算机考研——操作系统》学习笔记总目录+思维导图

本篇文章是对《王道计算机考研——操作系统》所有知识点的笔记总结归档和计算机网络的思维导图 学习视频&#xff1a;王道计算机考研 操作系统 408四件套【计网、计组、操作系统、数据结构】完整课堂PPT 思维导图 &#xff08;求Star~&#xff09;&#xff1a;【王道考研】计…

NodeJS VM沙箱逃逸

文章目录 基本概念Node将字符串执行为代码方法一 eval方法二&#xff1a;new Function Nodejs作用域vm沙箱逃逸vm沙箱逃逸的一些其他情况实例 基本概念 什么是沙箱&#xff08;sandbox&#xff09;当我们运行一些可能会产生危害的程序&#xff0c;我们不能直接在主机的真实环境…

Promise详解:手写Promise底层-实现Promise所有的功能和方法

前言 目标&#xff1a;封装一个promise&#xff0c;更好的理解promise底层逻辑需求&#xff1a;实现以下promise所有的功能和方法 如下图所示一、构造函数编写 步骤 1、定义一个TestPromise类&#xff0c; 2、添加构造函数&#xff0c; 3、定义resolve/reject&#xff0c; 4、…

FL Studio21中文版本好用吗?值不值得下载

今天&#xff0c;我从一个FL Studio忠实且还算资深的用户角度&#xff0c;来为大家深度介绍并评测一下FL Studio的性能以及我四年的使用感受。 FL Studio是一款集剪辑、编曲、录音、混音一体的全能DAW&#xff08;数字音频工作站&#xff09;。其所有界面都是支持100%矢量化的…

Pycharm设置快捷键

本文主要讲一下Pycharm如何设置字体的缩小和放大的快捷键。 参见&#xff1a; 编程的快乐&#xff0c;你想象到了吗&#xff1f;PyCharm插件大全&#xff08;适合所有JetBrains家族产品&#xff09;_哔哩哔哩_bilibili

虚函数实例

1.声明&#xff1a;virtual 同名成员名 可实现父类访问子类中与其同名的成员 #include<iostream> using namespace std; class A{protected:int x;public:A(int x10):x(x1){}virtual void print(){//在类A中定义print为虚函数cout<<"A类中的x"<<x…

vue项目编译、打包、部署服务器运行

在vue项目执行npm run build,生成dis目录 打包dis上传 安装npm install -g http-server或者apt install node-http-server 运行http-server

微信小程序scroll-view设置display:flex后子view宽度设置无效解决

如果scroll-view设置了display:flex&#xff0c;子view设置宽度值无效&#xff0c;宽度值都是随着内容多少而改变&#xff1a; 效果和wxml&#xff1a; css: 原因&#xff1a;flex布局元素的子元素&#xff0c;自动获得了flex-shrink的属性 解决办法&#xff1a; 给子view增加…

国内智能客服机器人都有哪些?

随着人工智能技术的不断发展&#xff0c;智能客服机器人已经成为了企业客户服务的重要工具。国内的智能客服机器人市场也迎来了飞速发展&#xff0c;越来越多的企业开始采用智能客服机器人来提升客户服务效率和质量。 在这篇文章中&#xff0c;我将详细介绍国内知名的智能客服机…

大模型之Chat Markup Language

背景 在笔者应用大模型的场景中&#xff0c;对话模型(即大模型-chat系列)通常具有比较重要的地位&#xff0c;我们通常基于与大模型进行对话来获取我们希望理解的知识。然而大模型对话是依据何种数据格式来进行训练的&#xff0c;他们的数据为什么这么来进行组织&#xff0c;本…

7种典型的钢结构BIM应用

钢铁的工作流程往往会造成项目各个阶段信息缺乏、成本高、效率低等问题。 BIM技术通过数字化真实信息模拟建筑&#xff0c;通过中央文档共享信息&#xff0c;将流程的各个阶段紧密联系起来&#xff0c;交换信息&#xff0c;提高效率&#xff0c;降低成本。 制造专用软件不断发展…

pytorch C++ 移植

文章目录 前言安装 libtorch安装 opencv&#xff08;C&#xff09;模型转换通过跟踪转换为 Torch Script通过注解转换为 Torch Script 编写 C 代码编译环境搭建C 库管理方法一&#xff1a;手动配置 visual studio 环境方法二&#xff1a;cmake 配置环境 python 调用 C 程序 前言…

go语言Array 与 Slice

有的语言会把数组用作常用的基本的数据结构&#xff0c;比如 JavaScript&#xff0c;而 Golang 中的数组(Array)&#xff0c;更倾向定位于一种底层的数据结构&#xff0c;记录的是一段连续的内存空间数据。但是在 Go 语言中平时直接用数组的时候不多&#xff0c;大多数场景下我…

MySQL中查询重复字段的方法和步骤是怎样

示例 accountinfo 表数据如下&#xff1a; 场景一 单个字段重复数据查找 & 去重 我们要把上面这个表中 单个字段 account字段相同的数据找出来。 思路 分三步 简述&#xff1a; 第一步 要找出重复数据&#xff0c;我们首先想到的就是&#xff0c;既然是重复&#xff0c…

【斗破年番】再遭群嘲,美杜莎怀孕之事被魔改,三方联手除萧潇?

【侵权联系删除】【文/郑尔巴金】 斗破苍穹年番第67集已经更新了。和很多人一样&#xff0c;小郑也去看了&#xff0c;只是小郑万万没有想到&#xff0c;我满怀期待的去看这一集&#xff0c;这一集却能魔改成这样。魔改成什么样了呢&#xff1f;下面来分析下吧&#xff01; 一&…