easyidp.pointcloud.PointCloud#
- class easyidp.pointcloud.PointCloud(pcd_path='', offset=[0.0, 0.0, 0.0])#
EasyIDP defined PointCloud class, consists by point coordinates, and optionally point colors and point normals.
- __init__(pcd_path='', offset=[0.0, 0.0, 0.0])#
The method to initialize the PointCloud class
- パラメータ:
pcd_path (str, optional) -- The point cloud file path for loading/reading, by default "", means create an empty point cloud class
offset (list, optional) --
This parameter is used to specify your own offsets rather than the automatically calculated one.
注釈
When the point cloud xyz value is too large, need to deduct duplicate values (minus offsets) to save the memory cost and increase the precision.
注意
For some Pix4D produced pointcloud, the point cloud itself has been offseted, need manually add the offset value back.
サンプル
Prepare
Cancel the numpy scientific counting method display:
>>> import numpy as np >>> np.set_printoptions(suppress=True)
Package loading:
>>> import easyidp as idp >>> test_data = idp.data.TestData()
Read large xyz point cloud
Most point cloud use the CRS (GPS) coordianate as xyz values directly.
>>> 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]])
If store these values directly, will cost a lot of memeory with precision loss. But with offsets, the data can be stored more neatly in the 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]])
Manually specify offset
The previous offset is calculated automatically by EasyIDP, you can also manually specify the offset values:
>>> 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]])
Though the inner stored values changed, it does not affect the final point valus:
>>> 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]])
Read Pix4D offseted point cloud and add offset back
If you read the Pix4D produced point cloud directly:
>>> 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
Here the xyz seems not the correct one, when we check the Pix4D project
{name}_offset.xyz
file in the param folders, we can find the offset values stored by 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']
This often requires user manually add that offset back to point cloud. But EasyIDP supports dealing with such situation easily:
>>> 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
注釈
You can also obtain the
p4d_offset_np
byeasyidp.Pix4D
object:>>> 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.])
And feed it to the previous function:
>>> pcd = idp.PointCloud(test_data.pcd.lotus_ply_bin, p4d.offset_np)
Methods
__init__
([pcd_path, offset])The method to initialize the PointCloud class
clear
()Delete all points and make an empty point cloud
crop_point_cloud
(polygon_xy)crop the point cloud along z axis
crop_rois
(roi[, save_folder])Crop several ROIs by given <ROI> or dict object with several polygons and polygon names, along z-axis
Returns True if the point cloud contains point colors.
Returns True if the point cloud contains point normals.
Returns True if the point cloud contains points.
read_point_cloud
(pcd_path)Open a new point cloud file to overwritting current file, support ply, laz, and las.
save
(pcd_path)Save current point cloud to a file, support ply, las, laz format.
update_offset_value
(off_val)Change the offset value without affecting the xyz point values.
write_point_cloud
(pcd_path)Save current point cloud to a file, support ply, las, laz format.
Attributes
The offset value of point cloud
The xyz values of point cloud
the file path to the current point cloud file
the file extension to the current point cloud file
The color (RGB) values of point cloud
The normal vector values of point cloud
The size of point cloud (xyz)
- clear()#
Delete all points and make an empty point cloud
- colors#
The color (RGB) values of point cloud
- crop_point_cloud(polygon_xy)#
crop the point cloud along z axis
- パラメータ:
polygon_xy (nx2 ndarray) -- the polygon xy coords
- 戻り値の型:
<easyidp.PointCloud> object, The cropped point cloud
サンプル
Data prepare:
>>> 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]])
Run this function:
>>> 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_rois(roi, save_folder=None)#
Crop several ROIs by given <ROI> or dict object with several polygons and polygon names, along z-axis
- パラメータ:
roi (easyidp.ROI | dict) --
the <ROI> object created by easyidp.ROI()or dict object with key as roi name and value as coordinatesis_geo (bool, optional) -- whether the given polygon is pixel coords on imarray or geo coords (default)
save_folder (str, optional) -- the folder to save cropped images, use ROI indices as file_names, by default None, means not save.
- 戻り値の型:
dict, The dictionary with key as roi name and value as <idp.PointCloud> object
サンプル
Data prepare:
>>> import easyidp as idp >>> test_data = idp.data.TestData() >>> roi = idp.ROI(test_data.shp.lotus_shp, name_field=0) >>> roi = roi[0:3] >>> header = idp.geotiff.get_header(test_data.pix4d.lotus_dom) >>> roi.change_crs(header['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
Run this function:
>>> out = pcd.crop_rois(roi) >>> out {'N1W1': <easyidp.PointCloud class>, 'N1W2': <easyidp.PointCloud class>, 'N1W3': <easyidp.PointCloud class>}
You can also save the output point cloud to given folder by:
>>> out = pcd.crop_rois(roi, save_folder=r'path/to/save/folder/')
- file_ext#
the file extension to the current point cloud file
- file_path#
the file path to the current point cloud file
- has_colors()#
Returns True if the point cloud contains point colors.
- 戻り値の型:
bool
- has_normals()#
Returns True if the point cloud contains point normals.
- 戻り値の型:
bool
- has_points()#
Returns True if the point cloud contains points.
- 戻り値の型:
bool
- normals#
The normal vector values of point cloud
- property offset#
The offset value of point cloud
注意
If change this value directly, the xyz value of point cloud will also be changed, just like moving the whole point cloud.
サンプル
For example, the point cloud like:
>>> 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.])
Change the offset directly:
>>> 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
注意
If you want to change the offset without affecting the point xyz values, please use
update_offset_value()
- property points#
The xyz values of point cloud
- read_point_cloud(pcd_path)#
Open a new point cloud file to overwritting current file, support ply, laz, and las.
注意
This operation will totally clear all data of current point cloud, and reopen a new point cloud.
- パラメータ:
pcd_path (str | pathlib.Path) -- the path to point cloud file want to open
サンプル
Data prepare:
>>> 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
This operation will totally overwrite the previous point cloud
>>> 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)#
Save current point cloud to a file, support ply, las, laz format.
- パラメータ:
pcd_path (str) -- The file path of saved point cloud, if file extention not given, will use parent point cloud file extention.
- shape#
The size of point cloud (xyz)
- update_offset_value(off_val)#
Change the offset value without affecting the xyz point values.
- パラメータ:
off_val (list | tuple | ndarray) -- The offset values want to set
サンプル
For example, the point cloud like:
>>> 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.])
Change the offset without affecting the xyz values:
>>> 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
注意
If you want to change the offset like moving point cloud (also change the xyz values), please use
offset()
- write_point_cloud(pcd_path)#
Save current point cloud to a file, support ply, las, laz format.
- パラメータ:
pcd_path (str) -- The file path of saved point cloud, if file extention not given, will use parent point cloud file extention.
サンプル
Data prepare:
>>> 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")