Add squash function.
This commit is contained in:
parent
4e28e73aa6
commit
39ba87c0e9
@ -39,11 +39,11 @@ Voxels data
|
|||||||
+ Orientation PCA
|
+ Orientation PCA
|
||||||
+ Normals
|
+ Normals
|
||||||
- Feature distribution
|
- Feature distribution
|
||||||
+ **Mean**
|
+ **Mean**: Reduce noise in the cell
|
||||||
+ Variance
|
+ Variance: Characterize the distribution of the data
|
||||||
+ **Mode**
|
+ **Mode**: Return the majority value (e.g. labels)
|
||||||
+ Entropy
|
+ Entropy
|
||||||
+ Min
|
+ *Min*: To create last echoes map
|
||||||
+ Max
|
+ Max
|
||||||
+ Quantil
|
+ Quantil
|
||||||
|
|
||||||
|
@ -262,10 +262,81 @@ def _human_to_bytes(human_size):
|
|||||||
|
|
||||||
def _geo_to_np_coordinate(raster):
|
def _geo_to_np_coordinate(raster):
|
||||||
'''Geographic to numpy coordinate system.
|
'''Geographic to numpy coordinate system.
|
||||||
|
|
||||||
Transfer the raster (2D and 3D) from a geographic coordinate system to the
|
Transfer the raster (2D and 3D) from a geographic coordinate system to the
|
||||||
numpy coordinate system.
|
numpy coordinate system.
|
||||||
'''
|
'''
|
||||||
return np.flip(np.swapaxes(raster, 0, 1), 0)
|
return np.flip(np.swapaxes(raster, 0, 1), 0)
|
||||||
|
|
||||||
|
def _squash_position(voxel_grid, method, axis):
|
||||||
|
squash_mask = np.zeros_like(voxel_grid, dtype=np.int)
|
||||||
|
mask_idx = (~voxel_grid.mask).nonzero()
|
||||||
|
squash_mask[mask_idx] = mask_idx[axis]
|
||||||
|
|
||||||
|
if method == 'top':
|
||||||
|
squash_id = squash_mask.max(axis=axis).astype(np.uint)
|
||||||
|
elif method == 'center':
|
||||||
|
squash_id = np.ma.median(squash_mask, axis=axis).astype(np.uint)
|
||||||
|
elif method == 'bottom':
|
||||||
|
squash_id = squash_mask.min(axis=axis).astype(np.uint)
|
||||||
|
|
||||||
|
xy_where = np.nonzero(~squash_id.mask)
|
||||||
|
voxel_grid_where = list(xy_where)
|
||||||
|
voxel_grid_where.insert(axis%(len(voxel_grid_where)+1), squash_id.compressed())
|
||||||
|
|
||||||
|
raster = np.zeros_like(squash_id)
|
||||||
|
raster[xy_where] = voxel_grid[tuple(voxel_grid_where)]
|
||||||
|
|
||||||
|
return raster
|
||||||
|
|
||||||
|
def squash(voxel_grid, method='top', axis=-1):
|
||||||
|
"""Flatten a voxel grid.
|
||||||
|
|
||||||
|
Squash the voxel grid along `axis` according to `method` into a raster.
|
||||||
|
|
||||||
|
The squash methods proposed are :
|
||||||
|
|
||||||
|
- Position based in the "column" (i.e. along axis).
|
||||||
|
+ 'top': The first non empty cells (from top) is returned.
|
||||||
|
+ 'center': The most centered cell is returned.
|
||||||
|
+ 'bottom': The last
|
||||||
|
- Cell description in the "column".
|
||||||
|
+ 'count': The number of non empty cells.
|
||||||
|
+ 'mean': The mean value of the non empty cells.
|
||||||
|
+ 'median': The median value...
|
||||||
|
+ 'std': ...
|
||||||
|
+ 'min': ...
|
||||||
|
+ 'max': ...
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
voxel_grid : masked array (3D)
|
||||||
|
The voxel grid (binned point cloud) to squash.
|
||||||
|
method : str
|
||||||
|
The squash method. It can be 'top', 'center', 'bottom', 'count', 'min',
|
||||||
|
'mean', 'max', 'std' or 'median'. Default is 'top'.
|
||||||
|
axis : number
|
||||||
|
The axis to squash along. Default is last (i.e. 2 for 3D voxel grid).
|
||||||
|
|
||||||
|
Return
|
||||||
|
------
|
||||||
|
raster_grid : masked array (2D)
|
||||||
|
The squashed raster.
|
||||||
|
"""
|
||||||
|
if method in ('top', 'center', 'bottom'):
|
||||||
|
return _squash_position(voxel_grid, method, axis)
|
||||||
|
elif method == 'count':
|
||||||
|
return ~voxel_grid.mask.sum(axis=axis)
|
||||||
|
elif method == 'mean':
|
||||||
|
return voxel_grid.mean(axis=axis)
|
||||||
|
elif method == 'median':
|
||||||
|
return np.ma.median(voxel_grid, axis=axis)
|
||||||
|
elif method == 'min':
|
||||||
|
return voxel_grid.min(axis=axis)
|
||||||
|
elif method == 'max':
|
||||||
|
return voxel_grid.max(axis=axis)
|
||||||
|
elif method == 'std':
|
||||||
|
return voxel_grid.std(axis=axis)
|
||||||
|
|
||||||
|
raise NotImplementedError('Method \'{}\' does not exist.'.format(method))
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ def data_vxl(datadir, set_id, grid_id, method):
|
|||||||
|
|
||||||
i = fields.index(feature_name)
|
i = fields.index(feature_name)
|
||||||
|
|
||||||
data = np.loadtxt('test/test_vxl/pc0_vxl_s1.txt')
|
data = np.loadtxt(fname)
|
||||||
spatial = data[:,:3].astype(np.intp)
|
spatial = data[:,:3].astype(np.intp)
|
||||||
feature = data[:,i]
|
feature = data[:,i]
|
||||||
|
|
||||||
@ -48,6 +48,14 @@ def data_vxl(datadir, set_id, grid_id, method):
|
|||||||
path = datadir.join('pc{}_vxl_s{}.txt'.format(set_id, grid_id))
|
path = datadir.join('pc{}_vxl_s{}.txt'.format(set_id, grid_id))
|
||||||
return _load_vxl(path, method)
|
return _load_vxl(path, method)
|
||||||
|
|
||||||
|
def data_raster(datadir, set_id, grid_id, axis, method):
|
||||||
|
def _load_raster(fname):
|
||||||
|
data = np.loadtxt(fname)
|
||||||
|
return np.ma.masked_array(data, data==0)
|
||||||
|
|
||||||
|
path = datadir.join('pc{}_vxl_s{}_raster_{}_{}.txt'.format(set_id, grid_id, axis, method))
|
||||||
|
return _load_raster(path)
|
||||||
|
|
||||||
def data_grid(datadir, set_id, step_id):
|
def data_grid(datadir, set_id, step_id):
|
||||||
def _read(fname):
|
def _read(fname):
|
||||||
with open(fname, 'r') as f:
|
with open(fname, 'r') as f:
|
||||||
@ -183,4 +191,26 @@ def test__geo_to_np_coordinate():
|
|||||||
|
|
||||||
assert (raster_truth == vxl._geo_to_np_coordinate(raster)).all(), 'Missmatch between 3D raters'
|
assert (raster_truth == vxl._geo_to_np_coordinate(raster)).all(), 'Missmatch between 3D raters'
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('set_id, grid_id, axis, method', [
|
||||||
|
(1, 1, 2, 'top'),
|
||||||
|
(1, 1, 2, 'center'),
|
||||||
|
(1, 1, 2, 'bottom'),
|
||||||
|
(1, 1, 2, 'mean'),
|
||||||
|
(1, 1, 2, 'max'),
|
||||||
|
(1, 1, 2, 'min'),
|
||||||
|
(1, 1, 2, 'median'),
|
||||||
|
(1, 1, 0, 'top'),
|
||||||
|
(1, 1, 0, 'center'),
|
||||||
|
(1, 1, 0, 'bottom'),
|
||||||
|
(1, 1, 1, 'top'),
|
||||||
|
(1, 1, 1, 'center'),
|
||||||
|
(1, 1, 1, 'bottom'),
|
||||||
|
])
|
||||||
|
def test_squash(datadir, set_id, grid_id, axis, method):
|
||||||
|
vxld = data_vxl(datadir, set_id, grid_id, 'density' )
|
||||||
|
truth = data_raster(datadir, set_id, grid_id, axis, method)
|
||||||
|
res = vxl.squash(vxld, method, axis)
|
||||||
|
|
||||||
|
assert res is not None, 'Tested function did not return anything :('
|
||||||
|
assert res.shape == truth.shape, 'Missmatch between truth and tested shape'
|
||||||
|
assert np.allclose(res, truth), 'Missmatch between truth and tested raster'
|
||||||
|
9
test/test_vxl/pc1_vxl_s1.txt
Normal file
9
test/test_vxl/pc1_vxl_s1.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# x y z density mean mode
|
||||||
|
1 2 0 2 0 0
|
||||||
|
1 3 0 8 0 0
|
||||||
|
3 0 1 7 0 0
|
||||||
|
3 4 1 42 0 0
|
||||||
|
0 0 2 1 0 0
|
||||||
|
1 2 2 4 0 0
|
||||||
|
1 2 3 5 0 0
|
||||||
|
2 2 3 6 0 0
|
5
test/test_vxl/pc1_vxl_s1_raster_0_bottom.txt
Normal file
5
test/test_vxl/pc1_vxl_s1_raster_0_bottom.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
0 7 1 0
|
||||||
|
0 0 0 0
|
||||||
|
2 0 4 5
|
||||||
|
8 0 0 0
|
||||||
|
0 42 0 0
|
5
test/test_vxl/pc1_vxl_s1_raster_0_center.txt
Normal file
5
test/test_vxl/pc1_vxl_s1_raster_0_center.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
0 7 1 0
|
||||||
|
0 0 0 0
|
||||||
|
2 0 4 5
|
||||||
|
8 0 0 0
|
||||||
|
0 42 0 0
|
5
test/test_vxl/pc1_vxl_s1_raster_0_top.txt
Normal file
5
test/test_vxl/pc1_vxl_s1_raster_0_top.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
0 7 1 0
|
||||||
|
0 0 0 0
|
||||||
|
2 0 4 6
|
||||||
|
8 0 0 0
|
||||||
|
0 42 0 0
|
4
test/test_vxl/pc1_vxl_s1_raster_1_bottom.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_1_bottom.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
0 0 1 0
|
||||||
|
0 0 4 5
|
||||||
|
0 0 0 6
|
||||||
|
0 7 0 0
|
4
test/test_vxl/pc1_vxl_s1_raster_1_center.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_1_center.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
0 0 1 0
|
||||||
|
0 0 4 5
|
||||||
|
0 0 0 6
|
||||||
|
0 7 0 0
|
4
test/test_vxl/pc1_vxl_s1_raster_1_top.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_1_top.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
0 0 1 0
|
||||||
|
0 0 4 5
|
||||||
|
0 0 0 6
|
||||||
|
0 42 0 0
|
4
test/test_vxl/pc1_vxl_s1_raster_2_bottom.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_2_bottom.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1 0 0 0 0
|
||||||
|
0 0 2 8 0
|
||||||
|
0 0 6 0 0
|
||||||
|
7 0 0 0 42
|
4
test/test_vxl/pc1_vxl_s1_raster_2_center.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_2_center.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1 0 0 0 0
|
||||||
|
0 0 4 8 0
|
||||||
|
0 0 6 0 0
|
||||||
|
7 0 0 0 42
|
4
test/test_vxl/pc1_vxl_s1_raster_2_max.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_2_max.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1 0 0 0 0
|
||||||
|
0 0 5 8 0
|
||||||
|
0 0 6 0 0
|
||||||
|
7 0 0 0 42
|
4
test/test_vxl/pc1_vxl_s1_raster_2_mean.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_2_mean.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1 0 0 0 0
|
||||||
|
0 0 3.66667 8 0
|
||||||
|
0 0 6 0 0
|
||||||
|
7 0 0 0 42
|
4
test/test_vxl/pc1_vxl_s1_raster_2_median.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_2_median.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1 0 0 0 0
|
||||||
|
0 0 4 8 0
|
||||||
|
0 0 6 0 0
|
||||||
|
7 0 0 0 42
|
4
test/test_vxl/pc1_vxl_s1_raster_2_min.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_2_min.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1 0 0 0 0
|
||||||
|
0 0 2 8 0
|
||||||
|
0 0 6 0 0
|
||||||
|
7 0 0 0 42
|
4
test/test_vxl/pc1_vxl_s1_raster_2_top.txt
Normal file
4
test/test_vxl/pc1_vxl_s1_raster_2_top.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
1 0 0 0 0
|
||||||
|
0 0 5 8 0
|
||||||
|
0 0 6 0 0
|
||||||
|
7 0 0 0 42
|
Loading…
Reference in New Issue
Block a user