【CGAL】Region_Growing检测圆柱,保存结果并输出圆柱体参数

目录

  • 说明
  • 代码展示
  • 结果展示
    • 问题说明

说明

这篇博客以代码为主,使用CGAL中的region growing方法检测圆柱体。将不同的圆柱按不同颜色保存,并输出圆柱体的中心坐标、轴方向以及半径。
region growing的具体思想网上的文章已经有很多,可以参考这个。

代码展示

#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Shape_detection/Region_growing/Region_growing.h>
#include <CGAL/IO/read_points.h>
#include <CGAL/property_map.h>
#include <CGAL/Shape_detection/Region_growing/Point_set.h>
#include <boost/iterator/function_output_iterator.hpp>
#include <CGAL/utils.h>
#include <fstream>

// 源文件
#define src_file_path "cylinder1_dense.ply"

// 检测结果分颜色保存
#define result_path "cylinder1_dense_result.ply"

// 参数保存
#define param_path "cylinder1_dense_param.txt"


// Typedefs.
using Kernel = CGAL::Simple_cartesian<double>;
using FT = Kernel::FT;
using Point_3 = Kernel::Point_3;
using Vector_3 = Kernel::Vector_3;
using Point_set = CGAL::Point_set_3<Point_3>;
using Point_map = typename Point_set::Point_map;
//using Normal_map = typename Point_set::Vector_map;
typedef std::pair<Point_3, Vector_3> Point_with_normal;
typedef std::vector<Point_with_normal> Pwn_vector;
using Neighbor_query = CGAL::Shape_detection::Point_set::K_neighbor_query_for_point_set<Point_set>;
using Region_type = CGAL::Shape_detection::Point_set::Least_squares_cylinder_fit_region_for_point_set<Point_set>;
using Region_growing = CGAL::Shape_detection::Region_growing<Neighbor_query, Region_type>;

void detect_and_save(Point_set& point_set, Neighbor_query& neighbor_query, Region_type& region_type)
{
    // Create an instance of the region growing class.
    Region_growing region_growing(
        point_set, neighbor_query, region_type);

    // Add maps to get a colored output.
    Point_set::Property_map<unsigned char>
        red = point_set.add_property_map<unsigned char>("red", 0).first,
        green = point_set.add_property_map<unsigned char>("green", 0).first,
        blue = point_set.add_property_map<unsigned char>("blue", 0).first;
    // Run the algorithm.
    //CGAL::Random random;
    std::size_t num_cylinders = 0;

    region_growing.detect(
    boost::make_function_output_iterator(
        [&](const std::pair< Region_type::Primitive, std::vector<typename Point_set::Index> >& region) {
            // Assign a random color to each region.
            const unsigned char r = static_cast<unsigned char>(rand() % 255);
            const unsigned char g = static_cast<unsigned char>(rand() % 255);
            const unsigned char b = static_cast<unsigned char>(rand() % 255);
            for (auto id : region.second) {
                put(red, id, r);
                put(green, id, g);
                put(blue, id, b);
            }
            ++num_cylinders;
        }
    )
);

    std::cout << "* number of found cylinders: " << num_cylinders << std::endl;
    // Save regions to a file.
    std::ofstream out(src_file_path);
    CGAL::IO::set_ascii_mode(out);
    out << point_set;
}

void detect_and_print_param(Point_set& point_set, Neighbor_query& neighbor_query, Region_type& region_type)
{
    // Create an instance of the region growing class.
    Region_growing region_growing(
        point_set, neighbor_query, region_type);

    std::vector<typename Region_growing::Primitive_and_region> regions;
    region_growing.detect(std::back_inserter(regions));

    // 打开输出文件
    std::ofstream outFile(param_path);

    for (size_t i = 0; i < regions.size(); i++)
    {
        const auto& primitive_and_region = regions[i];
        //const auto& region = primitive_and_region.second;
        const auto& cylinder_param = primitive_and_region.first;

        // 获取轴的方向
        const auto& dx = cylinder_param.axis.direction().dx();
        const auto& dy = cylinder_param.axis.direction().dy();
        const auto& dz = cylinder_param.axis.direction().dz();

        // 获取圆柱中心位置
        const auto& cx = cylinder_param.axis.point(0).x();
        const auto& cy = cylinder_param.axis.point(0).y();
        const auto& cz = cylinder_param.axis.point(0).z();

        // 获取圆柱半径
        const auto& r = cylinder_param.radius;

        outFile << r << " " << dx << " " << dy << " " << dz << " " << cx << " " << cy << " " << cz << "\n";

        std::cout << "圆柱半径:" << r << std::endl;
        std::cout << "圆柱轴方向:" << dx << ", " << dy << ", " << dz << std::endl;
        std::cout << "圆柱中心:" << cx << ", " << cy << ", " << cz << std::endl;
    }

    outFile.close();
}


int main(int argc, char** argv) {
    // Load ply data either from a local folder or a user-provided file.

    const std::string input_file = src_file_path;

    std::ifstream in(CGAL::data_file_path(input_file));
    CGAL::IO::set_ascii_mode(in);
    //CGAL::IO::set_binary_mode(in);
    if (!in) {
        std::cerr << "ERROR: cannot read the input file!" << std::endl;
        return EXIT_FAILURE;
    }
    Point_set point_set;
    in >> point_set;
    in.close();
    std::cout << "* number of input points: " << point_set.size() << std::endl;
    //assert(!is_default_input || point_set.size() == 1813);
    assert(point_set.has_normal_map()); // input should have normals
    // Default parameter values for the data file cuble.pwn.
    const std::size_t k = 10;
    const FT          max_distance = FT(1) / FT(500);
    const FT          max_angle = FT(60);
    const std::size_t min_region_size = 200;
    // Create instances of the classes Neighbor_query and Region_type.
    Neighbor_query neighbor_query = CGAL::Shape_detection::Point_set::make_k_neighbor_query(point_set, CGAL::parameters::k_neighbors(k));
    Region_type region_type = CGAL::Shape_detection::Point_set::make_least_squares_cylinder_fit_region(
        point_set,
        CGAL::parameters::
        maximum_distance(max_distance).
        maximum_angle(max_angle).
        minimum_region_size(min_region_size));
    
    // 检测圆柱,对属于不同圆柱的点赋予不同颜色
    //detect_and_save(point_set, neighbor_query, region_type);

    // 检测圆柱,输出每个圆柱的参数
    detect_and_print_param(point_set, neighbor_query, region_type);

    return EXIT_SUCCESS;
}

关于代码
写这个博客的一部分原因是,记录CGAL中保存region growing结果与检测到物体的参数的方式。可以从代码中看到,进行region_growing.detect(*)时,保存结果与输出参数所用的region类型并不一致。

另外还需注意,代码读取的ply文件必须是ASCII格式保存的,否则会出现读取的点不完整问题。

结果展示

原文件
在这里插入图片描述
检测结果
在这里插入图片描述

问题说明

当原点云中的圆柱体拥有上下底面时,检测结果很差。
源文件
在这里插入图片描述
检测结果
在这里插入图片描述

结论
进行圆柱体检测时,干扰点越少结果越精准。其中干扰点除了一些杂点之外,还包括圆柱体的上下两个底面点。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安装mysql5.7,然后安装mysql workbench进行管理。

1、下载mysql5.7 MySQL :: Download MySQL Installer 这个是32位的安装版 MySQL :: Download MySQL Community Server (Archived Versions) 这个是zip版 这里我下载的是zip版本。 下载完成后&#xff0c;解压缩&#xff0c;然后新建文件my.ini进行配制。 my.ini [mysqld]…

Django DetailView视图

Django的DetailView是一个用于显示单个对象详情的视图。下面是一个使用DetailView来显示单个书籍详情的例子。 1&#xff0c;添加视图 Test/app3/views.py from django.shortcuts import render# Create your views here. from django.views.generic import ListView from .m…

数据结构预备知识(Java):包装类泛型

1、包装类 1.1 包装类 在Java中&#xff0c;每一个基本数据类型都有一个对应的包装类&#xff1a; 在SE的学习中我们已有过简单了解。 我们可以注意到&#xff0c;除了int类型的包装类为Integer&#xff0c;char类型的包装类为Character外&#xff0c;其余基本类型的包装类均…

wordpress主题开发

科普一&#xff1a;wordpress 是一套用 php 这个语言写的CMS后台管理系统&#xff0c;即我们大家的 wordpress 网站后台是一样的&#xff0c;能体现我们网站外观不同的地方就在于wordpress主题&#xff08;即皮肤&#xff09;&#xff0c;而这个主题的基本构成是 htmlcssjavasc…

JMH309【亲测】典藏3D魔幻端游【剑踪3DⅢ】GM工具+开区合区工具+PC客户端+配置修改教程+Win一键服务端+详细外网视频教程

资源介绍&#xff1a; 经典不错的一款端游 GM工具开区合区工具PC客户端配置修改教程Win一键服务端详细外网视频教程 资源截图&#xff1a; 下载地址

任务倒计时App

设计背景 在某一阶段可能需要给自己设置长期任务&#xff0c;比如找工作、考研等&#xff0c;需要一个单纯的任务计时工具&#xff0c;设置完任务的目标时间后&#xff0c;每次打开App时都能直接看到最新的剩余时间 设计步骤 1. 写java源码 由于需要界面显示&#xff0c;需…

使用MySQL

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 1 下载安装MySQL MySQL是一款开源的数据库软件&#xff0c;由于其免费特性得到了全世界用户的喜爱&#xff0c;是目前使用人数最多的数据库。下面将…

Unity【入门】重要组件和API

Unity重要组件和API 文章目录 1、最小单位GameObject1、成员变量2、静态方法1、代码创建Unity自带几何体 CreatePrimitive2、查找对象3、实例化对象&#xff08;克隆对象&#xff09;的方法4、删除对象的方法5、切换场景不移除 3、成员方法1、创建空物体2、为对象动态添加脚本(…

基数排序详解

目录 一、桶排序思想 1.1 什么是桶排序 1.2 桶排序的步骤 二、基数排序思想 2.1 什么是基数排序 2.2 实现方式 2.3 图解 三、代码思路 3.1 前置工作 3.2 映射 3.3 排序 四、C语言源码 一、桶排序思想 1.1 什么是桶排序 桶排序(Bucket sort)是一种排序算法&#xff…

网络安全课程开发

我们为卡巴斯基实验室开发了一个交钥匙教育门户网站&#xff0c;并为其开设了网络安全课程。在资源上&#xff0c;你可以熟悉课程的理论部分-观看视频或阅读插图文本版本&#xff0c;然后通过回答问题来验证你的知识。通过最终测试后&#xff0c;用户将获得证书。 对于这个项目…

Pythone 程序打包成 exe

1.安装pyinstaller # 安装 pip install pyinstaller # 查看版本 pyinstaller -v2.更新pyinstaller 版本 # 更新 pip install --upgrade pyinstaller # 查看版本 pyinstaller -v3.切换到 py文件所在目录 #切换到.py所在的目录 E: cd cd E:\x-svn_x-local\04PythoneProjects\A…

平安养老险陕西分公司荣获“2021-2023年乡村振兴‘三村工程’先进机构”

5月27日&#xff0c;中国平安成立36周年司庆暨三省推广启动大会顺利召开。会上&#xff0c;平安养老险陕西分公司获“2021-2023年乡村振兴‘三村工程’先进机构”荣誉表彰。 过去三年间&#xff0c;平安养老险陕西分公司始终坚持金融为民&#xff0c;在平安集团、平安养老险的指…

【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【08】【商品服务】Object划分_批量删除

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【08】【商品服务】Object划分_批量删除 Object划分批量删除/添加参考 Object划分 数据库中对于一张表的数据&#xff0c;由于拥有隐私字段、多余字段、字段过少等原因&#xff0c;不应该直…

33 _ 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?

通过上篇文章的介绍&#xff0c;我们知道了同源策略可以隔离各个站点之间的DOM交互、页面数据和网络通信&#xff0c;虽然严格的同源策略会带来更多的安全&#xff0c;但是也束缚了Web。这就需要在安全和自由之间找到一个平衡点&#xff0c;所以我们默认页面中可以引用任意第三…

js之简单轮播图

今天给大家封装一个简单的轮播图,可以点击下一张上一张以及自动轮播 <!DOCTYPE html> <html><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>走马…

基于蚁群算法的二维路径规划算法(matlab)

微♥关注“电击小子程高兴的MATLAB小屋”获得资料 一、理论基础 1、路径规划算法 路径规划算法是指在有障碍物的工作环境中寻找一条从起点到终点、无碰撞地绕过所有障碍物的运动路径。路径规划算法较多&#xff0c;大体上可分为全局路径规划算法和局部路径规划算法两大类。其…

Neo4j 桌面版打不开踩坑贴

真的踩坑。。。没有人告诉我为啥桌面版和社区版不能一起下啊&#xff01;&#xff01; 我是先下载了社区版之后再下载的桌面版&#xff0c;结果桌面版界面一直打不开。 尝试了网上多种办法都没效果&#xff0c;好多都是说jdk不兼容导致无法打开&#xff0c;让我从JDK 17 ->…

跨域、JSONP、CORS、Spring、Spring Security解决方案

概述 JavaScript出于安全方面的考虑&#xff0c;不允许跨域调用其他页面的对象。跨域是浏览器&#xff08;如Chrome浏览器基于JS V8引擎&#xff0c;可以简单理解为JS解释器&#xff09;的一种同源安全策略&#xff0c;是浏览器单方面限制脚本的跨域访问。因此&#xff0c;仅有…

python使用wkhtmltopdf将html字符串保存pdf,解决出现方框的问题

出现的问题: 解决办法: <html> <head><meta charset="UTF-8"/> </head> <style> * {font-family: Arial,SimSun !important; } </style> </html>在html字符串前面加上上面代码,意思是设置字体编码和样式 html示例:…

足球实况分析系统YOLO

① 足球运动员、裁判和球检测&#xff1b; ② 球员球队预测&#xff1b; ③ 足球地图上球员和球位置的估计&#xff1b; ④ 足球跟踪&#xff1b; 当你启动应用程序时&#xff0c;会自动加载两个演示视频以及推荐的设置和超参数. 1. 使用侧栏菜单“浏览文件”按钮上传视频…