-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
split pulse penetration ratio and dens abs mean z and norm features
- Loading branch information
Showing
7 changed files
with
192 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
laserchicken/feature_extractor/density_absolute_mean_norm_z_feature_extractor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
"""Pulse penetration ratio and density absolute mean calculations. | ||
See https://github.com/eEcoLiDAR/eEcoLiDAR/issues/23. | ||
""" | ||
|
||
import numpy as np | ||
|
||
from laserchicken.feature_extractor.abc import AbstractFeatureExtractor | ||
from laserchicken.feature_extractor.density_absolute_mean_z_feature_extractor import \ | ||
DensityAbsoluteMeanZFeatureExtractor | ||
from laserchicken.keys import point, normalized_height | ||
|
||
# classification according to | ||
# http://www.asprs.org/wp-content/uploads/2010/12/LAS_1-4_R6.pdf | ||
GROUND_TAGS = [2] | ||
|
||
|
||
class DensityAbsoluteMeanNormZFeatureExtractor(DensityAbsoluteMeanZFeatureExtractor): | ||
"""Feature extractor for the point density.""" | ||
DATA_KEY = normalized_height | ||
|
||
@classmethod | ||
def provides(cls): | ||
""" | ||
Get a list of names of the feature values. | ||
This will return as many names as the number feature values that will be returned. | ||
For instance, if a feature extractor returns the first 3 eigen values, this method | ||
should return 3 names, for instance 'eigen_value_1', 'eigen_value_2' and 'eigen_value_3'. | ||
:return: List of feature names | ||
""" | ||
return ['density_absolute_mean_norm_z'] |
93 changes: 93 additions & 0 deletions
93
laserchicken/feature_extractor/density_absolute_mean_z_feature_extractor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
"""Pulse penetration ratio and density absolute mean calculations. | ||
See https://github.com/eEcoLiDAR/eEcoLiDAR/issues/23. | ||
""" | ||
|
||
import numpy as np | ||
|
||
from laserchicken.feature_extractor.abc import AbstractFeatureExtractor | ||
from laserchicken.keys import point, normalized_height | ||
|
||
# classification according to | ||
# http://www.asprs.org/wp-content/uploads/2010/12/LAS_1-4_R6.pdf | ||
GROUND_TAGS = [2] | ||
|
||
|
||
def _is_ground(i, point_cloud): | ||
return point_cloud[point]['raw_classification']["data"][i] in GROUND_TAGS | ||
|
||
|
||
class DensityAbsoluteMeanZFeatureExtractor(AbstractFeatureExtractor): | ||
"""Feature extractor for the point density.""" | ||
DATA_KEY = 'z' | ||
|
||
@classmethod | ||
def requires(cls): | ||
""" | ||
Get a list of names of the point attributes that are needed for this feature extraction. | ||
For simple features, this could be just x, y, and z. Other features can build on again | ||
other features to have been computed first. | ||
:return: List of feature names | ||
""" | ||
return [] | ||
|
||
@classmethod | ||
def provides(cls): | ||
""" | ||
Get a list of names of the feature values. | ||
This will return as many names as the number feature values that will be returned. | ||
For instance, if a feature extractor returns the first 3 eigen values, this method | ||
should return 3 names, for instance 'eigen_value_1', 'eigen_value_2' and 'eigen_value_3'. | ||
:return: List of feature names | ||
""" | ||
return ['density_absolute_mean_z'] | ||
|
||
def extract(self, point_cloud, neighborhood, target_point_cloud, target_index, volume_description): | ||
""" | ||
Extract the feature value(s) of the point cloud at location of the target. | ||
:param point_cloud: environment (search space) point cloud | ||
:param neighborhood: array of indices of points within the point_cloud argument | ||
:param target_point_cloud: point cloud that contains target point | ||
:param target_index: index of the target point in the target point cloud | ||
:param volume_description: volume object that describes the shape and size of the search volume | ||
:return: feature value | ||
""" | ||
if 'raw_classification' not in point_cloud[point]: | ||
raise ValueError( | ||
'Missing raw_classification attribute which is necessary for calculating density_absolute_mean.') | ||
|
||
non_ground_indices = [i for i in neighborhood if not _is_ground(i, point_cloud)] | ||
density_absolute_mean_z = self._get_density_absolute_mean(non_ground_indices, point_cloud) | ||
|
||
return density_absolute_mean_z | ||
|
||
@staticmethod | ||
def _get_ground_indices(point_cloud, ground_tags): | ||
index_grd = [] | ||
for ipt, c in enumerate(point_cloud): | ||
if c in ground_tags: | ||
index_grd.append(ipt) | ||
return index_grd | ||
|
||
def _get_density_absolute_mean(self, non_ground_indices, source_point_cloud): | ||
n_non_ground = len(non_ground_indices) | ||
z_non_ground = source_point_cloud[point][self.DATA_KEY]["data"][non_ground_indices] | ||
if n_non_ground == 0: | ||
density_absolute_mean = 0. | ||
else: | ||
density_absolute_mean = float( | ||
len(z_non_ground[z_non_ground > np.mean(z_non_ground)])) / n_non_ground * 100. | ||
return density_absolute_mean | ||
|
||
def get_params(self): | ||
""" | ||
Return a tuple of parameters involved in the current feature extractor object. | ||
Needed for provenance. | ||
""" | ||
return () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
laserchicken/feature_extractor/test_density_absolute_mean_norm_z_extractor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import unittest | ||
|
||
import numpy as np | ||
|
||
from laserchicken.feature_extractor.density_absolute_mean_norm_z_feature_extractor import \ | ||
DensityAbsoluteMeanNormZFeatureExtractor | ||
from laserchicken.feature_extractor.density_absolute_mean_z_feature_extractor import \ | ||
DensityAbsoluteMeanZFeatureExtractor | ||
from laserchicken.feature_extractor.pulse_penetration_feature_extractor import PulsePenetrationFeatureExtractor | ||
from laserchicken.keys import point | ||
from laserchicken.test_tools import create_point_cloud | ||
|
||
|
||
class TestDensityAbsoluteMeanNormZFeatureExtractorArtificialData(unittest.TestCase): | ||
def test_simle_case_correct(self): | ||
"""Check that one out of 4 points above mean of only vegetation points yields a value of 25""" | ||
ground = 2 # Ground tag | ||
veg = 4 # Medium vegetation tag | ||
x = y = z = np.array([10, 10, 10, 1, 1, 1, 2]) | ||
point_cloud = create_point_cloud(x, y, np.zeros_like(z), normalized_z=z) | ||
point_cloud[point]['raw_classification'] = {'data': np.array([ground, ground, ground, veg, veg, veg, veg]), | ||
'type': 'double'} | ||
neighborhood = list(range(len(x))) | ||
|
||
extractor = DensityAbsoluteMeanNormZFeatureExtractor() | ||
density_absolute_mean = extractor.extract(point_cloud, neighborhood, None, None, None) | ||
|
||
self.assertAlmostEqual(density_absolute_mean, 25) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
29 changes: 29 additions & 0 deletions
29
laserchicken/feature_extractor/test_density_absolute_mean_z_extractor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import unittest | ||
|
||
import numpy as np | ||
|
||
from laserchicken.feature_extractor.density_absolute_mean_z_feature_extractor import \ | ||
DensityAbsoluteMeanZFeatureExtractor | ||
from laserchicken.keys import point | ||
from laserchicken.test_tools import create_point_cloud | ||
|
||
|
||
class TestDensityAbsoluteMeanZFeatureExtractorArtificialData(unittest.TestCase): | ||
def test_simle_case_correct(self): | ||
"""Check that one out of 4 points above mean of only vegetation points yields a value of 25""" | ||
ground = 2 # Ground tag | ||
veg = 4 # Medium vegetation tag | ||
x = y = z = np.array([10, 10, 10, 1, 1, 1, 2]) | ||
point_cloud = create_point_cloud(x, y, z) | ||
point_cloud[point]['raw_classification'] = {'data': np.array([ground, ground, ground, veg, veg, veg, veg]), | ||
'type': 'double'} | ||
neighborhood = list(range(len(x))) | ||
|
||
extractor = DensityAbsoluteMeanZFeatureExtractor() | ||
density_absolute_mean = extractor.extract(point_cloud, neighborhood, None, None, None) | ||
|
||
self.assertAlmostEqual(density_absolute_mean, 25) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters