前言
在连接服务器训练和推理代码时,有些时候需要用open3d
查看运行结果(例如:6DoF机械臂抓取结果可视化展示)。open3d
的.draw
方法通过生成一个窗口来实现可视化数据。这种可视化原理导致它在服务器(一众没有GUI界面的运行环境)上是行不通的。因此需要一种在服务器上也能使用open3d
进行点云等类型数据可视化的方法,方便我们可视化服务器上代码的运行结果。
策略1:.draw_plotly方法
前言部分说过,open3d
的可视化机制是创建一个窗口,而服务器是没有GUI窗口环境的,所以一种解决策略就是将open3d
创建的窗口传回本地电脑,例如使用X11连接ssh。但是此种方案比较麻烦,而且我尝试过网上很多的连接教程, 最后都失败了。放弃这种方法。
目前找到的方法是:在服务器上创建一个jupyternotebook
文件,在文件里使用o3d.visualization.draw_plotly
方法进行可视化,这样可以让open3d
在单元格下创建类似图像的可视化窗口,而不是新开一个专用的窗口。
举一个简单的例子,现在使用numpy
创建一个有100个点的点云数据,采用上述方法在服务器中的notebook
文件中可视化:
import open3d as o3d
import numpy as np
# 生成随机点云数据
point_cloud_np = np.random.rand(100, 3)
# 将numpy数组转换为Open3D的PointCloud对象
point_cloud_o3d = o3d.geometry.PointCloud()
point_cloud_o3d.points = o3d.utility.Vector3dVector(point_cloud_np)
# 使用draw_plotly可视化点云
o3d.visualization.draw_plotly([point_cloud_o3d], mesh_show_wireframe=False)
可视化效果如下:
’
可以看到,使用这种方法可以让open3d
把窗口直接显示在当前执行代码块的下方,就像显示图像一样。同时,也可以使用鼠标对数据进行旋转缩放,查看数据的方法和相关功能都相同。
这种方法的好处有:可以直接在服务器上使用open3d可视化数据;同时因为显示背景网格且有刻度,所以可直接鼠标定位点云的位置信息,便于细致观察。它的缺点是:因为背景网格的存在,导致这种方法导出(截图)的图像不能去掉背景,只显示点云数据。难以作为论文里的可视化展示图。
策略2:保存ply本地调用open3d
策略1虽然实现了在服务器上直接可视化数据,但受限于.visualization.draw_plotly
方法无法去掉背景网格,导致它的导出效果不能作为论文里的可视化展出效果图。因此策略2将重点实现去掉背景网络,可视化成论文能用的效果。
策略2的方法其实很简单:将服务器上要展示的数据(点云/mesh)保存成.ply
文件,在本地调用open3d
进行可视化。
下面以numpy生成的点云数据为例,介绍怎么从服务器上保存并在本地展示:
#服务器上的保存程序
import open3d as o3d
import numpy as np
# 假设这是你的点云数据
point_cloud_np = np.random.rand(100, 3)
point_cloud_o3d = o3d.geometry.PointCloud()
point_cloud_o3d.points = o3d.utility.Vector3dVector(point_cloud_np)
# 指定要保存的文件名
file_name = "./your_point_cloud.ply"
# 保存点云数据到PLY文件
o3d.io.write_point_cloud(file_name, point_cloud_o3d)
将"./your_point_cloud.ply"文件下载下来,在本地上运行下面代码就能实现可视化(把程序写在.py文件中):
import open3d as o3d
pointcloud=o3d.io.read_point_cloud('"./your_point_cloud.ply")
o3d.visualization.draw_geometries([pointcloud])
下面重点演示下对与6DoF位姿抓取来说,怎么将可视化结果从服务器下载到本地并进行展示(不是这行的小伙伴直接跳过就行):
从服务器上保存的程序(伪码,需要根据自己当前的程序进行一定的修改才能使用):
#1 保存场景点云数据
# 其中points表示当前场景的点,colors表示每个点的颜色,都是numpy类型
vispc = o3d.geometry.PointCloud()
vispc.points = o3d.utility.Vector3dVector(points)
vispc.colors = o3d.utility.Vector3dVector(colors)
o3d.io.write_point_cloud("./point_cloud.ply", vispc)
#2 保存可行的抓取位姿数据
# 可行抓取位姿grasp_geo是一个list, 里面存储这所有可行的抓取位姿
# 每一个位姿是一个triangle_mesh类型的数据
# 合并每一个抓取位姿保存进一个文件
# 使用reduce函数和lambda表达式将所有的三角网格合并为一个
from functools import reduce
combined_mesh = reduce(lambda combined, current: combined + current, grasp_geo)
# 保存合并后的三角网格到一个文件
o3d.io.write_triangle_mesh("./grasp.ply", combined_mesh)
以HGGD-grasp抓取代码中的demo.py为例,可以通过将原代码236行的if vis_grasp:
更改成下面的代码,实现保存当前预测结果:
if vis_grasp:
print('pred grasp num ==', len(pred_gg))
grasp_geo = pred_gg.to_open3d_geometry_list()
points = view_points[..., :3].cpu().numpy().squeeze()
colors = view_points[..., 3:6].cpu().numpy().squeeze()
vispc = o3d.geometry.PointCloud()
vispc.points = o3d.utility.Vector3dVector(points)
vispc.colors = o3d.utility.Vector3dVector(colors)
# o3d.visualization.draw_geometries([vispc] + grasp_geo)
o3d.io.write_point_cloud("./point_cloud.ply", vispc)
from functools import reduce
combined_mesh = reduce(lambda combined, current: combined + current, grasp_geo)
o3d.io.write_triangle_mesh("./grasp.ply", combined_mesh)
在本地加载并运行:
import open3d as o3d
pointcloud=o3d.io.read_point_cloud('./point_cloud.ply')
grasp = o3d.io.read_triangle_mesh('./grasp.ply')
o3d.visualization.draw_geometries([pointcloud, grasp])
运行效果如下:
’
这种方法展示的结果就和论文中的效果是一样的了。要注意:对于抓取问题来说,它的可视化抓取姿势实际上是一系列的mesh夹爪,可视化也就是场景点云与mesh夹爪的堆叠效果。
总结
为实现可视化服务器上的open3d数据,本文提供了上述两种解决策略。这两种方法各有优劣,在实际情况中可以根据自己需求灵活调用。