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
|
||||
from idefix import utils
|
||||
|
||||
def test_first():
|
||||
assert utils.first(1) == -1
|
||||
assert utils.first(-4) == 4
|
||||
@pytest.mark.parametrize("first_input,first_expected", [
|
||||
(1, -1),
|
||||
(-4, 4),
|
||||
])
|
||||
def test_first(first_input, first_expected):
|
||||
assert utils.first(first_input) == first_expected
|
||||
|
||||
@pytest.fixture
|
||||
def fix_data():
|
||||
@ -23,3 +26,7 @@ def fix_data():
|
||||
def test_bbox(fix_data):
|
||||
res = np.array([fix_data.min(axis=0), fix_data.max(axis=0)])
|
||||
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