Change default behavior of get_grid
This commit is contained in:
parent
ae0308374c
commit
a21598eb74
@ -55,5 +55,42 @@ def bbox(data):
|
|||||||
|
|
||||||
[[xmin, ymin, zmin],
|
[[xmin, ymin, zmin],
|
||||||
[xmax, ymax, zmax]]
|
[xmax, ymax, zmax]]
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
fit_bbox : Return a bounding box fit on fixed coordinates.
|
||||||
"""
|
"""
|
||||||
return np.array((np.min(data, axis=0), np.max(data, axis=0)))
|
return np.array((np.min(data, axis=0), np.max(data, axis=0)))
|
||||||
|
|
||||||
|
def fit_bbox(data, decimals=0):
|
||||||
|
"""Return a bounding box fit on fixed coordinates.
|
||||||
|
|
||||||
|
- Round $x$ and $y$ coordinates to match most orthoimagery tiles.
|
||||||
|
- Ceil and floor $z$ coordinates to include all the point on the vertical axis.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
data : ndarray (N, 3)
|
||||||
|
Bbox or point cloud data of shape (N, 3), i.e. (x,y,z).
|
||||||
|
decimals : int
|
||||||
|
The precision for the rounding, ceiling and flooring operations.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bbox : ndarray
|
||||||
|
Lower and upper points describing the bounding box such as::
|
||||||
|
|
||||||
|
[[xmin, ymin, zmin],
|
||||||
|
[xmax, ymax, zmax]]
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
bbox : Returns a raw bounding box on the data.
|
||||||
|
"""
|
||||||
|
bbox = bbox(data)
|
||||||
|
|
||||||
|
nbbox = np.round(bbox, decimals)
|
||||||
|
nbbox[0,2] = np.floor(bbox * 10 ** decimals)[0,2] / 10 ** decimals
|
||||||
|
nbbox[1,2] = np.ceil(bbox * 10 ** decimals)[1,2] / 10 ** decimals
|
||||||
|
|
||||||
|
return nbbox
|
||||||
|
|||||||
@ -11,7 +11,7 @@ General functions to transform point clouds to voxels compatible with numpy.
|
|||||||
import logging
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import humanize
|
import humanize
|
||||||
from .utils import bbox
|
from .utils import bbox, fit_bbox
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ def _ui_step(step, spatial):
|
|||||||
def get_grid(spatial, step):
|
def get_grid(spatial, step):
|
||||||
'''Return grid bins.
|
'''Return grid bins.
|
||||||
|
|
||||||
Compute the grid bins of a point cloud or the corresponding bounding box
|
Compute the grid bins of a point cloud or the corresponding bounding
|
||||||
according to given step (or steps for anisotropic grid).
|
box according to given step (or steps for anisotropic grid).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -54,8 +54,26 @@ def get_grid(spatial, step):
|
|||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
grid : array of array (n,)
|
grid : array of array (n,)
|
||||||
Grid of spatial given step. Return three arrays (not necessarily of the
|
Grid of spatial given step. Return three arrays (not necessarily
|
||||||
same size) defining the bins of axis `x`, `y` and `z`.
|
of the same size) defining the bins of axis `x`, `y` and `z`.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The grid is built considering the half-open interval
|
||||||
|
$[min_of_the_axis, max_of_the_axis)$. If the positions of the points
|
||||||
|
are directly used as spatial parameter, the points at the upper
|
||||||
|
limits will be excluded from further processing.
|
||||||
|
|
||||||
|
You can define a more precise bounding box to take into account all
|
||||||
|
the points of your dataset (e.g. by adding a small distance on the
|
||||||
|
upper limits).
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
bbox : Returns the raw bounding box of the point cloud (excluding
|
||||||
|
points on upper limit).
|
||||||
|
fit_bbox : Returns a bounding box on rounded coordinates (can
|
||||||
|
include all the points).
|
||||||
'''
|
'''
|
||||||
spatial = np.array(spatial)
|
spatial = np.array(spatial)
|
||||||
bb = bbox(spatial)
|
bb = bbox(spatial)
|
||||||
@ -65,7 +83,7 @@ def get_grid(spatial, step):
|
|||||||
for a_min, a_max, a_s in zip(bb[0], bb[1], step):
|
for a_min, a_max, a_s in zip(bb[0], bb[1], step):
|
||||||
# Beware of float underflow
|
# Beware of float underflow
|
||||||
if a_s:
|
if a_s:
|
||||||
bins = np.trunc((a_max - a_min) / a_s).astype(int) + 1
|
bins = np.trunc((a_max - a_min) / a_s).astype(int)
|
||||||
grid += [np.linspace(a_min, a_min + bins * a_s, bins + 1)]
|
grid += [np.linspace(a_min, a_min + bins * a_s, bins + 1)]
|
||||||
else:
|
else:
|
||||||
grid += [np.array((a_min, a_max + 1))]
|
grid += [np.array((a_min, a_max + 1))]
|
||||||
@ -347,7 +365,7 @@ def squash(voxel_grid, method='top', axis=-1):
|
|||||||
return voxel_grid.max(axis=axis)
|
return voxel_grid.max(axis=axis)
|
||||||
elif method == 'std':
|
elif method == 'std':
|
||||||
return voxel_grid.std(axis=axis)
|
return voxel_grid.std(axis=axis)
|
||||||
|
|
||||||
raise NotImplementedError('Method \'{}\' does not exist.'.format(method))
|
raise NotImplementedError('Method \'{}\' does not exist.'.format(method))
|
||||||
|
|
||||||
def plot(voxel_grid, vmin=None, vmax=None):
|
def plot(voxel_grid, vmin=None, vmax=None):
|
||||||
|
|||||||
@ -86,7 +86,14 @@ def test_get_grid(datadir, set_id, step, grid_id):
|
|||||||
assert res is not None, 'Test data empty, test function is broken!'
|
assert res is not None, 'Test data empty, test function is broken!'
|
||||||
assert len(res) == 3, 'Test data malformed, test function is broken!'
|
assert len(res) == 3, 'Test data malformed, test function is broken!'
|
||||||
|
|
||||||
test = vxl.get_grid(spatial, step)
|
bbox = vxl.bbox(spatial)
|
||||||
|
try:
|
||||||
|
bbox[1,:] += step * 1.01
|
||||||
|
except:
|
||||||
|
# Workaround for the None on last axis
|
||||||
|
bbox[1,:] += step[0]
|
||||||
|
|
||||||
|
test = vxl.get_grid(bbox, step)
|
||||||
|
|
||||||
assert test is not None, 'Function did not return anything :('
|
assert test is not None, 'Function did not return anything :('
|
||||||
assert len(test) == 3, 'Function doesn\'t give right number of axis'
|
assert len(test) == 3, 'Function doesn\'t give right number of axis'
|
||||||
@ -178,7 +185,7 @@ def test__geo_to_np_coordinate():
|
|||||||
raster_truth[0, -1] = 25
|
raster_truth[0, -1] = 25
|
||||||
raster_truth[-1, 2] = 7
|
raster_truth[-1, 2] = 7
|
||||||
|
|
||||||
assert (raster_truth == vxl._geo_to_np_coordinate(raster)).all(), 'Missmatch between 2D raters'
|
assert (raster_truth == vxl._geo_to_np_coordinate(raster)).all(), 'Missmatch between 2D raters'
|
||||||
|
|
||||||
raster = np.zeros((5, 5, 3), dtype=np.uint8)
|
raster = np.zeros((5, 5, 3), dtype=np.uint8)
|
||||||
raster[0, 0, 0] = 42
|
raster[0, 0, 0] = 42
|
||||||
@ -190,7 +197,7 @@ def test__geo_to_np_coordinate():
|
|||||||
raster_truth[0, -1, 1] = 25
|
raster_truth[0, -1, 1] = 25
|
||||||
raster_truth[-1, 2, 2] = 7
|
raster_truth[-1, 2, 2] = 7
|
||||||
|
|
||||||
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', [
|
@pytest.mark.parametrize('set_id, grid_id, axis, method', [
|
||||||
(1, 1, 2, 'top'),
|
(1, 1, 2, 'top'),
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0
|
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0
|
||||||
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0
|
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0
|
||||||
1.0 11.0
|
1.0 12.0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user