tout le monde,
Je voudrais recadrer et enregistrer une zone d'un nuage de points et l'enregistrer.
J'ai les coordonnées BBox (maxx, maxy, minx, miny), qui sont les MaxP et MinP du nuage de points et je veux en faire un polygone. Avec bbox_to_Polygon (MaxP, MinP)
les coordonnées BBox sont converties en points d'angle. Ceux-ci doivent être utilisés pour créer deux polygones. À partir de cela, j'avais fait un polyèdre avec pyny3D.
Maintenant je peux nourrir open3d.visualization.SelectionPolygonVolume () avec un volume, ai-je pensé. Je ne veux pas utiliser un fichier JSON comme décrit dans la documentation Open3d Recadrer à partir du cloud . J'ai donc trouvé ce Comment créer un open3d.visualization. Objet SelectionPolygonVolume sans charger un fichier json .
Pourquoi orthogonal_axis = "Y"
? Pourquoi pas seulement l'axe "Z"?
Dans l ' exemple de fichier JSON , les valeurs Y sont 0. Je suggérerais parce que de orthogonal_axis = "Y"
mais je ne comprends pas pourquoi? N'avons-nous pas besoin d'un PolygonVolume?
J'apprécierais de l'aide.
Je travaille avec Google Colab et Jupyter Notebook Python 3.6
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)
Voici tout le code
#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`
3 Réponses :
Vous pouvez choisir n'importe quel axe comme axe_orthogonal. Par exemple, si vous choisissez Z, définissez votre polygone avec un ensemble de points avec Z = 0. Ensuite, définissez vos Z min et max, comme si vous extrudiez un volume en utilisant le polygone entre Z min et max. J'espère que cela vous aidera.
Cet article m'a aidé à aller assez loin pour recadrer un nuage de points dans les limites d'un cuboïde. J'ai également constamment rencontré geometry :: PointCloud avec 0 point
en utilisant vol.crop_point_cloud (pcd)
et je n'ai pas pu le faire fonctionner, mais j'ai trouvé une solution différente.
J'ai fini par faire référence à ce PR # 1218 pour utiliser un open3d.geometry. OrientedBoundingBox volume cuboïde pour rogner le nuage de points. Le code ci-dessous crée un parallélépipède «tuile» de 200 mx 200 m autour d'une position de départ, qui correspond à une pose de départ du véhicule de l'ego dans un nuage de points, et filtre les points qui se trouvent uniquement dans la tuile.
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()
Voici une version abrégée qui montre comment recadrer un nuage de points en utilisant un np.array
de sommets:
""" 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])
Exemple après (il s'agit du bloc bleu de points au centre du nuage):
Pourquoi orthogonal_axis = "Y"? Je pense → entrez la description de l'image ici