easyidp.pointcloud.PointCloud

class easyidp.pointcloud.PointCloud(pcd_path='', offset=[0.0, 0.0, 0.0])

EasyIDP定义的PointCloud类,由点坐标以及可选的点颜色和点法线组成。

__init__(pcd_path='', offset=[0.0, 0.0, 0.0])

初始化PointCloud类的方法

参数:
  • pcd_path (str, optional) -- 用于加载/读取的点云文件路径,默认值为"",表示创建一个空的点云类

  • offset (list, optional) -- 此参数用于指定您自己的偏移量,而不是自动计算的偏移量。 .. 注意:: 当点云xyz值过大时,需要扣除重复值(减去偏移量)以节省内存成本并提高精度。 .. 警告:: 对于某些Pix4D生成的点云,点云本身已被偏移,需要手动添加偏移值。

示例

准备

取消numpy科学计数法显示:

>>> import numpy as np
>>> np.set_printoptions(suppress=True)

包加载:

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

读取大型xyz点云

大多数点云直接使用CRS(GPS)坐标作为xyz值。

>>> pcd = idp.PointCloud(test_data.pcd.maize_las)
>>> pcd.points
array([[ 367993.0206, 3955865.095 ,      57.9707],
       [ 367993.146 , 3955865.3131,      57.9703],
       [ 367992.6317, 3955867.2979,      57.9822],
       ...,
       [ 368014.7912, 3955879.4943,      58.0219],
       [ 368014.1528, 3955883.5785,      58.0321],
       [ 368016.7278, 3955874.1188,      57.9668]])

如果直接存储这些值,将会消耗大量内存并且精度会降低。但通过偏移,这些数据可以更整齐地存储在EasyIDP中:

>>> pcd.offset
array([ 367900., 3955800.,       0.])
>>> pcd._points
array([[ 93.0206,  65.095 ,  57.9707],
       [ 93.146 ,  65.3131,  57.9703],
       [ 92.6317,  67.2979,  57.9822],
       ...,
       [114.7912,  79.4943,  58.0219],
       [114.1528,  83.5785,  58.0321],
       [116.7278,  74.1188,  57.9668]])

手动指定偏移量

之前的偏移量由EasyIDP自动计算,您也可以手动指定偏移量:

>>> pcd = idp.PointCloud(test_data.pcd.maize_las, offset=[367800, 3955700, 50])
>>> pcd.offset
array([ 367800., 3955700.,       50.])
>>> pcd._points
array([[193.0206, 165.095 ,   7.9707],
       [193.146 , 165.3131,   7.9703],
       [192.6317, 167.2979,   7.9822],
       ...,
       [214.7912, 179.4943,   8.0219],
       [214.1528, 183.5785,   8.0321],
       [216.7278, 174.1188,   7.9668]])

尽管内部存储的值发生了变化,但这不会影响最终的点值:

>>> pcd.points
array([[ 367993.0206, 3955865.095 ,      57.9707],
       [ 367993.146 , 3955865.3131,      57.9703],
       [ 367992.6317, 3955867.2979,      57.9822],
       ...,
       [ 368014.7912, 3955879.4943,      58.0219],
       [ 368014.1528, 3955883.5785,      58.0321],
       [ 368016.7278, 3955874.1188,      57.9668]])

读取Pix4D偏移的点云并添加偏移值回去

如果您直接读取Pix4D生成的点云:

>>> pcd = idp.PointCloud(test_data.pcd.lotus_ply_bin)
>>> pcd
             x        y        z  r    g    b        nx      ny      nz
    0  -18.908  -15.778   -0.779  123  103  79   nodata  nodata  nodata
    1  -18.908  -15.777   -0.78   124  104  81   nodata  nodata  nodata
    2  -18.907  -15.775   -0.802  123  103  80   nodata  nodata  nodata
  ...  ...      ...      ...      ...  ...  ...     ...     ...     ...
42451  -15.789  -17.961   -0.847  116  98   80   nodata  nodata  nodata
42452  -15.789  -17.939   -0.84   113  95   76   nodata  nodata  nodata
42453  -15.786  -17.937   -0.833  115  97   78   nodata  nodata  nodata

这里的xyz值似乎不正确,当我们检查param文件夹中的Pix4D项目``{name}_offset.xyz``文件时,我们可以找到Pix4D存储的偏移值。

>>> with open(test_data.pix4d.lotus_param / "hasu_tanashi_20170525_Ins1RGB_30m_offset.xyz", 'r') as f:
...     f.readlines()
['368043.000 3955495.000 98.000']

这通常需要用户手动将偏移值添加回点云。但EasyIDP支持轻松处理这种情况:

>>> p4d_offset_np = np.array([368043, 3955495,  98])
>>> pcd = idp.PointCloud(test_data.pcd.lotus_ply_bin, p4d_offset_np)
>>> pcd
                x            y        z  r    g    b        nx      ny      nz
    0  368024.092  3955479.222   97.221  123  103  79   nodata  nodata  nodata
    1  368024.092  3955479.223   97.22   124  104  81   nodata  nodata  nodata
    2  368024.093  3955479.225   97.198  123  103  80   nodata  nodata  nodata
  ...     ...          ...      ...      ...  ...  ...     ...     ...     ...
42451  368027.211  3955477.039   97.153  116  98   80   nodata  nodata  nodata
42452  368027.211  3955477.061   97.16   113  95   76   nodata  nodata  nodata
42453  368027.214  3955477.063   97.167  115  97   78   nodata  nodata  nodata

备注

您还可以通过 easyidp.Pix4D 对象获取 p4d_offset_np

>>> p4d = idp.Pix4D(project_path   = test_data.pix4d.lotus_folder,
...                 raw_img_folder = test_data.pix4d.lotus_photos,
...                 param_folder   = test_data.pix4d.lotus_param))
>>> p4d.offset_np
array([ 368043., 3955495.,      98.])

并将其传递给前面的函数:

>>> pcd = idp.PointCloud(test_data.pcd.lotus_ply_bin, p4d.offset_np)

Methods

__init__([pcd_path, offset])

初始化PointCloud类的方法

change_crs(target_crs)

Change the point cloud coordinate system

clear()

删除所有点并创建一个空的点云

crop_point_cloud(polygon_xy)

沿着z轴切点云

crop_polygon(polygon_xy)

Get all points inside a 2D polygon.

crop_rois(roi[, save_folder])

通过给定的<ROI>或具有多个多边形和多边形名称的字典对象,沿z轴裁剪多个ROI

has_colors()

如果点云包含点颜色,则返回True。

has_normals()

如果点云包含点法线,则返回True。

has_points()

如果点云包含点,则返回True。

read_point_cloud(pcd_path)

打开一个新的点云文件以覆盖当前文件,支持ply、laz和las格式。

save(pcd_path)

将当前点云保存到文件,支持ply、las、laz格式。

update_offset_value(off_val)

更改偏移值而不影响xyz点值。

write_point_cloud(pcd_path)

将当前点云保存到文件,支持ply、las、laz格式。

Attributes

crs

The Coordinate Reference System (CRS) of point cloud

offset

点云的偏移值

points

点云的xyz值

tree

The 2D KDTree of point cloud for fast spatial query

file_path

当前点云文件的文件路径

file_ext

当前点云文件的文件扩展名

colors

点云的颜色(RGB)值

normals

点云的法向量值

shape

点云的大小(xyz)

change_crs(target_crs)

Change the point cloud coordinate system

参数:

target_crs (pyproj.CRS)

clear()

删除所有点并创建一个空的点云

colors

点云的颜色(RGB)值

crop_point_cloud(polygon_xy)

沿着z轴切点云

参数:

polygon_xy (nx2 ndarray) -- 多边形的xy坐标

返回类型:

<easyidp.PointCloud> object, The cropped point cloud

示例

数据准备:

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

>>> pcd = idp.PointCloud(test_data.pcd.lotus_ply_bin)
>>> polygon = np.array([
...     [-18.42576599, -16.10819054],
...     [-18.00066757, -18.05295944],
...     [-16.05021095, -17.63488388],
...     [-16.46848488, -15.66774559],
...     [-18.42576599, -16.10819054]])

运行此函数:

>>> cropped = pcd.crop_point_cloud(polygon)
>>> cropped
             x        y        z  r       g       b           nx      ny      nz
    0  -18.417  -16.119   -0.641  nodata  nodata  nodata  nodata  nodata  nodata
    1  -18.409  -16.169   -0.647  nodata  nodata  nodata  nodata  nodata  nodata
    2  -18.404  -16.142   -0.634  nodata  nodata  nodata  nodata  nodata  nodata
  ...  ...      ...      ...      ...     ...     ...        ...     ...     ...
22419  -16.065  -17.607   -0.699  nodata  nodata  nodata  nodata  nodata  nodata
22420  -16.062  -17.578   -0.678  nodata  nodata  nodata  nodata  nodata  nodata
22421  -16.051  -17.632   -0.692  nodata  nodata  nodata  nodata  nodata  nodata
crop_polygon(polygon_xy)

Get all points inside a 2D polygon.

Uses KDTree with bounding box pre-filtering for fast spatial query, then applies exact polygon containment test.

参数:

polygon_xy (np.ndarray) -- A 2D polygon coordinates with shape (n, 2), representing the boundary vertices in XY plane. The polygon should be closed (first and last point can be same or different).

返回:

The xyz coordinates of points inside the polygon, shape (m, 3). Returns empty array with shape (0, 3) if no points found.

返回类型:

np.ndarray

示例

>>> import easyidp as idp
>>> pcd = idp.PointCloud("path/to/pointcloud.ply")
>>> polygon = np.array([
...     [100.0, 200.0],
...     [110.0, 200.0],
...     [110.0, 210.0],
...     [100.0, 210.0],
...     [100.0, 200.0]
... ])
>>> xyz_inside = pcd.crop_polygon(polygon)
>>> z_values = xyz_inside[:, 2]
crop_rois(roi, save_folder=None)

通过给定的<ROI>或具有多个多边形和多边形名称的字典对象,沿z轴裁剪多个ROI

参数:
  • roi (easyidp.ROI | dict) --

    由easyidp.ROI()创建的<ROI>对象
    或者键为roi名称,值为坐标的字典对象

  • is_geo (bool, optional) -- 给定的多边形是 imarray 上的像素坐标还是地理坐标(默认)

  • save_folder (str, optional) -- 保存裁剪图像的文件夹,使用ROI索引作为文件名,默认值为None,表示不保存。

返回类型:

dict, The dictionary with key as roi name and value as <idp.PointCloud> object

示例

数据准备:

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

>>> roi = idp.ROI(test_data.shp.lotus_shp, name_field=0)
>>> roi = roi[0:3]
>>> dom = idp.GeoTiff(test_data.pix4d.lotus_dom)
>>> roi.change_crs(dom.crs)
<easyidp.ROI> with 3 items
[0]     N1W1
array([[ 368017.7565143 , 3955511.08102276],
       [ 368019.70190232, 3955511.49811902],
       [ 368020.11263046, 3955509.54636219],
       [ 368018.15769062, 3955509.13563382],
       [ 368017.7565143 , 3955511.08102276]])
[1]     N1W2
array([[ 368018.20042946, 3955508.96051697],
       [ 368020.14581791, 3955509.37761334],
       [ 368020.55654627, 3955507.42585654],
       [ 368018.601606  , 3955507.01512806],
       [ 368018.20042946, 3955508.96051697]])
[2]     N1W3
array([[ 368018.64801755, 3955506.84956301],
       [ 368020.59340644, 3955507.26665948],
       [ 368021.00413502, 3955505.31490271],
       [ 368019.04919431, 3955504.90417413],
       [ 368018.64801755, 3955506.84956301]])

>>> pcd = idp.PointCloud(test_data.pix4d.lotus_pcd, offset=[368043, 3955495,  98])
                  x            y        z  r    g    b        nx      ny      nz
      0  368014.849  3955511.333   97.215  51   55   33   nodata  nodata  nodata
      1  368014.853  3955511.352   97.239  49   52   33   nodata  nodata  nodata
      2  368014.865  3955511.485   97.402  46   50   30   nodata  nodata  nodata
    ...     ...          ...      ...      ...  ...  ...     ...     ...     ...
6235710  368055.047  3955482.412   96.997  173  168  170  nodata  nodata  nodata
6235711  368055.051  3955482.407   97.051  154  140  129  nodata  nodata  nodata
6235712  368055.058  3955482.373   97.107  114  93   72   nodata  nodata  nodata

运行此函数:

>>> out = pcd.crop_rois(roi)
>>> out
{'N1W1': <easyidp.PointCloud class>, 'N1W2': <easyidp.PointCloud class>, 'N1W3': <easyidp.PointCloud class>}

您还可以通过以下方式将输出点云保存到给定文件夹:

>>> out = pcd.crop_rois(roi, save_folder=r'path/to/save/folder/')
property crs

The Coordinate Reference System (CRS) of point cloud

file_ext

当前点云文件的文件扩展名

file_path

当前点云文件的文件路径

has_colors()

如果点云包含点颜色,则返回True。

返回类型:

bool

has_normals()

如果点云包含点法线,则返回True。

返回类型:

bool

has_points()

如果点云包含点,则返回True。

返回类型:

bool

normals

点云的法向量值

property offset

点云的偏移值

小心

如果直接更改此值,点云的xyz值也会更改,就像移动整个点云一样。

示例

例如,点云像这样:

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

>>> pts = idp.PointCloud(test_data.pcd.maize_las)
>>> pts
                x            y        z  r    g    b
    0  367993.021  3955865.095   57.971  28   21   17
    1  367993.146  3955865.313   57.97   28   23   19
    2  367992.632  3955867.298   57.982  29   22   18
    ...     ...          ...      ...      ...  ...  ...
49655  368014.791  3955879.494   58.022  33   28   25
49656  368014.153  3955883.578   58.032  30   40   26
49657  368016.728  3955874.119   57.967  25   20   18
>>> pts.offset
array([ 367900., 3955800.,       0.])

直接更改偏移量:

>>> pts.offset = [300, 200, 50]
>>> pts
                x        y        z  r    g    b
    0  393.021  265.095  107.971  28   21   17
    1  393.146  265.313  107.97   28   23   19
    2  392.632  267.298  107.982  29   22   18
    ...  ...      ...      ...      ...  ...  ...
49655  414.791  279.494  108.022  33   28   25
49656  414.153  283.578  108.032  30   40   26
49657  416.728  274.119  107.967  25   20   18

小心

如果您想更改偏移量而不影响点xyz值,请使用 update_offset_value()

property points

点云的xyz值

read_point_cloud(pcd_path)

打开一个新的点云文件以覆盖当前文件,支持ply、laz和las格式。

小心

此操作将完全清除当前点云的所有数据,并重新打开一个新的点云。

参数:

pcd_path (str | pathlib.Path) -- 要打开的点云文件的路径

示例

数据准备:

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

>>> aaa = idp.PointCloud(test_data.pcd.maize_las)
>>> aaa
                x            y        z  r    g    b                        nx                     ny                    nz
    0  367993.021  3955865.095   57.971  28   21   17    -0.031496062992125984    0.36220472440944884    0.9291338582677166
    1  367993.146  3955865.313   57.97   28   23   19     0.08661417322834646     0.07086614173228346    0.9921259842519685
    2  367992.632  3955867.298   57.982  29   22   18    -0.007874015748031496    0.26771653543307083    0.9606299212598425
...     ...          ...      ...      ...  ...  ...  ...                     ...                    ...
49655  368014.791  3955879.494   58.022  33   28   25     0.44881889763779526    -0.14960629921259844    0.8740157480314961
49656  368014.153  3955883.578   58.032  30   40   26     0.44881889763779526    -0.29133858267716534    0.8346456692913385
49657  368016.728  3955874.119   57.967  25   20   18     0.3228346456692913      0.26771653543307083    0.8976377952755905

此操作将完全覆盖之前的点云

>>> aaa.read_point_cloud(test_data.pcd.lotus_las)
>>> aaa
            x        y        z  r    g    b        nx      ny      nz
    0  -18.908  -15.778   -0.779  123  103  79   nodata  nodata  nodata
    1  -18.908  -15.777   -0.78   124  104  81   nodata  nodata  nodata
    2  -18.907  -15.775   -0.802  123  103  80   nodata  nodata  nodata
...  ...      ...      ...      ...  ...  ...     ...     ...     ...
42451  -15.789  -17.961   -0.847  116  98   80   nodata  nodata  nodata
42452  -15.789  -17.939   -0.84   113  95   76   nodata  nodata  nodata
42453  -15.786  -17.937   -0.833  115  97   78   nodata  nodata  nodata
save(pcd_path)

将当前点云保存到文件,支持ply、las、laz格式。

参数:

pcd_path (str) -- 保存的点云文件的路径,如果未给出文件扩展名,将使用父点云文件扩展名。

shape

点云的大小(xyz)

property tree

The 2D KDTree of point cloud for fast spatial query

update_offset_value(off_val)

更改偏移值而不影响xyz点值。

参数:

off_val (list | tuple | ndarray) -- 要设置的偏移值

示例

例如,点云像这样:

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

>>> pts = idp.PointCloud(test_data.pcd.maize_las)
>>> pts
                x            y        z  r    g    b
    0  367993.021  3955865.095   57.971  28   21   17
    1  367993.146  3955865.313   57.97   28   23   19
    2  367992.632  3955867.298   57.982  29   22   18
    ...     ...          ...      ...      ...  ...  ...
49655  368014.791  3955879.494   58.022  33   28   25
49656  368014.153  3955883.578   58.032  30   40   26
49657  368016.728  3955874.119   57.967  25   20   18
>>> pts.offset
array([ 367900., 3955800.,       0.])

更改偏移量而不影响xyz值:

>>> pts.update_offset_value([360000, 3955000, 50])

>>> pts.offset
array([ 360000., 3955000.,      50.])

>>> pts.points
                x            y        z  r    g    b                        nx                     ny                    nz
    0  367993.021  3955865.095   57.971  28   21   17    -0.031496062992125984    0.36220472440944884    0.9291338582677166
    1  367993.146  3955865.313   57.97   28   23   19     0.08661417322834646     0.07086614173228346    0.9921259842519685
    2  367992.632  3955867.298   57.982  29   22   18    -0.007874015748031496    0.26771653543307083    0.9606299212598425
  ...     ...          ...      ...      ...  ...  ...  ...                     ...                    ...
49655  368014.791  3955879.494   58.022  33   28   25     0.44881889763779526    -0.14960629921259844    0.8740157480314961
49656  368014.153  3955883.578   58.032  30   40   26     0.44881889763779526    -0.29133858267716534    0.8346456692913385
49657  368016.728  3955874.119   57.967  25   20   18     0.3228346456692913      0.26771653543307083    0.8976377952755905

小心

如果您想更改偏移量如同移动点云(也更改xyz值),请使用 offset()

write_point_cloud(pcd_path)

将当前点云保存到文件,支持ply、las、laz格式。

参数:

pcd_path (str) -- 保存的点云文件的路径,如果未给出文件扩展名,将使用父点云文件扩展名。

示例

数据准备:

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

>>> pcd = idp.PointCloud(test_data.pcd.lotus_ply_bin)
>>> polygon = np.array([
...     [-18.42576599, -16.10819054],
...     [-18.00066757, -18.05295944],
...     [-16.05021095, -17.63488388],
...     [-16.46848488, -15.66774559],
...     [-18.42576599, -16.10819054]])

>>> cropped = pcd.crop_point_cloud(polygon)
>>> cropped
             x        y        z  r       g       b           nx      ny      nz
    0  -18.417  -16.119   -0.641  nodata  nodata  nodata  nodata  nodata  nodata
    1  -18.409  -16.169   -0.647  nodata  nodata  nodata  nodata  nodata  nodata
    2  -18.404  -16.142   -0.634  nodata  nodata  nodata  nodata  nodata  nodata
  ...  ...      ...      ...      ...     ...     ...        ...     ...     ...
22419  -16.065  -17.607   -0.699  nodata  nodata  nodata  nodata  nodata  nodata
22420  -16.062  -17.578   -0.678  nodata  nodata  nodata  nodata  nodata  nodata
22421  -16.051  -17.632   -0.692  nodata  nodata  nodata  nodata  nodata  nodata

Use this function:

>>> cropped.write_point_cloud(r"path/to/save/pointcloud.ply")