Skip to content

Commit

Permalink
Added entropy feature extractor
Browse files Browse the repository at this point in the history
  • Loading branch information
goord committed Jan 25, 2018
1 parent 7ea5be4 commit e069c02
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 3 deletions.
8 changes: 5 additions & 3 deletions laserchicken/feature_extractor/__init__.py
@@ -1,10 +1,10 @@
"""Feature extractor module."""
import importlib
import itertools
import re
import numpy as np
from laserchicken import keys,utils
#from .gijs_elena_feature import MyFeatureExtractor

from .entropy_feature_extractor import EntropyFeatureExtractor

def _feature_map(module_name = __name__):
"""Construct a mapping from feature names to feature extractor classes."""
Expand All @@ -19,13 +19,15 @@ def _feature_map(module_name = __name__):
FEATURES = _feature_map()


def compute_features(env_point_cloud, neighborhoods, target_point_cloud, feature_names, overwrite = False):
def compute_features(env_point_cloud, neighborhoods, target_point_cloud, feature_names, overwrite = False, **kwargs):
ordered_features = _make_feature_list(feature_names)
targetsize = len(target_point_cloud[keys.point]["x"]["data"])
for feature in ordered_features:
if((not overwrite) and (feature in target_point_cloud[keys.point])):
continue # Skip feature calc if it is already there and we do not overwrite
extractor = FEATURES[feature]()
for k in kwargs:
setattr(extractor,k,kwargs[k])
providedfeatures = extractor.provides()
numfeatures = len(providedfeatures)
featurevalues = [np.empty(targetsize,dtype = np.float64) for i in range(numfeatures)]
Expand Down
41 changes: 41 additions & 0 deletions laserchicken/feature_extractor/entropy_feature_extractor.py
@@ -0,0 +1,41 @@
import numpy as np
from laserchicken import keys
from laserchicken.feature_extractor.abc import AbstractFeatureExtractor

class EntropyFeatureExtractor(AbstractFeatureExtractor):

# TODO: make this settable from command line
layer_thickness = 0.5
zmin = None
zmax = None

@classmethod
def requires(cls):
return []

@classmethod
def provides(cls):
return ['z_entropy']

def get_params(self):
p = [self.layer_thickness]
if(not self.zmin is None):
p.append(self.zmin)
if(not self.zmax is None):
p.append(self.zmax)
return p


def extract(self,sourcepc,neighborhood,targetpc,targetindex):
z = sourcepc[keys.point]["z"]["data"][neighborhood]
_zmin = np.min(z) if self.zmin is None else self.zmin
_zmax = np.max(z) if self.zmax is None else self.zmax
nbins = int(np.ceil((_zmax - _zmin)/self.layer_thickness))
data = np.histogram(z,bins = nbins,range = (_zmin,_zmax),density = True)[0]
entropyfunc = np.vectorize(xlog2x)
norm = np.sum(data)
return -(entropyfunc(data/norm)).sum()


def xlog2x(x):
return 0 if x == 0 else x * np.log2(x)
@@ -0,0 +1,36 @@
import os
import random
import unittest

from laserchicken import compute_neighbors, feature_extractor, keys, read_las, utils

class TestExtractEntropy(unittest.TestCase):

_test_file_name = 'AHN3.las'
_test_data_source = 'testdata'
pointcloud = None

def test_entropy_in_cylinders(self):
"""Test computing of eigenvalues in cylinder."""
num_all_pc_points = len(self.pointcloud[keys.point]["x"]["data"])
rand_indices = [random.randint(0, num_all_pc_points) for p in range(20)]
target_pointcloud = utils.copy_pointcloud(self.pointcloud, rand_indices)
numtargets = len(target_pointcloud[keys.point]["x"]["data"])
radius = 25
result_index_lists = compute_neighbors.compute_cylinder_neighbourhood_indicies(
self.pointcloud, target_pointcloud, radius)
feature_extractor.compute_features(self.pointcloud, result_index_lists, target_pointcloud,
["z_entropy"],layer_thickness = 0.1)
for i in range(numtargets):
H = utils.get_feature(target_pointcloud, i, "z_entropy")
self.assertTrue(H >= 0)
self.assertEqual("laserchicken.feature_extractor.entropy_feature_extractor",
target_pointcloud[keys.provenance][0]["module"])
self.assertEqual([0.1],target_pointcloud[keys.provenance][0]["parameters"])

def setUp(self):
self.pointcloud = read_las.read(os.path.join(self._test_data_source, self._test_file_name))
random.seed(102938482634)

def tearDown(self):
pass

0 comments on commit e069c02

Please sign in to comment.