def _call(self, x, out=None): """Apply resampling operator. The element ``x`` is resampled using the sampling and interpolation operators of the underlying spaces. """ interpolator = per_axis_interpolator(x, self.domain.grid.coord_vectors, self.interp) context = none_context if out is None else writable_array with context(out) as out_arr: return point_collocation(interpolator, self.range.meshgrid, out=out_arr)
def test_collocation_interpolation_identity(): """Check if collocation is left-inverse to interpolation.""" # Interpolation followed by collocation on the same grid should be # the identity coord_vecs = [[0.125, 0.375, 0.625, 0.875], [0.25, 0.75]] f = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], dtype='float64') interpolators = [ nearest_interpolator(f, coord_vecs), linear_interpolator(f, coord_vecs), per_axis_interpolator(f, coord_vecs, interp=['linear', 'nearest']), ] for interpolator in interpolators: mg = sparse_meshgrid(*coord_vecs) ident_f = point_collocation(interpolator, mg) assert all_almost_equal(ident_f, f)
def test_per_axis_interpolation(): """Test different interpolation schemes per axis.""" coord_vecs = [[0.125, 0.375, 0.625, 0.875], [0.25, 0.75]] interp = ['linear', 'nearest'] f = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], dtype='float64') interpolator = per_axis_interpolator(f, coord_vecs, interp) # Evaluate at single point val = interpolator([0.3, 0.5]) l1 = (0.3 - 0.125) / (0.375 - 0.125) # 0.5 equally far from both neighbors -> NN chooses 0.75 true_val = (1 - l1) * f[0, 1] + l1 * f[1, 1] assert val == pytest.approx(true_val) # Input array, with and without output array pts = np.array([[0.3, 0.6], [0.1, 0.25], [1.0, 1.0]]) l1 = (0.3 - 0.125) / (0.375 - 0.125) true_val_1 = (1 - l1) * f[0, 1] + l1 * f[1, 1] l1 = (0.125 - 0.1) / (0.375 - 0.125) true_val_2 = (1 - l1) * f[0, 0] # only lower left contributes l1 = (1.0 - 0.875) / (0.875 - 0.625) true_val_3 = (1 - l1) * f[3, 1] # lower left only true_arr = [true_val_1, true_val_2, true_val_3] assert all_equal(interpolator(pts.T), true_arr) out = np.empty(3, dtype='float64') interpolator(pts.T, out=out) assert all_equal(out, true_arr) # Input meshgrid, with and without output array mg = sparse_meshgrid([0.3, 1.0], [0.4, 0.85]) # Indices: (1, 3) x (0, 1) lx1 = (0.3 - 0.125) / (0.375 - 0.125) lx2 = (1.0 - 0.875) / (0.875 - 0.625) true_val_11 = (1 - lx1) * f[0, 0] + lx1 * f[1, 0] true_val_12 = ((1 - lx1) * f[0, 1] + lx1 * f[1, 1]) true_val_21 = (1 - lx2) * f[3, 0] true_val_22 = (1 - lx2) * f[3, 1] true_mg = [[true_val_11, true_val_12], [true_val_21, true_val_22]] assert all_equal(interpolator(mg), true_mg) out = np.empty((2, 2), dtype='float64') interpolator(mg, out=out) assert all_equal(out, true_mg)
def linear_deform(template, displacement, interp='linear', out=None): """Linearized deformation of a template with a displacement field. The function maps a given template ``I`` and a given displacement field ``v`` to the new function ``x --> I(x + v(x))``. Parameters ---------- template : `DiscreteLpElement` Template to be deformed by a displacement field. displacement : element of power space of ``template.space`` Vector field (displacement field) used to deform the template. interp : str or sequence of str Interpolation type that should be used to sample the template on the deformed grid. A single value applies to all axes, and a sequence gives the interpolation scheme per axis. Supported values: ``'nearest'``, ``'linear'`` out : `numpy.ndarray`, optional Array to which the function values of the deformed template are written. It must have the same shape as ``template`` and a data type compatible with ``template.dtype``. Returns ------- deformed_template : `numpy.ndarray` Function values of the deformed template. If ``out`` was given, the returned object is a reference to it. Examples -------- Create a simple 1D template to initialize the operator and apply it to a displacement field. Where the displacement is zero, the output value is the same as the input value. In the 4-th point, the value is taken from 0.2 (one cell) to the left, i.e. 1.0. >>> space = odl.uniform_discr(0, 1, 5) >>> disp_field_space = space.tangent_bundle >>> template = space.element([0, 0, 1, 0, 0]) >>> displacement_field = disp_field_space.element([[0, 0, 0, -0.2, 0]]) >>> linear_deform(template, displacement_field, interp='nearest') array([ 0., 0., 1., 1., 0.]) The result depends on the chosen interpolation. With 'linear' interpolation and an offset of half the distance between two points, 0.1, one gets the mean of the values. >>> displacement_field = disp_field_space.element([[0, 0, 0, -0.1, 0]]) >>> linear_deform(template, displacement_field, interp='linear') array([ 0. , 0. , 1. , 0.5, 0. ]) """ points = template.space.points() for i, vi in enumerate(displacement): points[:, i] += vi.asarray().ravel() templ_interpolator = per_axis_interpolator( template, coord_vecs=template.space.grid.coord_vectors, interp=interp ) values = templ_interpolator(points.T, out=out) return values.reshape(template.space.shape)