[英]Open3D - Crop Pointcloud with Polygon Volume
everyone,每个人,
I would like to crop and save out an area from a point cloud and save it.我想从点云中裁剪并保存一个区域并保存它。
I have the BBox Coordinats (maxx,maxy,minx,miny), which are the MaxP and MinP of the Pointcloud and want to make a polygon out of it.我有 BBox Coordinats (maxx,maxy,minx,miny),它们是 Pointcloud 的 MaxP 和 MinP,我想用它制作一个多边形。 With bbox_to_Polygon(MaxP,MinP)
the BBox coordinates are converted into corner points.使用bbox_to_Polygon(MaxP,MinP)
将 BBox 坐标转换为角点。 These should be used to create two polygons.这些应该用于创建两个多边形。 Out of this i had made a Polyhedron with pyny3D.为此,我用 pyny3D 制作了一个多面体。
Now i can feed open3d.visualization.SelectionPolygonVolume() with a Volume, i thought.现在我可以给 open3d.visualization.SelectionPolygonVolume() 提供一个 Volume,我想。 I dont wanna use a JSON-File like described in the Open3d Docs Crop from Cloud .我不想使用像 Open3d Docs Crop from Cloud中描述的 JSON 文件。 So I found this How to Create a open3d.visualization.SelectionPolygonVolume Object Without Loading a json Filel .所以我发现了这个How to Create a open3d.visualization.SelectionPolygonVolume Object without Loading a json Filel 。
Why is orthogonal_axis="Y"
?为什么orthogonal_axis="Y"
? Why not just the "Z"-axis?为什么不只是“Z”轴? In example of JSON-File the Y values are 0. I would suggest because of orthogonal_axis="Y"
but i dont understand why?在JSON 文件的示例中,Y 值为 0。我建议因为orthogonal_axis="Y"
,但我不明白为什么? Don´t we need a PolygonVolume?我们不需要 PolygonVolume 吗?
I would appreciate some help.我会很感激一些帮助。
I am working with Google Colab and Jupyter Notebook Python 3.6我正在使用 Google Colab 和 Jupyter Notebook Python 3.6
#Vertics Poyhedrol to create a PolygonVolume
bounding_polygon = np.array([
#Vertics Polygon 1
[488.8989868164062, 612.208984375, 286.5320129394531],
[485.114990234375, 612.208984375, 286.5320129394531],
[485.114990234375, 605.0880126953125, 286.5320129394531],
[488.8989868164062, 605.0880126953125, 286.5320129394531],
#Vertics Polygon2
[488.89898681640625, 612.208984375, 291.6619873046875],
[485.114990234375, 612.208984375, 291.6619873046875],
[485.114990234375, 605.0880126953125, 291.6619873046875],
[488.89898681640625, 605.0880126953125, 291.6619873046875]]).astype("float64")
vol = o3d.visualization.SelectionPolygonVolume()
vol.orthogonal_axis = "Y"
vol.axis_max = 500
vol.axis_min = 700
vol.bounding_polygon = o3d.utility.Vector3dVector(bounding_polygon)
comp = vol.crop_point_cloud(pcd)
comp
#Since I took the MaxP and MinP of the Pointcloud as BBCoords I would expect the same number of points. But I get this:
#`geometry::PointCloud with 0 points`
Here is the whole Code这是整个代码
import numpy as np
import pyny3d
import pyny3d.geoms as pyny
import open3d as o3d
from open3d import JVisualizer
path_incloud = ('/gdrive/My Drive/Colab Notebooks/Georeferenzierung/BildGeoreferenzieren/PointCloud/PointCloudFormats/Kranfundament - Cloud.ply')
pcd = o3d.io.read_point_cloud(path_incloud)
print("Input Cloud:", pcd)
visualizer = JVisualizer()
visualizer.add_geometry(pcd)
visualizer.show()
def bbox_to_Polygon(MaxP,MinP):
p1= [MaxP[0], MaxP[1], MinP[2]]
p2= [MaxP[0],MinP[1],MinP[2]]
p3= [MinP[0],MaxP[1],MinP[2]]
p4= MinP
p5= MaxP
p6= [MinP[0],MaxP[1],MaxP[2]]
p7= [MinP[0],MinP[1],MaxP[2]]
p8= [MaxP[0],MinP[1], MaxP[2]]
listPoints1 = [p1,p3,p4,p2]
print(listPoints1)
listPoints2 = [p5,p6,p7,p8]
print(listPoints2)
return listPoints1,listPoints2
MaxP = MaxPoint_PointCloud
MinP = MinPoint_PointCloud
listPointsPoly1 , listPointsPoly2 = bbox_to_Polygon(MaxP= MaxP, MinP=MinP)
poly1 = pyny.Polygon(np.array(listPoints1))
poly2 = pyny.Polygon(np.array(listPoints2))
poly1.plot()
poly2.plot()
polyhedron = pyny.Polyhedron.by_two_polygons(poly1, poly2)
polyhedron.plot('b')
MaxP = MaxPoint_PointCloud
MinP = MinPoint_PointCloud
#Vertics Poyhedrol to create a PolygonVolume
bounding_polygon = np.array([
#Vertics Polygon 1
[488.8989868164062, 612.208984375, 286.5320129394531],
[485.114990234375, 612.208984375, 286.5320129394531],
[485.114990234375, 605.0880126953125, 286.5320129394531],
[488.8989868164062, 605.0880126953125, 286.5320129394531],
#Vertics Polygon2
[488.89898681640625, 612.208984375, 291.6619873046875],
[485.114990234375, 612.208984375, 291.6619873046875],
[485.114990234375, 605.0880126953125, 291.6619873046875],
[488.89898681640625, 605.0880126953125, 291.6619873046875]]).astype("float64")
vol = o3d.visualization.SelectionPolygonVolume()
vol.orthogonal_axis = "Y"
vol.axis_max = 1000
vol.axis_min = -1000
vol.bounding_polygon = o3d.utility.Vector3dVector(bounding_polygon)
comp = vol.crop_point_cloud(pcd)
print("Cropped Cloud",comp)
This post helped me get decently far to crop a point cloud within the bounds of a cuboid.这篇文章帮助我在一个长方体的范围内裁剪了一个点云。 I also consistently ran into geometry::PointCloud with 0 points
using vol.crop_point_cloud(pcd)
and couldn't get it working, but I found a different solution.我也一直使用vol.crop_point_cloud(pcd)
遇到geometry::PointCloud with 0 points
并且无法使其正常工作,但我找到了不同的解决方案。
I ended up referencing this PR #1218 to use an open3d.geometry.OrientedBoundingBox cuboid volume to crop the point cloud.我最终参考了这个 PR #1218来使用 open3d.geometry.OrientedBoundingBox 长方体体积来裁剪点云。 The code below creates a 200m x 200m "tile" cuboid around a start_position, which corresponds to an ego vehicle start pose within a point cloud, and filters the points that only lie within the tile.下面的代码在 start_position 周围创建了一个 200m x 200m 的“平铺”长方体,它对应于点云中的自我车辆起始姿势,并过滤仅位于平铺内的点。
import json
import numpy as np
import open3d as o3d
CUBOID_EXTENT_METERS = 200
METERS_BELOW_START = 5
METERS_ABOVE_START = 30
def main():
## Point Cloud
points = np.array([
## These points lie inside the cuboid
[-2770.94365061042, 722.0595600050154, -20.004812609192445],
[-2755.94365061042, 710.0595600050154, -20.004812609192445],
[-2755.94365061042, 710.0595600050154, -15.004812609192445],
## These points lie outside the cuboid
[-2755.94365061042 + CUBOID_EXTENT_METERS, 710.0595600050154, -15.004812609192445],
[-2755.94365061042, 710.0595600050154 + CUBOID_EXTENT_METERS, -15.004812609192445],
]).reshape([-1, 3])
point_cloud = o3d.geometry.PointCloud()
point_cloud.points = o3d.utility.Vector3dVector(points)
## Start point here corresponds to an ego vehicle position start in a point cloud
start_position = {'x': -2755.94365061042, 'y': 722.0595600050154, 'z': -20.004812609192445}
cuboid_points = getCuboidPoints(start_position)
points = o3d.utility.Vector3dVector(cuboid_points)
oriented_bounding_box = o3d.geometry.OrientedBoundingBox.create_from_points(points)
point_cloud_crop = point_cloud.crop(oriented_bounding_box)
# View original point cloud with the cuboid, all 5 points present
o3d.visualization.draw_geometries([point_cloud, oriented_bounding_box])
# View cropped point cloud with the cuboid, only 3 points present
o3d.visualization.draw_geometries([point_cloud_crop, oriented_bounding_box])
def getCuboidPoints(start_position):
return np.array([
# Vertices Polygon1
[start_position['x'] + (CUBOID_EXTENT_METERS / 2), start_position['y'] + (CUBOID_EXTENT_METERS / 2), start_position['z'] + METERS_ABOVE_START], # face-topright
[start_position['x'] - (CUBOID_EXTENT_METERS / 2), start_position['y'] + (CUBOID_EXTENT_METERS / 2), start_position['z'] + METERS_ABOVE_START], # face-topleft
[start_position['x'] - (CUBOID_EXTENT_METERS / 2), start_position['y'] - (CUBOID_EXTENT_METERS / 2), start_position['z'] + METERS_ABOVE_START], # rear-topleft
[start_position['x'] + (CUBOID_EXTENT_METERS / 2), start_position['y'] - (CUBOID_EXTENT_METERS / 2), start_position['z'] + METERS_ABOVE_START], # rear-topright
# Vertices Polygon 2
[start_position['x'] + (CUBOID_EXTENT_METERS / 2), start_position['y'] + (CUBOID_EXTENT_METERS / 2), start_position['z'] - METERS_BELOW_START],
[start_position['x'] - (CUBOID_EXTENT_METERS / 2), start_position['y'] + (CUBOID_EXTENT_METERS / 2), start_position['z'] - METERS_BELOW_START],
[start_position['x'] - (CUBOID_EXTENT_METERS / 2), start_position['y'] - (CUBOID_EXTENT_METERS / 2), start_position['z'] - METERS_BELOW_START],
[start_position['x'] + (CUBOID_EXTENT_METERS / 2), start_position['y'] - (CUBOID_EXTENT_METERS / 2), start_position['z'] - METERS_BELOW_START],
]).astype("float64")
if __name__ == '__main__':
main()
You can choose any axis as orthogonal_axis.您可以选择任何轴作为正交轴。 For example, if you choose Z, define your polygon with a set of points with Z=0.例如,如果您选择 Z,请使用一组 Z=0 的点来定义您的多边形。 Then set your Z min and max, as if you extrude a volume using the polygon between Z min and max.然后设置 Z 最小值和最大值,就像使用 Z 最小值和最大值之间的多边形挤压体积一样。 Hope this helps.希望这可以帮助。
Here's a shortened version that shows how to crop a point cloud using an np.array
of vertices:这是一个缩短版本,显示如何使用np.array
顶点裁剪点云:
"""
corners = [[ 5.31972845 -3.21384387 0.30217625]
[ 5.34483288 -1.13804348 0.29917539]
[ 7.69983939 -1.16651864 0.30329364]
[ 7.67473496 -3.24231903 0.3062945 ]
[ 5.31845904 -3.21276837 1.03551451]
[ 5.34356348 -1.13696798 1.03251366]
[ 7.69856999 -1.16544314 1.03663191]
[ 7.67346556 -3.24124353 1.03963277]]
"""
corners = np.array(...)
# Convert the corners array to have type float64
bounding_polygon = corners.astype("float64")
# Create a SelectionPolygonVolume
vol = o3d.visualization.SelectionPolygonVolume()
# You need to specify what axis to orient the polygon to.
# I choose the "Y" axis. I made the max value the maximum Y of
# the polygon vertices and the min value the minimum Y of the
# polygon vertices.
vol.orthogonal_axis = "Y"
vol.axis_max = np.max(bounding_polygon[:, 1])
vol.axis_min = np.min(bounding_polygon[:, 1])
# Set all the Y values to 0 (they aren't needed since we specified what they
# should be using just vol.axis_max and vol.axis_min).
bounding_polygon[:, 1] = 0
# Convert the np.array to a Vector3dVector
vol.bounding_polygon = o3d.utility.Vector3dVector(bounding_polygon)
# Crop the point cloud using the Vector3dVector
cropped_pcd = vol.crop_point_cloud(pcd)
# Get a nice looking bounding box to display around the newly cropped point cloud
# (This part is optional and just for display purposes)
bounding_box = cropped_pcd.get_axis_aligned_bounding_box()
bounding_box.color = (1, 0, 0)
# Draw the newly cropped PCD and bounding box
o3d.visualization.draw_geometries([cropped_pcd, bounding_box],
zoom=2,
front=[5, -2, 0.5],
lookat=[7.67473496, -3.24231903, 0.3062945],
up=[1.0, 0.0, 0.0])
Example after (this is from the blue chunk of points in the center of the cloud):之后的示例(这是来自云中心的蓝色点块):
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.