Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 116 additions & 12 deletions point_cloud_colorize/las_colorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
"""
Python3

@author: Chris Lucas
@author: Chris Lucas, Arno Timmer
"""

import argparse
import json
from pathlib import Path

import shutil
import pdal

import datetime
from joblib import Parallel, delayed
import os

PDAL_PIPELINE = """{{
"pipeline":[
Expand Down Expand Up @@ -73,26 +75,114 @@ def run_pdal(input_path, output_path, las_srs, wms_url,
'wms_pixel_size': wms_pixel_size,
'wms_max_image_size': wms_max_image_size,
'las_srs': las_srs}

pdalargs_str = json.dumps(pdalargs).replace('"', '\\"')

path = Path(__file__)
path = Path(os.getcwd())

pipeline_json = PDAL_PIPELINE.format(input_file=input_path.as_posix(),
output_file=output_path.as_posix(),
srs=las_srs,
pdalargs=pdalargs_str,
directory=path.parent.as_posix())
directory=path.as_posix())
pipeline = pdal.Pipeline(pipeline_json)
pipeline.validate()
pipeline.execute()


def parallel_coloring(f, i, verbose, tmp_col_path, pdalargs, tmp_col='tmp_col_{}.laz'):
tmp_col = Path(tmp_col_path.joinpath(tmp_col.format(i)))
run_pdal(Path(f), tmp_col,
pdalargs['las_srs'], pdalargs['wms_url'],
pdalargs['wms_layer'], pdalargs['wms_srs'],
pdalargs['wms_version'], pdalargs['wms_format'],
pdalargs['wms_pixel_size'], pdalargs['wms_max_image_size'])

if verbose:
print(f'colored {i} parts of the las at {datetime.datetime.now()}')


def process_files_parallel(input, output, las_srs,
wms_url, wms_layer, wms_srs,
wms_version, wms_format,
wms_pixel_size, wms_max_image_size,
verbose):
"""
:param input_path:
:param output_path:
:param las_srs:
:param verbose:
:return:
"""
if verbose:
print(f'started colorizing parts at {datetime.datetime.now()}')
output_path = Path(output)
if not output_path.is_dir():
raise ValueError('Output should be a directory')

input_path = Path(input)
tmp_div_path = Path(output_path.parent.joinpath('tmp_div'))

if tmp_div_path.exists():
if verbose:
print('Temporary path exists, deleting.')
shutil.rmtree(tmp_div_path)
tmp_div_path.mkdir(parents=True, exist_ok=True)

divide_pipeline = """{{
"pipeline":[
{{
"type": "readers.las",
"filename": "{input_file}"
}},
{{
"type": "filters.divider",
"count": "6"
}},
{{
"type": "writers.las",
"a_srs": "{srs}",
"filename": "{output_path}/tmp_#.laz"
}}
]}}"""

# create pipeline for dividing the las
div_pipeline_json = divide_pipeline.format(input_file=input_path.as_posix(),
srs=las_srs,
output_path=tmp_div_path.as_posix())
pipeline = pdal.Pipeline(div_pipeline_json)
pipeline.validate()
pipeline.execute()

if verbose:
print(f'las is divided at {datetime.datetime.now()}')

pdalargs = {'wms_url': wms_url,
'wms_layer': wms_layer,
'wms_srs': wms_srs,
'wms_version': wms_version,
'wms_format': wms_format,
'wms_pixel_size': wms_pixel_size,
'wms_max_image_size': wms_max_image_size,
'las_srs': las_srs}

# for each of the created las-parts
if verbose:
print(f'start parallel processing at {datetime.datetime.now()}')

Parallel(n_jobs=6)(delayed(parallel_coloring)(f, i, verbose, output_path, pdalargs) for i, f in
enumerate(Path(tmp_div_path).iterdir(), 1))

if verbose:
print(f'colorizing in parts finished at {datetime.datetime.now()}')


def process_files(input_path, output_path, las_srs,
wms_url, wms_layer, wms_srs,
wms_version, wms_format, wms_pixel_size,
wms_max_image_size, verbose=False):
"""
Run the pdal pipeline for the input files.

Parameters
----------
input_path : str
Expand Down Expand Up @@ -224,7 +314,14 @@ def argument_parser():
'(int, default: 1000)'),
required=False,
default=1000)
parser.add_argument('-V', '--verbose', default=False, action="store_true",
parser.add_argument('-d', '--divide',
default=5,
action="store_true",
help='Divide the point cloud in a given number of '
'smaller areas which are colored seperately')
parser.add_argument('-V', '--verbose',
default=False,
action="store_true",
help='Set verbose.')
args = parser.parse_args()
return args
Expand All @@ -235,11 +332,18 @@ def main():
Run the application.
"""
args = argument_parser()
process_files(args.input, args.output, args.las_srs,
args.wms_url, args.wms_layer, args.wms_srs,
args.wms_version, args.wms_format,
args.wms_pixel_size, args.wms_max_image_size,
args.verbose)
if args.divide:
process_files_parallel(args.input, args.output, args.las_srs,
args.wms_url, args.wms_layer, args.wms_srs,
args.wms_version, args.wms_format,
args.wms_pixel_size, args.wms_max_image_size,
args.verbose)
else:
process_files(args.input, args.output, args.las_srs,
args.wms_url, args.wms_layer, args.wms_srs,
args.wms_version, args.wms_format,
args.wms_pixel_size, args.wms_max_image_size,
args.verbose)


if __name__ == '__main__':
Expand Down
Empty file.
26 changes: 26 additions & 0 deletions point_cloud_colorize/tests/create_test_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import json
from typing import Tuple

import pdal
import wget


def crop_tile(bounds: Tuple[float, float, float, float] = (139703.2, 556571.8, 139717.1, 556581.8)) -> None:
x_min, y_min, x_max, y_max = bounds
pdal_pipeline = {
"pipeline": [
"09HN2.LAZ",
{"type": "filters.crop", "bounds": f"([{x_min}, {y_min}], [{x_max}, {y_max}])"},
{"type": "writers.las", "filename": "test.laz"}
]
}
pipeline = pdal.Pipeline(json.dumps(pdal_pipeline))
pipeline.validate()
pipeline.execute()


if __name__ == '__main__':
url = 'https://geodata.nationaalgeoregister.nl/ahn3/extract/ahn3_laz/C_09HN2.LAZ'
wget.download(url, '09HN2.LAZ')

crop_tile()
2 changes: 2 additions & 0 deletions point_cloud_colorize/tests/data/input/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Input data directory
This is the directory for storing the input data
Binary file added point_cloud_colorize/tests/data/input/simple.laz
Binary file not shown.
2 changes: 2 additions & 0 deletions point_cloud_colorize/tests/data/output/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Output data directory
This is the directory for storing the output data
Binary file added point_cloud_colorize/tests/test.laz
Binary file not shown.
42 changes: 42 additions & 0 deletions point_cloud_colorize/tests/test_colorize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import os
import unittest

from point_cloud_colorize.las_colorize import process_files, process_files_parallel

class TestColorizePointcloud(unittest.TestCase):
def test_unparrallel_processing(self) -> None:
with self.subTest('It fails if the colorizing fails'):
input_laz = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test.laz')
output_laz = 'test_out.laz'

process_files(input_path=input_laz,
output_path=output_laz,
las_srs='EPSG:28992',
wms_url='https://geodata.nationaalgeoregister.nl/luchtfoto/rgb/wms?',
wms_layer='Actueel_ortho25',
wms_srs='EPSG:28992',
wms_version='1.3.0',
wms_format='image/png',
wms_pixel_size=0.25,
wms_max_image_size=1000,
verbose=False)

def test_parrallel_processing(self) -> None:
with self.subTest('It fails if the colorizing fails'):

input_laz = os.path.join(os.path.dirname(os.path.abspath(__file__)),'test.laz')
output_laz = 'test_out_dir'

process_files_parallel(input=input_laz,
output=output_laz,
las_srs='EPSG:28992',
wms_url='https://geodata.nationaalgeoregister.nl/luchtfoto/rgb/wms?',
wms_layer='Actueel_ortho25',
wms_srs='EPSG:28992',
wms_version='1.3.0',
wms_format='image/png',
wms_pixel_size=0.25,
wms_max_image_size=1000,
verbose=False)