点云处理库Open3D基础操作1

news2024/11/26 10:35:51

文章目录

    • 基础介绍
    • Open3D读取文件
    • `Voxel`降采样
    • 裁剪点云
    • `Open3D`点云和`numpy`数组的转换
    • 点云的`bounding box`


欢迎访问个人网络日志🌹🌹知行空间🌹🌹


基础介绍

Open3D是英特尔公司于2015年发布的开源3D视觉算法库,截至2023年03月已经更新到了0.17.0版本。基于MIT协议开源许可。

其后端使用C++11实现,经过了高度优化,使用OpenMP并行运算优化。通过Python Pybinding,其提供前端Python API

Open3D的介绍论文发布在http://www.open3d.org/wordpress/wp-content/paper.pdf。更多详细的介绍可以参考这里。

值得一提的是在另外一个大名鼎鼎的3D视觉算法库是Point Cloud Library(PCL)PCLWillow Garage实验室开源于2011年,与Robot Operating System(ROS)同出一源。关于PCL的介绍可以参考这里https://pointclouds.org/assets/pdf/pcl_icra2011.pdf。在Open3D的介绍论文中,作者指出,PCL作为较早出现的3D视觉算法库,经过一段时间的开源维护后,代码变的臃肿,且更新维护频率比较低。

Open3D的更新历史https://github.com/isl-org/Open3D/tags
PCL的更新历史https://github.com/PointCloudLibrary/pcl/tags

作为Open3DPCL的使用者,客观的讲Open3DPython接口更好用,维护更新做的也更好。

Open3D读取文件

使用的测试数据可以从这里下载。

数据下载地址http://graphics.stanford.edu/data/3Dscanrep/

物体的3D表示可以使用点云/Mesh/Model

Open3D支持的Mesh类型有:

Open3D支持的点云类型有:

  • 读取ply格式的Mesh
filename = "dragon_recon/dragon_vrip_res2.ply"
dragon_mesh = o3d.io.read_triangle_mesh(filename)
print(dragon_mesh)
dragon_mesh.compute_vertex_normals()
print(np.asarray(dragon_mesh.triangles).shape)
print(np.asarray(dragon_mesh.vertices).shape)
o3d.visualization.draw_geometries([dragon_mesh])    # 可视化Mesh

# TriangleMesh with 100250 points and 202520 triangles.
# (202520, 3)
# (100250, 3)

  • 读取pcd格式的点云
  • 保存点云write_point_cloud(filename, pointcloud, write_ascii=False, compressed=False, print_progress=False)
    Function to write PointCloud to file
  • 可视化点云
      1. draw_geometries(geometry_list, window_name='Open3D', width=1920, height=1080, left=50, top=50, point_show_normal=False, mesh_show_wireframe=False, mesh_show_back_face=False) Function to draw a list of geometry.Geometry objects。
        使用OpenGL进行渲染。
    • 2.draw_geometries_with_key_callbacks参考自callback
dragon_pc = dragon_mesh.sample_points_uniformly(number_of_points=20000)
save_file = "dragon_recon/dragon_vrip_res2.pcd"
o3d.io.write_point_cloud(save_file, dragon_pc)
o3d.visualization.draw_geometries([dragon_pc])    # 可视化点云 +/-可调点云的大小

def rotate_callback(vis):
    ctr = vis.get_view_control()
    ctr.rotate(10.0, 0.0)
    return False
key_to_callback = dict()
key_to_callback[ord("r")] = rotate_callback
o3d.visualization.draw_geometries_with_key_callbacks([dragon_pc], key_to_callback)

Voxel降采样

刚刚随机采样生成点云时,number_of_points设置的是20000,点太多了的时候,可以使用体素Voxel来降采样。

voxel_down_sample(self, voxel_size)
Function to downsample input pointcloud into output pointcloud with a voxel. Normals and colors are averaged if they exist.

  • o3d.visualization.read_selection_polygon_volume 通过空间多边形和最大最小距离来裁剪点云数据

  • compute_convex_hull(…) method of open3d.cpu.pybind.geometry.PointCloud instance,计算点云的凸包

  • estimate_normals 计算点云的法向量

max_bound = dragon_pc.get_max_bound()
min_bound = dragon_pc.get_min_bound()
dx, dy, dz = max_bound - min_bound
voxel_size = min([dx, dy, dz]) / 20
print(dragon_pc)
dragon_pc_downsampled = dragon_pc.voxel_down_sample(voxel_size=voxel_size)
print(dragon_pc_downsampled.points)

dragon_pc_downsampled.estimate_normals(o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=32)) 
o3d.visualization.draw_geometries([dragon_pc_downsampled], point_show_normal=True)

dragon_normals = dragon_pc_downsampled.normals
print(dragon_normals[0])

# PointCloud with 20000 points.
# std::vector<Eigen::Vector3d> with 4179 elements.
# Use numpy.asarray() to access data.
# [-0.39450818  0.35314528  0.84832288]

裁剪点云

demo_crop_data = o3d.data.DemoCropPointCloud()
pcd = o3d.io.read_point_cloud(demo_crop_data.point_cloud_path)
vol = o3d.visualization.read_selection_polygon_volume(demo_crop_data.cropped_json_path)
chair = vol.crop_point_cloud(pcd)
o3d.visualization.draw_geometries([chair],
                                  zoom=0.7,
                                  front=[0.5439, -0.2333, -0.8060],
                                  lookat=[2.4615, 2.1331, 1.338],
                                  up=[-0.1781, -0.9708, 0.1608])

解析打印出来裁剪使用json文件中的内容,如下

import json
import pprint
pp = pprint.PrettyPrinter(2)

with open(demo_crop_data.cropped_json_path) as f:
    d = json.load(f)
    pp.pprint(d)

bounding_polygon = np.array(d["bounding_polygon"])
bounding_polygon_data = o3d.geometry.PointCloud()
bounding_polygon_data.points = o3d.utility.Vector3dVector(bounding_polygon)
bounding_polygon_data.paint_uniform_color([1, 0.6, 0])
chair_dat = chair.random_down_sample(0.6)
hull, _ = chair_dat.compute_convex_hull()
hull_ls = o3d.geometry.LineSet.create_from_triangle_mesh(hull)
hull_ls.paint_uniform_color((1, 0, 0))
o3d.visualization.draw_geometries([bounding_polygon_data, hull_ls, chair_dat, o3d.geometry.TriangleMesh.create_coordinate_frame()])

json文件中的内容为:

{ 'axis_max': 4.022921085357666,
  'axis_min': -0.763413667678833,
  'bounding_polygon': [ [2.     6509309513852526, 0.0, 1.6834473132326844],
                        [2.578642824691715, 0.0, 1.6892074266735244],
                        [2.4625790337552154, 0.0, 1.6665777078297999],
                        [2.2228544982251655, 0.0, 1.6168160446813649],
                        [2.166993206001413, 0.0, 1.6115495157201662],
                        [2.1167895865303286, 0.0, 1.6257706054969348],
                        [2.0634657721747383, 0.0, 1.623021658624539],
                        [2.0568612343437236, 0.0, 1.5853892911207643],
                        [2.1605399001237027, 0.0, 0.9622899325508302],
                        [2.1956669387205228, 0.0, 0.9557274604978507],
                        [2.2191318790575583, 0.0, 0.8873444998210875],
                        [2.248488184792592, 0.0, 0.8704280726701363],
                        [2.6891234157295827, 0.0, 0.941406779889676],
                        [2.7328692490470647, 0.0, 0.9877574067484025],
                        [2.7129337547575547, 0.0, 1.0398850034649203],
                        [2.7592174072415405, 0.0, 1.0692940558509485],
                        [2.768921641945343, 0.0, 1.0953914441371593],
                        [2.685145562545567, 0.0, 1.6307334122162018],
                        [2.671477609998124, 0.0, 1.675524657088997],
                        [2.6579576128816544, 0.0, 1.6819127849749496]],
  'class_name': 'SelectionPolygonVolume',
  'orthogonal_axis': 'Y',
  'version_major': 1,
  'version_minor': 0}

bounding_polygon字段定义了空间中的多边形,axis_max/axis_min定义了与多边形垂直的轴上的最大最小距离。

裁剪mesh的方法

filename = "dragon_recon/dragon_vrip_res2.ply"
dragon_mesh = o3d.io.read_triangle_mesh(filename)
dragon_mesh.triangles = o3d.utility.Vector3iVector(
    np.asarray(dragon_mesh.triangles)[:len(dragon_mesh.triangles) // 2, :])
dragon_mesh.triangle_normals = o3d.utility.Vector3dVector(
    np.asarray(dragon_mesh.triangle_normals)[:len(dragon_mesh.triangle_normals) // 2, :])
dragon_mesh.paint_uniform_color([1, 0.7,0])
print(dragon_mesh.triangles)
o3d.visualization.draw_geometries([dragon_mesh])

裁剪的结果,如下:

Open3D点云和numpy数组的转换

Open3D点云的后端表示是std::vectorEigen::Vector,因此,

  • numpy.array转换成Open3D数组时,需要使用o3d.utility.Vector3dVector
  • PointCloud.points/colors转换成numpy.array时需要使用numpy.asarray
printr_points = np.array([[0, 0, 0], [0, 1, 1], [1, 1, 0], [0, 0, 1]])
four_pc = o3d.geometry.PointCloud()
four_pc.points = o3d.utility.Vector3dVector(four_points)
four_pc.paint_uniform_color([1, 0.2, 0.4])
aabb = four_pc.get_axis_aligned_bounding_box()
aabb.color = (1, 0, 0)
obb = four_pc.get_oriented_bounding_box()
obb.color = (0, 1, 0)
o3d.visualization.draw_geometries([four_pc, aabb, obb, o3d.geometry.TriangleMesh.create_coordinate_frame()])    # 可视化点云

点云的bounding box

open3d.geometry.PointCloud类中有get_axis_aligned_bounding_boxget_oriented_bounding_box两个方法可以获取当前点云的最小包围框。

其区别通过一个例子来介绍,

有点[0, 0, 0], [0, 1, 1], [1, 1, 0], [0, 0, 1]

  • get_axis_aligned_bounding_box 如上图,红色部分包围框就是此函数求得的结果,包围矩形的相互平行的四条边都与坐标轴平行,类似2D图像中的水平包围框
  • get_oriented_bounding_box 如上图,绿色部分的包围框就是此函数求得的结果,给出的是空间中的最小包围矩形,类似2D图像中的旋转包围框
printr_points = np.array([[0, 0, 0], [0, 1, 1], [1, 1, 0], [0, 0, 1]])
four_pc = o3d.geometry.PointCloud()
four_pc.points = o3d.utility.Vector3dVector(four_points)
four_pc.paint_uniform_color([1, 0.2, 0.4])
aabb = four_pc.get_axis_aligned_bounding_box()
aabb.color = (1, 0, 0)
obb = four_pc.get_oriented_bounding_box()
obb.color = (0, 1, 0)
o3d.visualization.draw_geometries([four_pc, aabb, obb, o3d.geometry.TriangleMesh.create_coordinate_frame()])    # 可视化点云

完整的例子见仓库https://gitee.com/lx_r/object_detection_task/tree/main/detection3d/open3d



欢迎访问个人网络日志🌹🌹知行空间🌹🌹


  • 1.https://github.com/isl-org/Open3D/blob/master/examples/python/visualization/draw.py

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

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

相关文章

QT(9.3)定时器,绘制事件

作业&#xff1a; 自定义一个闹钟 pro文件&#xff1a; QT core gui texttospeechgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecat…

C#,《小白学程序》第八课:列表(List)其二,编制《高铁列车时刻表》与时间DateTime

1 文本格式 /// <summary> /// 车站信息类 class /// </summary> public class Station { /// <summary> /// 编号 /// </summary> public int Id { get; set; } 0; /// <summary> /// 车站名 /// </summary&g…

2023年项目进度管理平台排行榜

项目进度管理是项目管理学科中的一门重要课程&#xff0c;通过合理的项目计划&#xff0c;有效控制项目进度&#xff0c;保障项目能够按时交付。 不过&#xff0c;项目进度管理并不是一件简单的工作&#xff0c;不仅需要面对项目过程中各种突发情况&#xff0c;还需要做好团队协…

函数指针与std::function<>对回调函数的实现与性能分析

函数指针与std::function<>都可以作为函数形参&#xff0c;通过接受另一个函数的地址来实现回调函数的功能&#xff0c;但是它们之间的性能差异非常明显。下面分别介绍对回调函数的实现与各自的性能分析。 函数指针与std::function<>对回调函数的实现 先在类中分…

植物大战僵尸植物僵尸表(一)

前言 此文章为“植物大战僵尸”专栏中的第005刊&#xff08;2023年9月第一刊&#xff09;。 警告&#xff1a; 1.仅适用于无名版&#xff1b; 2.可能存在遗漏&#xff0c;如发现请联系作者。 植物表 植物名称植物图片豌豆射手寒冰射手双发豌豆射手机枪射手裂荚射手三线射手…

IDEA提示忽略大小写

IDEA提示忽略大小写 IDEA代码提示默认是区分大小写的&#xff0c;设置为提示忽略大小写&#xff0c;编译我们后期的开发

【Unity编辑器扩展】 | 编辑器扩展 特性(Attribute) 整理总结 | 建议收藏

前言【Unity编辑器扩展】 | 编辑器扩展 特性(Attribute) 整理总结 | 建议收藏Unity中Attribute的作用一、System命名空间SerializableNonSerialized二、UnityEngine命名空间AddComponentMenuAssemblyIsEditorAssemblyColorUsageContextMenuContextMenuItemCreateAssetMenu

单片机第二季:温度传感器DS18B20

目录 1&#xff0c;DS18B20介绍 2&#xff0c;DS18B20数据手册 2.1&#xff0c;初始化时序 2.2&#xff0c;读写时序 3&#xff0c;DS18B20工作流程 4&#xff0c;代码 1&#xff0c;DS18B20介绍 DS18B20的基本特征&#xff1a; (1)内置集成ADC&#xff0c;外部数字接…

nginx-error错误页面

客户访问发生错误时&#xff0c;nginx返回给客户的错误页面。 例&#xff1a;客户访问的资源不存在时&#xff0c;返回302并跳转到一个网站。 2.可以返回200&#xff0c;给客户返回一个401.html的页面&#xff0c;这个页面可以做的友好一点&#xff0c;返回给客户。

【Java实战项目】【超详细过程】—大饼的图片服务器01

目录 一、该图片服务器的功能二、设计数据库设计前后端交互设计新增图片查看所有图片属性查看指定图片属性删除指定图片查看部分图片内容 一、该图片服务器的功能 1.可以选择文件上传或删除 2.拥有防盗功能 3.展示图片 二、设计 数据库设计 图片表中需要储存的数据有&#…

zabbix企业微信告警

目前&#xff0c;企业微信使用要设置可信域名 华为云搜索云函数 创建函数 选择http函数&#xff0c;随便输入函数名字 回到函数列表&#xff0c;选择刚创建的函数&#xff0c;创建触发器&#xff0c;安全模式选择none 点击右上角管理 选刚创建的api&#xff0c;右边操作点…

JVM中JAVA对象和数组内存布局

对象 数组 在Java中&#xff0c;所有的对象都是一种特殊的数组&#xff0c;它们的元素可以是基本数据类型、其他对象引用或者其他任何类型。Java对象和数组的内存布局包含以下部分&#xff1a; 1.对象头&#xff08;Object Header&#xff09; 每个Java对象都有一个对象头&am…

关于异或的小疑惑

今天写c&#xff0c;当我写出如下代码时&#xff0c;编译器报错了 #include<bits/stdc.h>using namespace std;int main(){int a1,b3,c2,d6;// cout<<(a^b^c^d)<<endl;cout<<a^b^c^d<<endl;return 0; } D:\sublineText\demo\demo.cpp: In funct…

UE4 Physics Constraint Actor 实现钟摆效果

放入场景&#xff0c;然后将一个球体放入场景 选择小球 将小球改为Movable 选择模拟物理&#xff0c;并将小球移除平衡点 就实现了

SAP-PP:基础概念笔记-5(物料主数据的工作计划视图)

文章目录 前言一、工作计划视图Production Supervisor 生产管理员生产计划参数文件序列号参数文件&#xff1a;序列化级批次管理批次管理工厂&#xff1a;需要批量记录&#xff1a;批量输入&#xff1a;不足交货允差 Underdelivery Tolerance&#xff1a;过度交货允差 Overdeli…

SAP-Tech:SAP EDI出站流程处理组件概念

文章目录 出站流程所使用的组件IDoc结构选择程序消息控制端口定义RFC目的地合作伙伴文件服务程序和配置表 总结 出站流程所使用的组件 出站流程使用了 IDoc类型&#xff0c;消息控制&#xff0c;伙伴文件&#xff0c;选择程序&#xff0c;服务程序&#xff0c;和生成IDoc的表。…

Linux驱动中常用的一些接口函数(经典)

​第一&#xff1a;设备树相关 查找节点的of函数 of_find_node_by_name struct device_node *of_find_node_by_name(struct device_node *from, const char *name);通过节点名字查找指定的节点 from&#xff1a;要开始查找的节点 name&#xff1a;节点名字 of_find_node_…

CSS 滚动驱动动画 scroll()

CSS 滚动驱动动画 scroll() animation-timeline 通过 scroll() 指定可滚动元素与滚动轴来为容器动画提供一个匿名的 scroll progress timeline. 通过元素在顶部和底部(或左边和右边)的滚动推进 scroll progress timeline. 并且元素滚动的位置会被转换为百分比, 滚动开始被转化为…

Nginx详解 四:重写功能

文章目录 1. 重写功能简介2. if 指令2.1 基本语法 3. return 指令3.1 语法格式3.2 示例3.2.1 状态码及响应报文返回3.2.2 URL返回 4. set 指令4.1 基本语法4.2 示例 5. break 指令5.1 示例 6. rewrite 指令6.1 语法格式6.2 rewrite flag部分使用介绍6.3 示例6.3.1 重写URL路径:…

攻防世界-Broadcast

原题 解题思路 原以为要运行py文件&#xff0c;结果打开就有