Load LAS file into pcloud format
This commit is contained in:
parent
4431d231de
commit
78c0d12d92
74
idefix/io.py
Normal file
74
idefix/io.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# file io.py
|
||||||
|
# author Florent Guiotte <florent.guiotte@uhb.fr>
|
||||||
|
# version 0.0
|
||||||
|
# date 04 mars 2019
|
||||||
|
"""Abstract
|
||||||
|
|
||||||
|
doc.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
import numpy as np
|
||||||
|
from numpy.lib import recfunctions as rfn
|
||||||
|
import laspy
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def load_las(fname):
|
||||||
|
'''Load a LAS file into idefix point cloud format.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The empty fields from LAS format will be automatically stripped. The fields
|
||||||
|
typing are automatically determined.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
fname : string, Path
|
||||||
|
Path to the LAS file to load.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
pcloud : recarray
|
||||||
|
Point cloud respecting structure::
|
||||||
|
|
||||||
|
[(spatial), (feature, [f1, f2, ..., fn])]
|
||||||
|
'''
|
||||||
|
fname = Path(fname)
|
||||||
|
if not fname.is_file():
|
||||||
|
msg = 'No such file: \'{}\''.format(fname)
|
||||||
|
log.error(msg)
|
||||||
|
raise IOError(msg)
|
||||||
|
|
||||||
|
log.info('Loading LAS file \'{}\'...'.format(fname))
|
||||||
|
infile = laspy.file.File(fname)
|
||||||
|
|
||||||
|
log.debug('Extract spatial data')
|
||||||
|
spatial = np.core.records.fromarrays([np.array((infile.x, infile.y, infile.z)).T],
|
||||||
|
dtype=[('spatial', np.float, 3)])
|
||||||
|
|
||||||
|
log.debug('Extract feature data')
|
||||||
|
feature_data, feature_dtype = [], []
|
||||||
|
for spec in infile.reader.point_format:
|
||||||
|
if spec.name in 'XYZ':
|
||||||
|
continue
|
||||||
|
att = infile.reader.get_dimension(spec.name)
|
||||||
|
if (att == 0).all():
|
||||||
|
log.info('Drop empty \'{}\' feature'.format(spec.name))
|
||||||
|
else:
|
||||||
|
log.info('Load \'{}\' feature'.format(spec.name))
|
||||||
|
feature_data.append(att)
|
||||||
|
feature_dtype.append((spec.name, att.dtype))
|
||||||
|
|
||||||
|
log.debug('Create feature recarray')
|
||||||
|
feature = np.core.records.fromarrays(feature_data, dtype=feature_dtype)
|
||||||
|
del feature_data, feature_dtype
|
||||||
|
|
||||||
|
log.debug('Concatenate pcloud')
|
||||||
|
pcloud = rfn.append_fields(spatial, 'feature', feature, usemask=False, asrecarray=True)
|
||||||
|
|
||||||
|
return pcloud
|
||||||
|
|
||||||
|
|
||||||
35
test/conftest.py
Normal file
35
test/conftest.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# file conftest.py
|
||||||
|
# author Florent Guiotte <florent.guiotte@uhb.fr>
|
||||||
|
# version 0.0
|
||||||
|
# date 04 mars 2019
|
||||||
|
"""Configuration script for PyTest.
|
||||||
|
|
||||||
|
Define in this script:
|
||||||
|
- Fixtures shared among tests
|
||||||
|
- Helpers functions for tests
|
||||||
|
- External plugins
|
||||||
|
- Hooks
|
||||||
|
"""
|
||||||
|
|
||||||
|
from distutils import dir_util
|
||||||
|
from pytest import fixture
|
||||||
|
import os
|
||||||
|
|
||||||
|
@fixture
|
||||||
|
def datadir(tmpdir, request):
|
||||||
|
'''
|
||||||
|
Fixture responsible for searching a folder with the same name of test
|
||||||
|
module and, if available, moving all contents to a temporary directory so
|
||||||
|
tests can use them freely.
|
||||||
|
|
||||||
|
from: https://stackoverflow.com/a/29631801
|
||||||
|
'''
|
||||||
|
filename = request.module.__file__
|
||||||
|
test_dir, _ = os.path.splitext(filename)
|
||||||
|
|
||||||
|
if os.path.isdir(test_dir):
|
||||||
|
dir_util.copy_tree(test_dir, str(tmpdir))
|
||||||
|
|
||||||
|
return tmpdir
|
||||||
|
|
||||||
41
test/test_io.py
Normal file
41
test/test_io.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# file test_io.py
|
||||||
|
# author Florent Guiotte <florent.guiotte@uhb.fr>
|
||||||
|
# version 0.0
|
||||||
|
# date 04 mars 2019
|
||||||
|
"""Idefix IO tests set.
|
||||||
|
|
||||||
|
doc.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import numpy as np
|
||||||
|
from idefix import io
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('fname, exp_point_count, exp_field_count', [
|
||||||
|
# TODO: test different LAS version
|
||||||
|
# TODO: test LAS without field
|
||||||
|
('test.las', 58629, 3, ),
|
||||||
|
])
|
||||||
|
def test_load_las(datadir, fname, exp_point_count, exp_field_count):
|
||||||
|
fname = datadir.join(fname)
|
||||||
|
|
||||||
|
# Raise "No such file"
|
||||||
|
with pytest.raises(IOError) as e_info:
|
||||||
|
io.load_las('not_as_file.las')
|
||||||
|
|
||||||
|
# Open file without exception
|
||||||
|
try:
|
||||||
|
result = io.load_las(fname)
|
||||||
|
except IOError:
|
||||||
|
pytest.fail('IO error')
|
||||||
|
|
||||||
|
assert result.size == exp_point_count, "Return correct point count"
|
||||||
|
|
||||||
|
assert result['spatial'].shape[-1] == 3, "Return ndarray with spatial field"
|
||||||
|
|
||||||
|
assert (result['spatial'] == result.spatial).all(), "Quick access with records array"
|
||||||
|
|
||||||
|
assert len(result['feature'].dtype) == exp_field_count, "Return ndarray with attribute fields"
|
||||||
|
|
||||||
|
assert result.spatial.dtype == np.float, "Dtype of spatial is np.float"
|
||||||
BIN
test/test_io/test.las
Normal file
BIN
test/test_io/test.las
Normal file
Binary file not shown.
BIN
test/test_io/test.ply
Normal file
BIN
test/test_io/test.ply
Normal file
Binary file not shown.
@ -11,9 +11,12 @@ import numpy as np
|
|||||||
import pytest
|
import pytest
|
||||||
from idefix import utils
|
from idefix import utils
|
||||||
|
|
||||||
def test_first():
|
@pytest.mark.parametrize("first_input,first_expected", [
|
||||||
assert utils.first(1) == -1
|
(1, -1),
|
||||||
assert utils.first(-4) == 4
|
(-4, 4),
|
||||||
|
])
|
||||||
|
def test_first(first_input, first_expected):
|
||||||
|
assert utils.first(first_input) == first_expected
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def fix_data():
|
def fix_data():
|
||||||
@ -23,3 +26,7 @@ def fix_data():
|
|||||||
def test_bbox(fix_data):
|
def test_bbox(fix_data):
|
||||||
res = np.array([fix_data.min(axis=0), fix_data.max(axis=0)])
|
res = np.array([fix_data.min(axis=0), fix_data.max(axis=0)])
|
||||||
assert (utils.bbox(fix_data) == res).all()
|
assert (utils.bbox(fix_data) == res).all()
|
||||||
|
|
||||||
|
def test_read(datadir):
|
||||||
|
with open(datadir.join('first.txt')) as f:
|
||||||
|
assert f.read() == 'hullo\n'
|
||||||
|
|||||||
1
test/test_utils/first.txt
Normal file
1
test/test_utils/first.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
hullo
|
||||||
Loading…
Reference in New Issue
Block a user