From ab89453ab7c307a8edebcbda17bebfdde6594f68 Mon Sep 17 00:00:00 2001 From: Antoine Lavenant Date: Fri, 28 Jun 2024 11:00:44 +0200 Subject: [PATCH 1/5] add fn to remove dimensions into las --- .gitignore | 1 + pdaltools/las_remove_dimensions.py | 58 ++++++++++++++++++++++++++++++ test/test_las_remove_dimensions.py | 51 ++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 pdaltools/las_remove_dimensions.py create mode 100644 test/test_las_remove_dimensions.py diff --git a/.gitignore b/.gitignore index b5f6a44..08af87f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ tmp __pycache__ ign_pdal_tools.egg-info dist +.idea* diff --git a/pdaltools/las_remove_dimensions.py b/pdaltools/las_remove_dimensions.py new file mode 100644 index 0000000..0063d0a --- /dev/null +++ b/pdaltools/las_remove_dimensions.py @@ -0,0 +1,58 @@ +import argparse +import os + +import pdal +from pdaltools.las_info import get_writer_parameters_from_reader_metadata + +def remove_dimensions_from_las(input_las: str, dimensions: [str], output_las: str): + """ + export new las without some dimensions + """ + pipeline = pdal.Pipeline() | pdal.Reader.las(input_las) + pipeline.execute() + points = pipeline.arrays[0] + input_dimensions = list(points.dtype.fields.keys()) + output_dimensions = [dim for dim in input_dimensions if dim not in dimensions] + points_pruned = points[output_dimensions] + params = get_writer_parameters_from_reader_metadata(pipeline.metadata) + pipeline_end = pdal.Pipeline(arrays=[points_pruned]) + pipeline_end |= pdal.Writer.las(output_las, forward="all", **params) + pipeline_end.execute() + + +def parse_args(): + parser = argparse.ArgumentParser("Remove dimensions from las") + parser.add_argument( + "--input_las", + "-i", + type=str, + required=True, + help="Path to the the las for which the dimensions will be removed", + ) + parser.add_argument( + "--output_las", + "-o", + type=str, + required=False, + help="Path to the the output las ; if none, we replace the input las", + ) + parser.add_argument( + "--dimensions", + "-d", + type=str, + required=True, + nargs="+", + help="The dimension we would like to remove from the point cloud file ; be aware to not remove mandatory " + "dimensions of las" + ) + + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + remove_dimensions_from_las( + input_las=args.input_las, + dimensions=args.dimensions, + output_las=args.input_las if args.output_las is None else args.output_las, + ) diff --git a/test/test_las_remove_dimensions.py b/test/test_las_remove_dimensions.py new file mode 100644 index 0000000..825931a --- /dev/null +++ b/test/test_las_remove_dimensions.py @@ -0,0 +1,51 @@ +import tempfile +import pdal +import numpy +import os +import logging +import pytest + +from pdaltools import las_remove_dimensions + +TEST_PATH = os.path.dirname(os.path.abspath(__file__)) +INPUT_DIR = os.path.join(TEST_PATH, "data") + + +def get_points(input_las): + pipeline_read_ini = pdal.Pipeline() | pdal.Reader.las(input_las) + pipeline_read_ini.execute() + return pipeline_read_ini.arrays[0] + + +def test_remove_dimension(): + ini_las = os.path.join(INPUT_DIR, "test_data_77055_627760_LA93_IGN69.laz") + added_dimensions = ["DIM_1", "DIM_2"] + + # get initial data + points_ini = get_points(ini_las) + + with tempfile.NamedTemporaryFile(suffix="_add.las") as tmp_las: + # append dimensions + pipeline = pdal.Pipeline() + pipeline |= pdal.Reader.las(ini_las) + pipeline |= pdal.Filter.ferry(dimensions="=>" + ", =>".join(added_dimensions)) + pipeline |= pdal.Writer.las(tmp_las.name, extra_dims="all", forward="all", ) + pipeline.execute() + + # remove all dimensions + with tempfile.NamedTemporaryFile(suffix="_rm.las") as tmp_las_rm: + las_remove_dimensions.remove_dimensions_from_las(tmp_las.name, added_dimensions, tmp_las_rm.name) + points_end = get_points(tmp_las_rm.name) + assert numpy.array_equal(points_ini, points_end) # output data should be the same + + # remove one dimension + with tempfile.NamedTemporaryFile(suffix="_rm.las") as tmp_las_rm: + las_remove_dimensions.remove_dimensions_from_las(tmp_las.name, added_dimensions[:1] , tmp_las_rm.name) + points_end = get_points(tmp_las_rm.name) + with pytest.raises(Exception): + numpy.array_equal(points_ini, points_end) # output data should not be the same + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + test_remove_dimension() From 962978d84ca5acb638e5fdec8981f0f385c2d408 Mon Sep 17 00:00:00 2001 From: Antoine Lavenant Date: Fri, 28 Jun 2024 11:17:28 +0200 Subject: [PATCH 2/5] update gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 08af87f..b0e7f80 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ tmp __pycache__ ign_pdal_tools.egg-info dist -.idea* +*.idea* From cff006b493077405d756e047acaeb337bf322310 Mon Sep 17 00:00:00 2001 From: Antoine Lavenant Date: Fri, 28 Jun 2024 11:49:38 +0200 Subject: [PATCH 3/5] split tests --- CHANGELOG.md | 3 +++ test/test_las_remove_dimensions.py | 23 +++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04278b2..79319ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# 1.7.0 +- las_remove_dimension: new tool to remove one or many dimensions + # 1.6.0 - color: choose streams for RGB colorization, and IRC colorization (doc https://geoservices.ign.fr/services-web-experts-ortho) - color: detect white images. diff --git a/test/test_las_remove_dimensions.py b/test/test_las_remove_dimensions.py index 825931a..1532630 100644 --- a/test/test_las_remove_dimensions.py +++ b/test/test_las_remove_dimensions.py @@ -10,6 +10,8 @@ TEST_PATH = os.path.dirname(os.path.abspath(__file__)) INPUT_DIR = os.path.join(TEST_PATH, "data") +ini_las = os.path.join(INPUT_DIR, "test_data_77055_627760_LA93_IGN69.laz") +added_dimensions = ["DIM_1", "DIM_2"] def get_points(input_las): pipeline_read_ini = pdal.Pipeline() | pdal.Reader.las(input_las) @@ -17,9 +19,7 @@ def get_points(input_las): return pipeline_read_ini.arrays[0] -def test_remove_dimension(): - ini_las = os.path.join(INPUT_DIR, "test_data_77055_627760_LA93_IGN69.laz") - added_dimensions = ["DIM_1", "DIM_2"] +def test_remove_all_dimension(): # get initial data points_ini = get_points(ini_las) @@ -38,6 +38,20 @@ def test_remove_dimension(): points_end = get_points(tmp_las_rm.name) assert numpy.array_equal(points_ini, points_end) # output data should be the same + +def test_remove_one_dimension(): + + # get initial data + points_ini = get_points(ini_las) + + with tempfile.NamedTemporaryFile(suffix="_add.las") as tmp_las: + # append dimensions + pipeline = pdal.Pipeline() + pipeline |= pdal.Reader.las(ini_las) + pipeline |= pdal.Filter.ferry(dimensions="=>" + ", =>".join(added_dimensions)) + pipeline |= pdal.Writer.las(tmp_las.name, extra_dims="all", forward="all", ) + pipeline.execute() + # remove one dimension with tempfile.NamedTemporaryFile(suffix="_rm.las") as tmp_las_rm: las_remove_dimensions.remove_dimensions_from_las(tmp_las.name, added_dimensions[:1] , tmp_las_rm.name) @@ -48,4 +62,5 @@ def test_remove_dimension(): if __name__ == "__main__": logging.basicConfig(level=logging.INFO) - test_remove_dimension() + test_remove_all_dimension() + test_remove_one_dimension() From ce9ab5eedde4c4a68a24f080acacd8fceb6ea711 Mon Sep 17 00:00:00 2001 From: Antoine Lavenant Date: Fri, 28 Jun 2024 15:34:43 +0200 Subject: [PATCH 4/5] update tests --- CHANGELOG.md | 4 +-- test/test_las_remove_dimensions.py | 39 +++++++++++++++--------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79319ad..a35552f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,7 @@ -# 1.7.0 -- las_remove_dimension: new tool to remove one or many dimensions - # 1.6.0 - color: choose streams for RGB colorization, and IRC colorization (doc https://geoservices.ign.fr/services-web-experts-ortho) - color: detect white images. +- las_remove_dimension: new tool to remove one or many dimensions # 1.5.2 - refactor tool to propagate header infos from one pipeline to another to use it by itself diff --git a/test/test_las_remove_dimensions.py b/test/test_las_remove_dimensions.py index 1532630..00eb282 100644 --- a/test/test_las_remove_dimensions.py +++ b/test/test_las_remove_dimensions.py @@ -13,11 +13,18 @@ ini_las = os.path.join(INPUT_DIR, "test_data_77055_627760_LA93_IGN69.laz") added_dimensions = ["DIM_1", "DIM_2"] -def get_points(input_las): +def get_points(input_las : str): pipeline_read_ini = pdal.Pipeline() | pdal.Reader.las(input_las) pipeline_read_ini.execute() return pipeline_read_ini.arrays[0] +def append_dimension(input_las : str, output_las : str): + pipeline = pdal.Pipeline() + pipeline |= pdal.Reader.las(input_las) + pipeline |= pdal.Filter.ferry(dimensions="=>" + ", =>".join(added_dimensions)) + pipeline |= pdal.Writer.las(output_las, extra_dims="all", forward="all", ) + pipeline.execute() + def test_remove_all_dimension(): @@ -25,15 +32,9 @@ def test_remove_all_dimension(): points_ini = get_points(ini_las) with tempfile.NamedTemporaryFile(suffix="_add.las") as tmp_las: - # append dimensions - pipeline = pdal.Pipeline() - pipeline |= pdal.Reader.las(ini_las) - pipeline |= pdal.Filter.ferry(dimensions="=>" + ", =>".join(added_dimensions)) - pipeline |= pdal.Writer.las(tmp_las.name, extra_dims="all", forward="all", ) - pipeline.execute() - - # remove all dimensions + append_dimension(ini_las, tmp_las.name) with tempfile.NamedTemporaryFile(suffix="_rm.las") as tmp_las_rm: + # remove all dimensions las_remove_dimensions.remove_dimensions_from_las(tmp_las.name, added_dimensions, tmp_las_rm.name) points_end = get_points(tmp_las_rm.name) assert numpy.array_equal(points_ini, points_end) # output data should be the same @@ -45,18 +46,18 @@ def test_remove_one_dimension(): points_ini = get_points(ini_las) with tempfile.NamedTemporaryFile(suffix="_add.las") as tmp_las: - # append dimensions - pipeline = pdal.Pipeline() - pipeline |= pdal.Reader.las(ini_las) - pipeline |= pdal.Filter.ferry(dimensions="=>" + ", =>".join(added_dimensions)) - pipeline |= pdal.Writer.las(tmp_las.name, extra_dims="all", forward="all", ) - pipeline.execute() - - # remove one dimension + append_dimension(ini_las, tmp_las.name) with tempfile.NamedTemporaryFile(suffix="_rm.las") as tmp_las_rm: - las_remove_dimensions.remove_dimensions_from_las(tmp_las.name, added_dimensions[:1] , tmp_las_rm.name) + # remove one dimension + las_remove_dimensions.remove_dimensions_from_las(tmp_las.name, ["DIM_1"], tmp_las_rm.name) points_end = get_points(tmp_las_rm.name) - with pytest.raises(Exception): + + assert list(points_end.dtype.fields.keys()).index("DIM_2") >= 0# should still contains DIM_2 + + with pytest.raises(ValueError): + list(points_end.dtype.fields.keys()).index("DIM_1") # should not have DIM_1 + + with pytest.raises(TypeError): numpy.array_equal(points_ini, points_end) # output data should not be the same From 71f73ea7e1d4ac8a7edbbdb65ae3216622a57919 Mon Sep 17 00:00:00 2001 From: Antoine Lavenant Date: Fri, 28 Jun 2024 23:25:14 +0200 Subject: [PATCH 5/5] update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a35552f..62e1336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ +- las_remove_dimension: new tool to remove one or many dimensions + # 1.6.0 - color: choose streams for RGB colorization, and IRC colorization (doc https://geoservices.ign.fr/services-web-experts-ortho) - color: detect white images. -- las_remove_dimension: new tool to remove one or many dimensions # 1.5.2 - refactor tool to propagate header infos from one pipeline to another to use it by itself