Skip to content

Commit

Permalink
Merge pull request #162 from eEcoLiDAR/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
fnattino authored May 13, 2020
2 parents 6619783 + 3cf879c commit ffbe6d8
Show file tree
Hide file tree
Showing 97 changed files with 3,002 additions and 2,171 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ before_install:
- export PATH="$HOME/miniconda/bin:$PATH"
- conda config --set always_yes yes
- conda update -q conda
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION pip openblas numpy scipy
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION pip
- source activate test-environment
- "pip install -q --upgrade 'pip'"
- "pip install -q 'coverage'"
Expand Down
12 changes: 12 additions & 0 deletions .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@
"affiliation": "Netherlands eScience Center",
"name": "van den Oord, Gijs"
},
{
"affiliation": "Netherlands eScience Center",
"name": "Grootes, Meiert W."
},
{
"affiliation": "Netherlands eScience Center",
"name": "Nattino, Francesco"
},
{
"affiliation": "Netherlands eScience Center",
"name": "Ku, Ou"
},
{
"affiliation": "Institute for Biodiversity and Ecosystem Dynamics, University of Amsterdam",
"name": "Koma, Zsófia"
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

## 0.4.0 - 2020-05-13
## Added:
- build_volume module
- the most relevant functions can be now imported directly from laserchicken
- reading/writing of binary PLY and LAZ files, with optional writing of selected attributes
- utility function to merge point-cloud data
- extra log tasks implemented: point-cloud log entries are introduced upon point-cloud loading, filtering, normalizing, merging and assigning to targets.
- select_polygon now supports multi-polygons and optionally return a mask for the selected points

## Changed:
- compute neighborhoods returns generator with neighborhoods instead of nested neighborhoods like it did before (breaking change!)
- Some of the existing modules have been renamed/restructured (breaking changes!):
- `normalization` --> `normalize`
- `feature_extraction` created (functions moved from `feature_extractor/__init__.py`)
- `select` and `spatial_selection` merged into `filter`, with the function `select_polygon` allowing to deal with all the spatial selection functionalities
- format-specific `read_*` and `write_*` modules replaced by `load` and `export`
- Dependency on `laspy` replaced by `pylas` + `lazperf` (easier reading/writing of LAS/LAZ files)

## 0.3.2 - 2019-12-12
## Added
- Features added:
Expand Down
16 changes: 14 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,24 @@ authors:
family-names: Oord
given-names: Gijs
name-particle: "van den"
-
affiliation: "Netherlands eScience Center"
family-names: Grootes
given-names: "Meiert W."
-
affiliation: "Netherlands eScience Center"
family-names: Nattino
given-names: Francesco
-
affiliation: "Netherlands eScience Center"
family-names: Ku
given-names: Ou
-
affiliation: "Institute for Biodiversity and Ecosystem Dynamics, University of Amsterdam"
family-names: Koma
given-names: Zsófia
cff-version: "1.0.3"
date-released: 2019-10-15
date-released: 2020-05-13
doi: "10.5281/zenodo.1219422"
keywords:
- "airborne laser scanning"
Expand All @@ -50,5 +62,5 @@ keywords:
license: "Apache-2.0"
message: "If you use this software, please cite it using these metadata."
title: "Laserchicken: toolkit for ALS point clouds"
version: "0.3.2"
version: "0.4.0"
...
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Toolkit for handling point clouds created using airborne laser scanning (ALS). F

# Installation
Prerequisites:
- Python 3.5 or higher
- Python 3.5 or higher (3.6 is recommended)
- pip
```
pip install laserchicken
Expand Down
38 changes: 18 additions & 20 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ the PDAL library (https://pdal.io/), this provides access to a comprehensive ran

Example from the tutorial notebook::

from laserchicken.read_las import read
point_cloud = read('testdata/AHN3.las')
from laserchicken import load
point_cloud = load('testdata/AHN3.las')

Normalize
---------

A number of features (Table~\ref{tab_features}) require the normalized height above ground as input. Laserchicken provides the option of internally constructing a digital terrain model (DTM) and deriving this quantity. To this end, the EPC is divided into small cells 1m or 2.5m squared). The lowest point in each cell is taken as the height of the DTM. Each point in the cell is then assigned a normalized height with respect to the derived DTM height. This results in strictly positive heights and smooths variations in elevation on scales larger than the cell size. The normalized EPC can be used directly in further analysis, or serialized to disk.
A number of features require the normalized height above ground as input. Laserchicken provides the option of internally constructing a digital terrain model (DTM) and deriving this quantity. To this end, the EPC is divided into small cells 1m or 2.5m squared). The lowest point in each cell is taken as the height of the DTM. Each point in the cell is then assigned a normalized height with respect to the derived DTM height. This results in strictly positive heights and smooths variations in elevation on scales larger than the cell size. The normalized EPC can be used directly in further analysis, or serialized to disk.

Example from the tutorial notebook::

from laserchicken.normalization import normalize
from laserchicken.normalize import normalize
normalize(point_cloud)

Filter
Expand All @@ -84,18 +84,17 @@ Laserchicken provides the option of filtering the EPC prior to extracting featur

Example of spatial filtering from the tutorial notebook::

from laserchicken.spatial_selections import points_in_polygon_wkt
from laserchicken.filter import select_polygon
polygon = "POLYGON(( 131963.984125 549718.375000," + \
" 132000.000125 549718.375000," + \
" 132000.000125 549797.063000," + \
" 131963.984125 549797.063000," + \
" 131963.984125 549718.375000))"
points_in_area = points_in_polygon_wkt(point_cloud, polygon)
point_cloud = points_in_area
point_cloud = select_polygon(point_cloud, polygon)

Example of applying a filter on the theshold of an attribute::

from laserchicken.select import select_above, select_below
from laserchicken.filter import select_above, select_below
points_below_1_meter = select_below(point_cloud, 'normalized_height', 1)
points_above_1_meter = select_above(point_cloud, 'normalized_height', 1)

Expand All @@ -110,13 +109,13 @@ and TPC in kdTrees in an initial step prior to the computation of neighbors, sub

Example from the tutorial notebook::

from laserchicken.compute_neighbors import compute_neighborhoods
from laserchicken.volume_specification import Sphere
from laserchicken import compute_neighborhoods
from laserchicken import build_volume
targets = point_cloud
volume = Sphere(5)
neighbors = compute_neighborhoods(point_cloud, targets, volume)
volume = build_volume('sphere', radius=5)
neighborhoods = compute_neighborhoods(point_cloud, targets, volume)

Note that in the above example, neighbors is a generator and can only be iterated once. If you would want to do multiple calculations without recalculating the neighbors, you can copy the neighbors to a list. This is not done by default because neighbors can quickly grow quite large so that available RAM unnecessarily becomes the bottle neck.
Note that in the above example, ``neighborhoods`` is a generator and can only be iterated once. If you would want to do multiple calculations without recalculating the neighbors, you can copy the neighborhoods to a list. This is not done by default because neighborhoods can quickly grow quite large so that available RAM unnecessarily becomes the bottle neck.

Features
--------
Expand All @@ -128,15 +127,14 @@ template for new features requiring similar operations.

Example from the tutorial notebook::

from laserchicken.feature_extractor import compute_features
for x in neighbors:
compute_features(point_cloud, x, 0, targets, ['std_z','mean_z','slope'], volume)
from laserchicken import compute_features
compute_features(point_cloud, neighborhoods, targets, ['std_z','mean_z','slope'], volume)

Features can be parameterized. If you need different parameters for them then their defaults you need to register them with these prior to using them.

Example of adding a few parameterized band ratio features on different attributes::

from laserchicken.feature_extractor import register_new_feature_extractor
from laserchicken import register_new_feature_extractor
from laserchicken.feature_extractor.band_ratio_feature_extractor import BandRatioFeatureExtractor
register_new_feature_extractor(BandRatioFeatureExtractor(None,1,data_key='normalized_height'))
register_new_feature_extractor(BandRatioFeatureExtractor(1,2,data_key='normalized_height'))
Expand Down Expand Up @@ -210,12 +208,12 @@ Below is an example. The figure visualizes the slope feature for a small neighbo
Export
------

Laserchicken can write to PLY, CSV, or LAS/LAZ format for further analysis with the user's choice of software. The PLY format is preferred, as it is flexibly extendable and is the only format Laserchicken will write provenance data to. It is also a widely supported point cloud format.
Laserchicken can write to PLY or LAS/LAZ format for further analysis with the user's choice of software. The PLY format is preferred, as it is flexibly extendable and is the only format Laserchicken will write provenance data to. It is also a widely supported point cloud format.

Example from the tutorial notebook::

from laserchicken.write_ply import write
write(point_cloud, 'my_output.ply')
from laserchicken import export
export(point_cloud, 'my_output.ply')



6 changes: 6 additions & 0 deletions laserchicken/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
from ._version import __version__

from laserchicken.compute_neighbors import compute_neighborhoods
from laserchicken.feature_extractor.feature_extraction import compute_features, register_new_feature_extractor
from laserchicken.io.load import load
from laserchicken.io.export import export
from laserchicken.build_volume import build_volume
7 changes: 6 additions & 1 deletion laserchicken/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
__version__ = '0.3.2'
import os

with open(os.path.join(os.path.dirname(__file__), '_version.txt'),
'r') as f:
version = f.read()
__version__ = version.strip()
1 change: 1 addition & 0 deletions laserchicken/_version.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.4.0
40 changes: 40 additions & 0 deletions laserchicken/build_volume.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import inspect

import laserchicken
from laserchicken.volume_specification import Volume


def create_volume_map():
""" Generate map of volume types that are available """
volume_map = {}
for name, obj in inspect.getmembers(laserchicken.volume_specification):
if inspect.isclass(obj) and issubclass(obj, Volume) and obj is not Volume:
volume_map[obj.TYPE] = obj
return volume_map


VOLUMES = create_volume_map()


def build_volume(volume_type, *args, **kwargs):
"""
Return volume object from the volume name and the corresponding parameters
Example:
>>>> vol = build_volume('sphere', radius=5)
:param volume_type: name corresponding to the
:param args: optional non-keyword args to build the volume
:param kwargs: optional keyword args to build the volume
:return:
"""
_volume_type = volume_type.lower()
_verify_volume_type(_volume_type)
volume_builder = VOLUMES[_volume_type]
return volume_builder(*args, **kwargs)


def _verify_volume_type(volume_type):
if volume_type not in VOLUMES.keys():
raise ValueError('Unknown volume specified: {}. Available volumes are: {}'
.format(volume_type, ', '.join(VOLUMES.keys())))
Loading

0 comments on commit ffbe6d8

Please sign in to comment.