def test_interpolate_scalar_3d(): np.random.seed(9216326) sz = 64 target_shape = (sz, sz, sz) image = np.empty(target_shape, dtype=floating) image[...] = np.random.randint(0, 10, np.size(image)).reshape(target_shape) extended_image = np.zeros((sz + 2, sz + 2, sz + 2), dtype=floating) extended_image[1:sz + 1, 1:sz + 1, 1:sz + 1] = image[...] # Select some coordinates inside the image to interpolate at nsamples = 800 locations =\ np.random.ranf(3 * nsamples).reshape((nsamples, 3)) * (sz + 2) - 1.0 extended_locations = locations + 1.0 # shift coordinates one voxel # Call the implementation under test interp, inside = interpolate_scalar_3d(image, locations) # Call the reference implementation expected = map_coordinates(extended_image, extended_locations.transpose(), order=1) npt.assert_array_almost_equal(expected, interp) # Test interpolation stability along the boundary epsilon = 5e-8 for k in range(3): for offset in [0, sz - 1]: delta = ((np.random.ranf(nsamples) * 2) - 1) * epsilon locations[:, k] = delta + offset locations[:, (k + 1) % 3] = np.random.ranf(nsamples) * (sz - 1) locations[:, (k + 2) % 3] = np.random.ranf(nsamples) * (sz - 1) interp, inside = interpolate_scalar_3d(image, locations) locations[:, k] = offset expected = map_coordinates(image, locations.transpose(), order=1) npt.assert_array_almost_equal(expected, interp) if offset == 0: expected_flag = np.array(delta >= 0, dtype=np.int32) else: expected_flag = np.array(delta <= 0, dtype=np.int32) npt.assert_array_almost_equal(expected_flag, inside)
def _extract_vals(data, streamlines, affine, threedvec=False): """ Helper function for use with `values_from_volume`. Parameters ---------- data : 3D or 4D array Scalar (for 3D) and vector (for 4D) values to be extracted. For 4D data, interpolation will be done on the 3 spatial dimensions in each volume. streamlines : ndarray or list If array, of shape (n_streamlines, n_nodes, 3) If list, len(n_streamlines) with (n_nodes, 3) array in each element of the list. affine : array_like (4, 4) The mapping from voxel coordinates to streamline points. The voxel_to_rasmm matrix, typically from a NIFTI file. threedvec : bool Whether the last dimension has length 3. This is a special case in which we can use :func:`dipy.core.interpolate.interpolate_vector_3d` for the interploation of 4D volumes without looping over the elements of the last dimension. Returns --------- array or list (depending on the input) : values interpolate to each coordinate along the length of each streamline """ data = data.astype(np.float) if (isinstance(streamlines, list) or isinstance(streamlines, types.GeneratorType) or isinstance(streamlines, Streamlines)): streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) vals = [] for sl in streamlines: if threedvec: vals.append( list(interpolate_vector_3d(data, sl.astype(np.float))[0])) else: vals.append( list(interpolate_scalar_3d(data, sl.astype(np.float))[0])) elif isinstance(streamlines, np.ndarray): sl_shape = streamlines.shape sl_cat = streamlines.reshape(sl_shape[0] * sl_shape[1], 3).astype(np.float) inv_affine = np.linalg.inv(affine) sl_cat = (np.dot(sl_cat, inv_affine[:3, :3]) + inv_affine[:3, 3]) # So that we can index in one operation: if threedvec: vals = np.array(interpolate_vector_3d(data, sl_cat)[0]) else: vals = np.array(interpolate_scalar_3d(data, sl_cat)[0]) vals = np.reshape(vals, (sl_shape[0], sl_shape[1], -1)) if vals.shape[-1] == 1: vals = np.reshape(vals, vals.shape[:-1]) else: raise RuntimeError("Extracting values from a volume ", "requires streamlines input as an array, ", "a list of arrays, or a streamline generator.") return vals