From a700df9805a5a626d4f33aa48d027d229d61042b Mon Sep 17 00:00:00 2001 From: frheault Date: Mon, 29 Jul 2019 11:17:19 -0400 Subject: [PATCH 01/13] First pass of deleting/fixing affine usage --- dipy/tracking/utils.py | 289 ++++++----------------------------------- 1 file changed, 43 insertions(+), 246 deletions(-) diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index 17c73e3987..6ad6eda4d4 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -71,7 +71,7 @@ import nibabel as nib -def density_map(streamlines, vol_dims, affine=None): +def density_map(streamlines, vol_dims, affine): """Counts the number of unique streamlines that pass through each voxel. Parameters @@ -84,6 +84,7 @@ def density_map(streamlines, vol_dims, affine=None): counts affine : array_like (4, 4) The mapping from voxel coordinates to streamline points. + The voxel_to_rasmm matrix, typically from a NIFTI file. Returns ------- @@ -114,7 +115,7 @@ def density_map(streamlines, vol_dims, affine=None): return counts -def connectivity_matrix(streamlines, label_volume, affine=None, +def connectivity_matrix(streamlines, label_volume, affine, symmetric=True, return_mapping=False, mapping_as_streamlines=False): """Counts the streamlines that start and end at each label pair. @@ -128,6 +129,7 @@ def connectivity_matrix(streamlines, label_volume, affine=None, volume map to anatomical structures. affine : array_like (4, 4) The mapping from voxel coordinates to streamline coordinates. + The voxel_to_rasmm matrix, typically from a NIFTI file. symmetric : bool, True by default Symmetric means we don't distinguish between start and end points. If symmetric is True, ``matrix[i, j] == matrix[j, i]``. @@ -319,7 +321,7 @@ def subsegment(streamlines, max_segment_length): yield output_sl -def seeds_from_mask(mask, density=[1, 1, 1], voxel_size=None, affine=None): +def seeds_from_mask(mask, affine, density=[1, 1, 1]): """Creates seeds for fiber tracking from a binary mask. Seeds points are placed evenly distributed in all voxels of ``mask`` which @@ -329,16 +331,16 @@ def seeds_from_mask(mask, density=[1, 1, 1], voxel_size=None, affine=None): ---------- mask : binary 3d array_like A binary array specifying where to place the seeds for fiber tracking. + affine : array, (4, 4) + The mapping between voxel indices and the point space for seeds. + The voxel_to_rasmm matrix, typically from a NIFTI file. + A seed point at the center the voxel ``[i, j, k]`` + will be represented as ``[x, y, z]`` where + ``[x, y, z, 1] == np.dot(affine, [i, j, k , 1])``. density : int or array_like (3,) Specifies the number of seeds to place along each dimension. A ``density`` of `2` is the same as ``[2, 2, 2]`` and will result in a total of 8 seeds per voxel. - voxel_size : - This argument is deprecated. - affine : array, (4, 4) - The mapping between voxel indices and the point space for seeds. A - seed point at the center the voxel ``[i, j, k]`` will be represented as - ``[x, y, z]`` where ``[x, y, z, 1] == np.dot(affine, [i, j, k , 1])``. See Also -------- @@ -363,7 +365,7 @@ def seeds_from_mask(mask, density=[1, 1, 1], voxel_size=None, affine=None): [ 0.5 , 0.25 , 0.83333333], [ 0.5 , 0.75 , 0.83333333]]) >>> mask[0,1,2] = 1 - >>> seeds_from_mask(mask, [1,1,2], [1.1,1.1,2.5]) + >>> seeds_from_mask(mask, np.eye(4), [1,1,2]]) array([[ 0.55 , 0.55 , 0.625], [ 0.55 , 0.55 , 1.875], [ 0.55 , 1.65 , 5.625], @@ -394,20 +396,16 @@ def seeds_from_mask(mask, density=[1, 1, 1], voxel_size=None, affine=None): seeds = seeds.reshape((-1, 3)) # Apply the spatial transform - if affine is not None: + if seeds is not None: # Use affine to move seeds into real world coordinates seeds = np.dot(seeds, affine[:3, :3].T) seeds += affine[:3, 3] - elif voxel_size is not None: - # Use voxel_size to move seeds into trackvis space - seeds += .5 - seeds *= voxel_size return seeds -def random_seeds_from_mask(mask, seeds_count=1, seed_count_per_voxel=True, - affine=None, random_seed=None): +def random_seeds_from_mask(mask, affine, seeds_count=1, + seed_count_per_voxel=True, random_seed=None): """Creates randomly placed seeds for fiber tracking from a binary mask. Seeds points are placed randomly distributed in voxels of ``mask`` @@ -421,6 +419,12 @@ def random_seeds_from_mask(mask, seeds_count=1, seed_count_per_voxel=True, ---------- mask : binary 3d array_like A binary array specifying where to place the seeds for fiber tracking. + affine : array, (4, 4) + The mapping between voxel indices and the point space for seeds. + The voxel_to_rasmm matrix, typically from a NIFTI file. + A seed point at the center the voxel ``[i, j, k]`` + will be represented as ``[x, y, z]`` where + ``[x, y, z, 1] == np.dot(affine, [i, j, k , 1])``. seeds_count : int The number of seeds to generate. If ``seed_count_per_voxel`` is True, specifies the number of seeds to place in each voxel. Otherwise, @@ -428,10 +432,6 @@ def random_seeds_from_mask(mask, seeds_count=1, seed_count_per_voxel=True, seed_count_per_voxel: bool If True, seeds_count is per voxel, else seeds_count is the total number of seeds. - affine : array, (4, 4) - The mapping between voxel indices and the point space for seeds. A - seed point at the center the voxel ``[i, j, k]`` will be represented as - ``[x, y, z]`` where ``[x, y, z, 1] == np.dot(affine, [i, j, k , 1])``. random_seed : int The seed for the random seed generator (numpy.random.seed). @@ -460,8 +460,8 @@ def random_seeds_from_mask(mask, seeds_count=1, seed_count_per_voxel=True, [ 0.39286015, -0.16802019, 0.32122912], [-0.42369171, 0.27991879, -0.06159077]]) >>> mask[0,1,2] = 1 - >>> random_seeds_from_mask(mask, seeds_count=2, seed_count_per_voxel=True, - ... random_seed=1) + >>> random_seeds_from_mask(mask, np.eye(4), + ... seeds_count=2, seed_count_per_voxel=True, random_seed=1) array([[-0.0640051 , -0.47407377, 0.04966248], [-0.27800683, 1.37073231, 1.70671916], [ 0.0507979 , 0.20814782, -0.20909526], @@ -507,7 +507,7 @@ def random_seeds_from_mask(mask, seeds_count=1, seed_count_per_voxel=True, seeds = seeds[:seeds_count] # Apply the spatial transform - if affine is not None: + if seeds is not None: # Use affine to move seeds into real world coordinates seeds = np.dot(seeds, affine[:3, :3].T) seeds += affine[:3, 3] @@ -543,7 +543,8 @@ def target(streamlines, target_mask, affine, include=True): A mask used as a target. Non-zero values are considered to be within the target region. affine : array (4, 4) - The affine transform from voxel indices to streamline points. + The mapping between voxel indices and the point space for seeds. + The voxel_to_rasmm matrix, typically from a NIFTI file. include : bool, default True If True, streamlines passing through `target_mask` are kept. If False, the streamlines not passing through `target_mask` are kept. @@ -580,7 +581,7 @@ def target(streamlines, target_mask, affine, include=True): @_with_initialize -def target_line_based(streamlines, target_mask, affine=None, include=True): +def target_line_based(streamlines, target_mask, affine, include=True): """Filters streamlines based on whether or not they pass through a ROI, using a line-based algorithm. Mostly used as a replacement of `target` for compressed streamlines. @@ -597,7 +598,8 @@ def target_line_based(streamlines, target_mask, affine=None, include=True): A mask used as a target. Non-zero values are considered to be within the target region. affine : array (4, 4) - The affine transform from voxel indices to streamline points. + The mapping between voxel indices and the point space for seeds. + The voxel_to_rasmm matrix, typically from a NIFTI file. include : bool, default True If True, streamlines passing through `target_mask` are kept. If False, the streamlines not passing through `target_mask` are kept. @@ -682,7 +684,7 @@ def streamline_near_roi(streamline, roi_coords, tol, mode='any'): return np.all(np.min(dist, -1) <= tol) -def near_roi(streamlines, region_of_interest, affine=None, tol=None, +def near_roi(streamlines, region_of_interest, affine, tol=None, mode="any"): """Provide filtering criteria for a set of streamlines based on whether they fall within a tolerance distance from an ROI @@ -695,8 +697,9 @@ def near_roi(streamlines, region_of_interest, affine=None, tol=None, region_of_interest : ndarray A mask used as a target. Non-zero values are considered to be within the target region. - affine : ndarray - Affine transformation from voxels to streamlines. Default: identity. + affine : array (4, 4) + The mapping between voxel indices and the point space for seeds. + The voxel_to_rasmm matrix, typically from a NIFTI file. tol : float Distance (in the units of the streamlines, usually mm). If any coordinate in the streamline is within this distance from the center @@ -723,8 +726,6 @@ def near_roi(streamlines, region_of_interest, affine=None, tol=None, that passes within a tolerance distance from the target ROI, `False` otherwise. """ - if affine is None: - affine = np.eye(4) dtc = dist_to_corner(affine) if tol is None: tol = dtc @@ -754,113 +755,13 @@ def near_roi(streamlines, region_of_interest, affine=None, tol=None, return(np.array(out, dtype=bool)) -def reorder_voxels_affine(input_ornt, output_ornt, shape, voxel_size): - """Calculates a linear transformation equivalent to changing voxel order. - - Calculates a linear transformation A such that [a, b, c, 1] = - A[x, y, z, 1], where [x, y, z] is a point in the coordinate system defined - by input_ornt and [a, b, c] is the same point in the coordinate system - defined by output_ornt. - - Parameters - ---------- - input_ornt : array (n, 2) - A description of the orientation of a point in n-space. See - ``nibabel.orientation`` or ``dipy.io.bvectxt`` for more information. - output_ornt : array (n, 2) - A description of the orientation of a point in n-space. - shape : tuple of int - Shape of the image in the input orientation. - ``map = ornt_mapping(input_ornt, output_ornt)`` - voxel_size : int - Voxel size of the image in the input orientation. - - Returns - ------- - A : array (n+1, n+1) - Affine matrix of the transformation between input_ornt and output_ornt. - - See Also - -------- - nibabel.orientation - dipy.io.bvectxt.orientation_to_string - dipy.io.bvectxt.orientation_from_string - """ - map = ornt_mapping(input_ornt, output_ornt) - if input_ornt.shape != output_ornt.shape: - raise ValueError("input_ornt and output_ornt must have the same shape") - affine = eye(len(input_ornt)+1) - affine[:3] = affine[map[:, 0]] - corner = asarray(voxel_size) * shape - affine[:3, 3] = (map[:, 1] < 0) * corner[map[:, 0]] - # multiply the rows of affine to get right sign - affine[:3, :3] *= map[:, 1:] - return affine - - -def affine_from_fsl_mat_file(mat_affine, input_voxsz, output_voxsz): - """ - Converts an affine matrix from flirt (FSLdot) and a given voxel size for - input and output images and returns an adjusted affine matrix for trackvis. - - Parameters - ---------- - mat_affine : array of shape (4, 4) - An FSL flirt affine. - input_voxsz : array of shape (3,) - The input image voxel dimensions. - output_voxsz : array of shape (3,) - - Returns - ------- - affine : array of shape (4, 4) - A trackvis-compatible affine. +# reorder_voxels_affine - """ - # TODO the affine returned by this function uses a different reference than - # the nifti-style index coordinates dipy has adopted as a convention. We - # should either fix this function in a backward compatible way or replace - # and deprecate it. - input_voxsz = asarray(input_voxsz) - output_voxsz = asarray(output_voxsz) - shift = eye(4) - shift[:3, 3] = -input_voxsz / 2 - affine = dot(mat_affine, shift) - affine[:3, 3] += output_voxsz / 2 +# affine_from_fsl_mat_file - return affine - - -def affine_for_trackvis(voxel_size, voxel_order=None, dim=None, - ref_img_voxel_order=None): - """Returns an affine which maps points for voxel indices to trackvis - space. - - Parameters - ---------- - voxel_size : array (3,) - The sizes of the voxels in the reference image. - Returns - ------- - affine : array (4, 4) - Mapping from the voxel indices of the reference image to trackvis - space. - """ - if ((voxel_order is not None or dim is not None or - ref_img_voxel_order is not None)): - raise NotImplemented - - # Create affine - voxel_size = np.asarray(voxel_size) - affine = np.eye(4) - affine[[0, 1, 2], [0, 1, 2]] = voxel_size - affine[:3, 3] = voxel_size / 2. - return affine - - -def length(streamlines, affine=None): +def length(streamlines): """ Calculate the lengths of many streamlines in a bundle. @@ -868,17 +769,13 @@ def length(streamlines, affine=None): ---------- streamlines : list Each item in the list is an array with 3D coordinates of a streamline. - affine : 4 x 4 array - An affine transformation to move the fibers by, before computing their - lengths. Returns ------- Iterator object which then computes the length of each streamline in the bundle, upon iteration. """ - if affine is not None: - streamlines = move_streamlines(streamlines, affine) + return map(metrics.length, streamlines) @@ -914,52 +811,8 @@ def unique_rows(in_array, dtype='f4'): diff_in_array = diff_x[un_order] return in_array[diff_in_array] - -@_with_initialize -def move_streamlines(streamlines, output_space, input_space=None, - seeds=None): - """Applies a linear transformation, given by affine, to streamlines. - - Parameters - ---------- - streamlines : sequence - A set of streamlines to be transformed. - output_space : array (4, 4) - An affine matrix describing the target space to which the streamlines - will be transformed. - input_space : array (4, 4), optional - An affine matrix describing the current space of the streamlines, if no - ``input_space`` is specified, it's assumed the streamlines are in the - reference space. The reference space is the same as the space - associated with the affine matrix ``np.eye(4)``. - seeds : np.array, optional - If set, seeds associated to streamlines will be also moved and returned - - Returns - ------- - streamlines : generator - A sequence of transformed streamlines. - If return_seeds is True, also return seeds - - """ - if input_space is None: - affine = output_space - else: - inv = np.linalg.inv(input_space) - affine = np.dot(output_space, inv) - - lin_T = affine[:3, :3].T.copy() - offset = affine[:3, 3].copy() - yield - # End of initialization - - if seeds is not None: - for sl, seed in zip(streamlines, seeds): - yield np.dot(sl, lin_T) + offset, np.dot(seed, lin_T) + offset - else: - for sl in streamlines: - yield np.dot(sl, lin_T) + offset - +# affine_for_trackvis +# move_streamlines def reduce_rois(rois, include): """Reduce multiple ROIs to one inclusion and one exclusion ROI. @@ -1002,66 +855,9 @@ def reduce_rois(rois, include): return include_roi, exclude_roi -def flexi_tvis_affine(sl_vox_order, grid_affine, dim, voxel_size): - """ Computes the mapping from voxel indices to streamline points, - reconciling streamlines and grids with different voxel orders - - Parameters - ---------- - sl_vox_order : string of length 3 - a string that describes the voxel order of the streamlines (ex: LPS) - grid_affine : array (4, 4), - An affine matrix describing the current space of the grid in relation - to RAS+ scanner space - dim : tuple of length 3 - dimension of the grid - voxel_size : array (3,0) - voxel size of the grid - - Returns - ------- - flexi_tvis_aff : this affine maps between a grid and a trackvis space - """ - - sl_ornt = orientation_from_string(str(sl_vox_order)) - grid_ornt = nib.io_orientation(grid_affine) - reorder_grid = reorder_voxels_affine( - grid_ornt, sl_ornt, np.array(dim)-1, np.array([1, 1, 1])) - - tvis_aff = affine_for_trackvis(voxel_size) - - flexi_tvis_aff = np.dot(tvis_aff, reorder_grid) - - return flexi_tvis_aff - - -def get_flexi_tvis_affine(tvis_hdr, nii_aff): - """ Computes the mapping from voxel indices to streamline points, - reconciling streamlines and grids with different voxel orders - - Parameters - ---------- - tvis_hdr : header from a trackvis file - nii_aff : array (4, 4), - An affine matrix describing the current space of the grid in relation - to RAS+ scanner space - nii_data : nd array - 3D array, each with shape (x, y, z) corresponding to the shape of the - brain volume. - - Returns - ------- - flexi_tvis_aff : array (4,4) - this affine maps between a grid and a trackvis space - """ - - sl_vox_order = tvis_hdr['voxel_order'] - voxel_size = tvis_hdr['voxel_size'] - dim = tvis_hdr['dim'] - - flexi_tvis_aff = flexi_tvis_affine(sl_vox_order, nii_aff, dim, voxel_size) +# flexi_tvis_affine - return flexi_tvis_aff +# get_flexi_tvis_affine def _min_at(a, index, value): @@ -1097,7 +893,8 @@ def path_length(streamlines, aoi, affine, fill_value=-1): aoi : array, 3d A mask (binary array) of voxels from which to start computing distance. affine : array (4, 4) - The mapping from voxel indices to streamline points. + The mapping between voxel indices and the point space for seeds. + The voxel_to_rasmm matrix, typically from a NIFTI file. fill_value : float The value of voxel in the path length map that are not connected to the aoi. From c4e523da85b66640a39a0a2e4bd8abce14371a2b Mon Sep 17 00:00:00 2001 From: frheault Date: Mon, 29 Jul 2019 13:51:35 -0400 Subject: [PATCH 02/13] Fixing all broken function for density, connectivity and seeding --- dipy/tracking/local/tests/test_tracking.py | 6 +-- dipy/tracking/tests/test_utils.py | 51 ++++++++++------------ dipy/tracking/utils.py | 27 ++++++------ dipy/workflows/tracking.py | 10 ++--- doc/examples/cluster_confidence.py | 2 +- doc/examples/fiber_to_bundle_coherence.py | 2 +- doc/examples/path_length_map.py | 2 +- doc/examples/streamline_tools.py | 8 ++-- doc/examples/tracking_bootstrap_peaks.py | 2 +- doc/examples/tracking_deterministic.py | 2 +- doc/examples/tracking_introduction_eudx.py | 2 +- doc/examples/tracking_pft.py | 2 +- doc/examples/tracking_probabilistic.py | 2 +- doc/examples/tracking_sfm.py | 2 +- doc/examples/tracking_tissue_classifier.py | 2 +- doc/examples/viz_roi_contour.py | 2 +- 16 files changed, 59 insertions(+), 65 deletions(-) diff --git a/dipy/tracking/local/tests/test_tracking.py b/dipy/tracking/local/tests/test_tracking.py index 8387fcb22b..4742f33a20 100644 --- a/dipy/tracking/local/tests/test_tracking.py +++ b/dipy/tracking/local/tests/test_tracking.py @@ -297,7 +297,7 @@ def allclose(x, y): npt.assert_(len(streamlines[1]) == 1) # OUTSIDEIMAGE # Test that all points are within the image volume - seeds = seeds_from_mask(np.ones(mask.shape), density=2) + seeds = seeds_from_mask(np.ones(mask.shape), np.eye(4), density=2) streamline_generator = LocalTracking(dg, tc, seeds, np.eye(4), 0.5, return_all=True) streamlines = Streamlines(streamline_generator) @@ -349,7 +349,7 @@ def test_particle_filtering_tractography(): np.zeros(simple_gm.shape)]) simple_csf = np.ones(simple_wm.shape) - simple_wm - simple_gm tc = ActTissueClassifier.from_pve(simple_wm, simple_gm, simple_csf) - seeds = seeds_from_mask(simple_wm, density=2) + seeds = seeds_from_mask(simple_wm, np.eye(4), density=2) # Random pmf in every voxel shape_img = list(simple_wm.shape) @@ -382,7 +382,7 @@ def test_particle_filtering_tractography(): npt.assert_almost_equal(np.linalg.norm(s[i] - s[i + 1]), step_size) # Test that all points are within the image volume - seeds = seeds_from_mask(np.ones(simple_wm.shape), density=1) + seeds = seeds_from_mask(np.ones(simple_wm.shape), np.eye(4), density=1) pft_streamlines_generator = ParticleFilteringTracking( dg, tc, seeds, np.eye(4), step_size, max_cross=1, return_all=True) pft_streamlines = Streamlines(pft_streamlines_generator) diff --git a/dipy/tracking/tests/test_utils.py b/dipy/tracking/tests/test_utils.py index 6c78999262..3fbcb4704f 100644 --- a/dipy/tracking/tests/test_utils.py +++ b/dipy/tracking/tests/test_utils.py @@ -46,7 +46,7 @@ def test_density_map(): x = np.arange(10) expected = np.zeros(shape) expected[x, x, x] = 1. - dm = density_map(streamlines, vol_dims=shape, affine=np.eye(4)) + dm = density_map(streamlines, np.eye(4), shape) npt.assert_array_equal(dm, expected) # add streamline, make voxel_size smaller. Each streamline should only be @@ -59,16 +59,16 @@ def test_density_map(): expected[0, 0, 0] += 1 affine = np.eye(4) * 2 affine[:3, 3] = 0.05 - dm = density_map(streamlines, vol_dims=shape, affine=affine) + dm = density_map(streamlines, affine, shape) npt.assert_array_equal(dm, expected) # should work with a generator - dm = density_map(iter(streamlines), vol_dims=shape, affine=affine) + dm = density_map(iter(streamlines), affine, shape) npt.assert_array_equal(dm, expected) # Test passing affine affine = np.diag([2, 2, 2, 1.]) affine[: 3, 3] = 1. - dm = density_map(streamlines, shape, affine=affine) + dm = density_map(streamlines, affine, shape) npt.assert_array_equal(dm, expected) # Shift the image by 2 voxels, ie 4mm @@ -77,7 +77,7 @@ def test_density_map(): new_shape = [i + 2 for i in shape] expected = np.zeros(new_shape) expected[2:, 2:, 2:] = expected_old - dm = density_map(streamlines, new_shape, affine=affine) + dm = density_map(streamlines, affine, new_shape) npt.assert_array_equal(dm, expected) @@ -114,12 +114,11 @@ def test_connectivity_matrix(): expected[3, 4] = 2 expected[4, 3] = 1 # Check basic Case - matrix = connectivity_matrix(streamlines, label_volume, affine=np.eye(4), + matrix = connectivity_matrix(streamlines, np.eye(4), label_volume, symmetric=False) npt.assert_array_equal(matrix, expected) # Test mapping - matrix, mapping = connectivity_matrix(streamlines, label_volume, - affine=np.eye(4), + matrix, mapping = connectivity_matrix(streamlines, np.eye(4), label_volume, symmetric=False, return_mapping=True) npt.assert_array_equal(matrix, expected) @@ -127,8 +126,7 @@ def test_connectivity_matrix(): npt.assert_equal(mapping[4, 3], [2]) npt.assert_equal(mapping.get((0, 0)), None) # Test mapping and symmetric - matrix, mapping = connectivity_matrix(streamlines, label_volume, - affine=np.eye(4), + matrix, mapping = connectivity_matrix(streamlines, np.eye(4), label_volume, symmetric=True, return_mapping=True) npt.assert_equal(mapping[3, 4], [0, 1, 2]) # When symmetric only (3,4) is a key, not (4, 3) @@ -137,8 +135,7 @@ def test_connectivity_matrix(): expected = expected + expected.T npt.assert_array_equal(matrix, expected) # Test mapping_as_streamlines, mapping dict has lists of streamlines - matrix, mapping = connectivity_matrix(streamlines, label_volume, - affine=np.eye(4), + matrix, mapping = connectivity_matrix(streamlines, np.eye(4), label_volume, symmetric=False, return_mapping=True, mapping_as_streamlines=True) @@ -149,7 +146,7 @@ def test_connectivity_matrix(): # Test passing affine to connectivity_matrix affine = np.diag([-1, -1, -1, 1.]) streamlines = [-i for i in streamlines] - matrix = connectivity_matrix(streamlines, label_volume, affine=affine) + matrix = connectivity_matrix(streamlines, affine, label_volume) # In the symmetrical case, the matrix should be, well, symmetric: npt.assert_equal(matrix[4, 3], matrix[4, 3]) @@ -502,18 +499,18 @@ def test_length(): def test_seeds_from_mask(): mask = np.random.randint(0, 1, size=(10, 10, 10)) - seeds = seeds_from_mask(mask, density=1) + seeds = seeds_from_mask(mask, np.eye(4), density=1) npt.assert_equal(mask.sum(), len(seeds)) npt.assert_array_equal(np.argwhere(mask), seeds) mask[:] = False mask[3, 3, 3] = True - seeds = seeds_from_mask(mask, density=[3, 4, 5]) + seeds = seeds_from_mask(mask, np.eye(4), density=[3, 4, 5]) npt.assert_equal(len(seeds), 3 * 4 * 5) assert_true(np.all((seeds > 2.5) & (seeds < 3.5))) mask[4, 4, 4] = True - seeds = seeds_from_mask(mask, density=[3, 4, 5]) + seeds = seeds_from_mask(mask, np.eye(4), density=[3, 4, 5]) npt.assert_equal(len(seeds), 2 * 3 * 4 * 5) assert_true(np.all((seeds > 2.5) & (seeds < 4.5))) in_333 = ((seeds > 2.5) & (seeds < 3.5)).all(1) @@ -524,35 +521,35 @@ def test_seeds_from_mask(): def test_random_seeds_from_mask(): mask = np.random.randint(0, 1, size=(4, 6, 3)) - seeds = random_seeds_from_mask(mask, + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=24, seed_count_per_voxel=True) npt.assert_equal(mask.sum() * 24, len(seeds)) - seeds = random_seeds_from_mask(mask, + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=0, seed_count_per_voxel=True) npt.assert_equal(0, len(seeds)) mask[:] = False mask[2, 2, 2] = True - seeds = random_seeds_from_mask(mask, + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=8, seed_count_per_voxel=True) npt.assert_equal(mask.sum() * 8, len(seeds)) assert_true(np.all((seeds > 1.5) & (seeds < 2.5))) - seeds = random_seeds_from_mask(mask, + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=24, seed_count_per_voxel=False) npt.assert_equal(24, len(seeds)) - seeds = random_seeds_from_mask(mask, + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=0, seed_count_per_voxel=False) npt.assert_equal(0, len(seeds)) mask[:] = False mask[2, 2, 2] = True - seeds = random_seeds_from_mask(mask, + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=100, seed_count_per_voxel=False) npt.assert_equal(100, len(seeds)) @@ -560,18 +557,18 @@ def test_random_seeds_from_mask(): mask = np.zeros((15, 15, 15)) mask[2:14, 2:14, 2:14] = 1 - seeds_npv_2 = random_seeds_from_mask(mask, seeds_count=2, + seeds_npv_2 = random_seeds_from_mask(mask, np.eye(4), seeds_count=2, seed_count_per_voxel=True, random_seed=0)[:150] - seeds_npv_3 = random_seeds_from_mask(mask, seeds_count=3, + seeds_npv_3 = random_seeds_from_mask(mask, np.eye(4), seeds_count=3, seed_count_per_voxel=True, random_seed=0)[:150] assert_true(np.all(seeds_npv_2 == seeds_npv_3)) - seeds_nt_150 = random_seeds_from_mask(mask, seeds_count=150, + seeds_nt_150 = random_seeds_from_mask(mask, np.eye(4), seeds_count=150, seed_count_per_voxel=False, random_seed=0)[:150] - seeds_nt_500 = random_seeds_from_mask(mask, seeds_count=500, + seeds_nt_500 = random_seeds_from_mask(mask, np.eye(4), seeds_count=500, seed_count_per_voxel=False, random_seed=0)[:150] assert_true(np.all(seeds_nt_150 == seeds_nt_500)) @@ -589,7 +586,7 @@ def test_connectivity_matrix_shape(): np.array([[0., 1., 1.], [0., 1., 0.5], [0., 1., 0.]])] - matrix = connectivity_matrix(streamlines, labels, affine=np.eye(4)) + matrix = connectivity_matrix(streamlines, np.eye(4), labels) npt.assert_equal(matrix.shape, (3, 3)) diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index 6ad6eda4d4..2575bd31c9 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -78,13 +78,12 @@ def density_map(streamlines, vol_dims, affine): ---------- streamlines : iterable A sequence of streamlines. - - vol_dims : 3 ints - The shape of the volume to be returned containing the streamlines - counts affine : array_like (4, 4) The mapping from voxel coordinates to streamline points. The voxel_to_rasmm matrix, typically from a NIFTI file. + vol_dims : 3 ints + The shape of the volume to be returned containing the streamlines + counts Returns ------- @@ -115,7 +114,7 @@ def density_map(streamlines, vol_dims, affine): return counts -def connectivity_matrix(streamlines, label_volume, affine, +def connectivity_matrix(streamlines, affine, label_volume, symmetric=True, return_mapping=False, mapping_as_streamlines=False): """Counts the streamlines that start and end at each label pair. @@ -124,12 +123,12 @@ def connectivity_matrix(streamlines, label_volume, affine, ---------- streamlines : sequence A sequence of streamlines. - label_volume : ndarray - An image volume with an integer data type, where the intensities in the - volume map to anatomical structures. affine : array_like (4, 4) The mapping from voxel coordinates to streamline coordinates. The voxel_to_rasmm matrix, typically from a NIFTI file. + label_volume : ndarray + An image volume with an integer data type, where the intensities in the + volume map to anatomical structures. symmetric : bool, True by default Symmetric means we don't distinguish between start and end points. If symmetric is True, ``matrix[i, j] == matrix[j, i]``. @@ -355,9 +354,9 @@ def seeds_from_mask(mask, affine, density=[1, 1, 1]): -------- >>> mask = np.zeros((3,3,3), 'bool') >>> mask[0,0,0] = 1 - >>> seeds_from_mask(mask, [1,1,1], [1,1,1]) + >>> seeds_from_mask(mask, np.eye(4), [1,1,1], [1,1,1]) array([[ 0.5, 0.5, 0.5]]) - >>> seeds_from_mask(mask, [1,2,3], [1,1,1]) + >>> seeds_from_mask(mask, np.eye(4), [1,2,3], [1,1,1]) array([[ 0.5 , 0.25 , 0.16666667], [ 0.5 , 0.75 , 0.16666667], [ 0.5 , 0.25 , 0.5 ], @@ -448,11 +447,11 @@ def random_seeds_from_mask(mask, affine, seeds_count=1, -------- >>> mask = np.zeros((3,3,3), 'bool') >>> mask[0,0,0] = 1 - >>> random_seeds_from_mask(mask, seeds_count=1, seed_count_per_voxel=True, - ... random_seed=1) + >>> random_seeds_from_mask(mask, np.eye(4), seeds_count=1, + ... seed_count_per_voxel=True, random_seed=1) array([[-0.0640051 , -0.47407377, 0.04966248]]) - >>> random_seeds_from_mask(mask, seeds_count=6, seed_count_per_voxel=True, - ... random_seed=1) + >>> random_seeds_from_mask(mask, np.eye(4), seeds_count=6, + ... seed_count_per_voxel=True, random_seed=1) array([[-0.0640051 , -0.47407377, 0.04966248], [ 0.0507979 , 0.20814782, -0.20909526], [ 0.46702984, 0.04723225, 0.47268436], diff --git a/dipy/workflows/tracking.py b/dipy/workflows/tracking.py index cfcb24e607..de3080d13b 100644 --- a/dipy/workflows/tracking.py +++ b/dipy/workflows/tracking.py @@ -91,9 +91,8 @@ def _core_run(self, stopping_path, use_binary_mask, stopping_thr, seed_mask, _ = load_nifti(seeding_path) seeds = \ utils.seeds_from_mask( - seed_mask, - density=[seed_density, seed_density, seed_density], - affine=affine) + seed_mask, affine, + density=[seed_density, seed_density, seed_density]) logging.info('seeds done') tracking_result = LocalTracking(direction_getter, @@ -292,10 +291,9 @@ def run(self, pam_files, wm_files, gm_files, csf_files, seeding_files, average_voxel_size=avs) logging.info('classifier done') seed_mask, _ = load_nifti(seeding_path) - seeds = utils.seeds_from_mask(seed_mask, + seeds = utils.seeds_from_mask(seed_mask, affine, density=[seed_density, seed_density, - seed_density], - affine=affine) + seed_density]) logging.info('seeds done') dg = ProbabilisticDirectionGetter diff --git a/doc/examples/cluster_confidence.py b/doc/examples/cluster_confidence.py index c26d73a283..9f6ec65bf7 100644 --- a/doc/examples/cluster_confidence.py +++ b/doc/examples/cluster_confidence.py @@ -54,7 +54,7 @@ # Make a corpus callosum seed mask for tracking seed_mask = labels == 2 -seeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine) +seeds = utils.seeds_from_mask(seed_mask, affine, density=[1, 1, 1]) # Make a streamline bundle model of the corpus callosum ROI connectivity streamlines = LocalTracking(csa_peaks, classifier, seeds, affine, step_size=2) diff --git a/doc/examples/fiber_to_bundle_coherence.py b/doc/examples/fiber_to_bundle_coherence.py index 741c37626e..e1ae0299ac 100644 --- a/doc/examples/fiber_to_bundle_coherence.py +++ b/doc/examples/fiber_to_bundle_coherence.py @@ -130,7 +130,7 @@ mask = np.zeros(data.shape[:-1], 'bool') rad = 3 mask[26-rad:26+rad, 29-rad:29+rad, 31-rad:31+rad] = True -seeds = utils.seeds_from_mask(mask, density=[4, 4, 4], affine=affine) +seeds = utils.seeds_from_mask(mask, affine, density=[4, 4, 4]) """ Local Tracking is used for probabilistic tractography which takes the diff --git a/doc/examples/path_length_map.py b/doc/examples/path_length_map.py index e6b901b988..b52d97c924 100644 --- a/doc/examples/path_length_map.py +++ b/doc/examples/path_length_map.py @@ -62,7 +62,7 @@ # Make a corpus callosum seed mask for tracking seed_mask = labels == 2 -seeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine) +seeds = utils.seeds_from_mask(seed_mask, affine, density=[1, 1, 1]) # Make a streamline bundle model of the corpus callosum ROI connectivity streamlines = LocalTracking(csa_peaks, classifier, seeds, affine, diff --git a/doc/examples/streamline_tools.py b/doc/examples/streamline_tools.py index 9d13e9f980..cab529c461 100644 --- a/doc/examples/streamline_tools.py +++ b/doc/examples/streamline_tools.py @@ -61,7 +61,7 @@ tracking exit the white matter. """ -seeds = utils.seeds_from_mask(white_matter, density=1) +seeds = utils.seeds_from_mask(white_matter, np.eye(4), density=1) tissue_classifier = BinaryTissueClassifier(white_matter) affine = np.eye(4) @@ -157,7 +157,7 @@ each streamline. """ -M, grouping = utils.connectivity_matrix(cc_streamlines, labels, affine=affine, +M, grouping = utils.connectivity_matrix(cc_streamlines, affine, labels, return_mapping=True, mapping_as_streamlines=True) M[:3, :] = 0 @@ -212,7 +212,7 @@ lr_superiorfrontal_track = grouping[11, 54] shape = labels.shape -dm = utils.density_map(lr_superiorfrontal_track, shape, affine=affine) +dm = utils.density_map(lr_superiorfrontal_track, affine, shape) """ Let's save this density map and the streamlines so that they can be @@ -264,7 +264,7 @@ as long as we specify the right coordinate system. """ -dm_trackvis = utils.density_map(lr_sf_trk, shape, affine=np.eye(4)) +dm_trackvis = utils.density_map(lr_sf_trk, np.eye(4), shape) assert np.all(dm == dm_trackvis) """ diff --git a/doc/examples/tracking_bootstrap_peaks.py b/doc/examples/tracking_bootstrap_peaks.py index 4f5aee0a2f..f176022fe2 100644 --- a/doc/examples/tracking_bootstrap_peaks.py +++ b/doc/examples/tracking_bootstrap_peaks.py @@ -31,7 +31,7 @@ seed_mask = (labels == 2) white_matter = (labels == 1) | (labels == 2) -seeds = utils.seeds_from_mask(seed_mask, density=1, affine=affine) +seeds = utils.seeds_from_mask(seed_mask, affine, density=1) """ Next, we fit the CSD model. diff --git a/doc/examples/tracking_deterministic.py b/doc/examples/tracking_deterministic.py index 71c2675425..ae85ca6228 100644 --- a/doc/examples/tracking_deterministic.py +++ b/doc/examples/tracking_deterministic.py @@ -41,7 +41,7 @@ seed_mask = labels == 2 white_matter = (labels == 1) | (labels == 2) -seeds = utils.seeds_from_mask(seed_mask, density=1, affine=affine) +seeds = utils.seeds_from_mask(seed_mask, affine, density=1) csd_model = ConstrainedSphericalDeconvModel(gtab, None, sh_order=6) csd_fit = csd_model.fit(data, mask=white_matter) diff --git a/doc/examples/tracking_introduction_eudx.py b/doc/examples/tracking_introduction_eudx.py index a2301315bb..5211496448 100644 --- a/doc/examples/tracking_introduction_eudx.py +++ b/doc/examples/tracking_introduction_eudx.py @@ -142,7 +142,7 @@ import numpy as np seed_mask = (labels == 2) -seeds = utils.seeds_from_mask(seed_mask, density=[2, 2, 2], affine=np.eye(4)) +seeds = utils.seeds_from_mask(seed_mask, np.eye(4), density=[2, 2, 2]) """ Finally, we can bring it all together using ``LocalTracking``, performing Using diff --git a/doc/examples/tracking_pft.py b/doc/examples/tracking_pft.py index 19807670e7..14db4715f8 100644 --- a/doc/examples/tracking_pft.py +++ b/doc/examples/tracking_pft.py @@ -56,7 +56,7 @@ seed_mask = (labels == 2) seed_mask[img_pve_wm.get_data() < 0.5] = 0 -seeds = utils.seeds_from_mask(seed_mask, density=2, affine=affine) +seeds = utils.seeds_from_mask(seed_mask, affine, density=2) """ CMC/ACT Tissue Classifiers diff --git a/doc/examples/tracking_probabilistic.py b/doc/examples/tracking_probabilistic.py index d0587edb7b..65739d2815 100644 --- a/doc/examples/tracking_probabilistic.py +++ b/doc/examples/tracking_probabilistic.py @@ -36,7 +36,7 @@ seed_mask = (labels == 2) white_matter = (labels == 1) | (labels == 2) -seeds = utils.seeds_from_mask(seed_mask, density=1, affine=affine) +seeds = utils.seeds_from_mask(seed_mask, affine, density=1) csd_model = ConstrainedSphericalDeconvModel(gtab, None, sh_order=6) csd_fit = csd_model.fit(data, mask=white_matter) diff --git a/doc/examples/tracking_sfm.py b/doc/examples/tracking_sfm.py index bb258c1447..ea05c2eaea 100644 --- a/doc/examples/tracking_sfm.py +++ b/doc/examples/tracking_sfm.py @@ -83,7 +83,7 @@ """ from dipy.tracking import utils -seeds = utils.seeds_from_mask(white_matter, density=[2, 2, 2], affine=affine) +seeds = utils.seeds_from_mask(white_matter, affine, density=[2, 2, 2]) """ For the sake of brevity, we will take only the first 1000 seeds, generating diff --git a/doc/examples/tracking_tissue_classifier.py b/doc/examples/tracking_tissue_classifier.py index 2f91918ca1..031d31c6f5 100644 --- a/doc/examples/tracking_tissue_classifier.py +++ b/doc/examples/tracking_tissue_classifier.py @@ -50,7 +50,7 @@ seed_mask = (labels == 2) seed_mask[img_pve_wm.get_data() < 0.5] = 0 -seeds = utils.seeds_from_mask(seed_mask, density=2, affine=affine) +seeds = utils.seeds_from_mask(seed_mask, affine, density=2) response, ratio = auto_response(gtab, data, roi_radius=10, fa_thr=0.7) csd_model = ConstrainedSphericalDeconvModel(gtab, response) diff --git a/doc/examples/viz_roi_contour.py b/doc/examples/viz_roi_contour.py index 3f67adab4b..214d82cf98 100644 --- a/doc/examples/viz_roi_contour.py +++ b/doc/examples/viz_roi_contour.py @@ -41,7 +41,7 @@ classifier = ThresholdTissueClassifier(csa_peaks.gfa, .25) seed_mask = labels == 2 -seeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine) +seeds = utils.seeds_from_mask(seed_mask, affine, density=[1, 1, 1]) # Initialization of LocalTracking. The computation happens in the next step. streamlines = LocalTracking(csa_peaks, classifier, seeds, affine, From aec04cc8ce4bdbf7bd32b75a713b1a9dbfab7882 Mon Sep 17 00:00:00 2001 From: frheault Date: Mon, 29 Jul 2019 16:15:59 -0400 Subject: [PATCH 03/13] Fix second half of dependacy from utils --- dipy/tracking/tests/test_utils.py | 56 +++++++++++------------ dipy/tracking/utils.py | 26 +++++------ doc/examples/fiber_to_bundle_coherence.py | 3 +- doc/examples/path_length_map.py | 3 +- doc/examples/streamline_tools.py | 4 +- 5 files changed, 45 insertions(+), 47 deletions(-) diff --git a/dipy/tracking/tests/test_utils.py b/dipy/tracking/tests/test_utils.py index 3fbcb4704f..335376eddc 100644 --- a/dipy/tracking/tests/test_utils.py +++ b/dipy/tracking/tests/test_utils.py @@ -255,28 +255,28 @@ def _target(target_f, streamlines, voxel_both_true, voxel_one_true, # Both pass though mask[voxel_both_true] = True - new = list(target_f(streamlines, mask, affine=affine)) + new = list(target_f(streamlines, affine, mask)) npt.assert_equal(len(new), 2) - new = list(target_f(streamlines, mask, affine=affine, include=False)) + new = list(target_f(streamlines, affine, mask, include=False)) npt.assert_equal(len(new), 0) # only first mask[:] = False mask[voxel_one_true] = True - new = list(target_f(streamlines, mask, affine=affine)) + new = list(target_f(streamlines, affine, mask)) npt.assert_equal(len(new), 1) assert_true(new[0] is streamlines[0]) - new = list(target_f(streamlines, mask, affine=affine, include=False)) + new = list(target_f(streamlines, affine, mask, include=False)) npt.assert_equal(len(new), 1) assert_true(new[0] is streamlines[1]) # Test that bad points raise a value error if test_bad_points: bad_sl = streamlines + [np.array([[10.0, 10.0, 10.0]])] - new = target_f(bad_sl, mask, affine=affine) + new = target_f(bad_sl, affine, mask) npt.assert_raises(ValueError, list, new) bad_sl = streamlines + [-np.array([[10.0, 10.0, 10.0]])] - new = target_f(bad_sl, mask, affine=affine) + new = target_f(bad_sl, affine, mask) npt.assert_raises(ValueError, list, new) # Test smaller voxels @@ -285,16 +285,16 @@ def _target(target_f, streamlines, voxel_both_true, voxel_one_true, [0, 0, .4, 0], [0, 0, 0, 1]]) streamlines = list(move_streamlines(streamlines, affine)) - new = list(target_f(streamlines, mask, affine=affine)) + new = list(target_f(streamlines, affine, mask)) npt.assert_equal(len(new), 1) assert_true(new[0] is streamlines[0]) - new = list(target_f(streamlines, mask, affine=affine, include=False)) + new = list(target_f(streamlines, affine, mask, include=False)) npt.assert_equal(len(new), 1) assert_true(new[0] is streamlines[1]) # Test that changing mask or affine does not break target/target_line_based - include = target_f(streamlines, mask, affine=affine) - exclude = target_f(streamlines, mask, affine=affine, include=False) + include = target_f(streamlines, affine, mask) + exclude = target_f(streamlines, affine, mask, include=False) affine[:] = np.eye(4) mask[:] = False include = list(include) @@ -320,23 +320,23 @@ def test_near_roi(): mask[0, 0, 0] = True mask[1, 0, 0] = True - npt.assert_array_equal(near_roi(streamlines, mask, tol=1), + npt.assert_array_equal(near_roi(streamlines, affine, mask, tol=1), np.array([True, True, False])) - npt.assert_array_equal(near_roi(streamlines, mask), + npt.assert_array_equal(near_roi(streamlines, affine, mask), np.array([False, True, False])) # If there is an affine, we need to use it: affine[:, 3] = [-1, 100, -20, 1] # Transform the streamlines: x_streamlines = [sl + affine[:3, 3] for sl in streamlines] - npt.assert_array_equal(near_roi(x_streamlines, mask, affine=affine, tol=1), + npt.assert_array_equal(near_roi(x_streamlines, affine, mask, tol=1), np.array([True, True, False])) - npt.assert_array_equal(near_roi(x_streamlines, mask, affine=affine, + npt.assert_array_equal(near_roi(x_streamlines, affine, mask, tol=None), np.array([False, True, False])) # Test for use of the 'all' mode: - npt.assert_array_equal(near_roi(x_streamlines, mask, affine=affine, + npt.assert_array_equal(near_roi(x_streamlines, affine, mask, tol=None, mode='all'), np.array([False, False, False])) @@ -346,15 +346,15 @@ def test_near_roi(): # to a very small number gets overridden: with warnings.catch_warnings(): warnings.simplefilter("ignore") - npt.assert_array_equal(near_roi(x_streamlines, - mask, affine=affine, + npt.assert_array_equal(near_roi(x_streamlines, affine, + mask, tol=0.1, mode='all'), np.array([False, True, False])) mask[2, 2, 2] = True mask[3, 3, 3] = True - npt.assert_array_equal(near_roi(x_streamlines, mask, affine=affine, + npt.assert_array_equal(near_roi(x_streamlines, affine, mask, tol=None, mode='all'), np.array([False, True, True])) @@ -363,17 +363,17 @@ def test_near_roi(): mask[0, 1, 1] = True mask[3, 2, 2] = True - npt.assert_array_equal(near_roi(streamlines, mask, tol=0.87, + npt.assert_array_equal(near_roi(streamlines, affine, mask, tol=0.87, mode="either_end"), np.array([True, False, False])) - npt.assert_array_equal(near_roi(streamlines, mask, tol=0.87, + npt.assert_array_equal(near_roi(streamlines, affine, mask, tol=0.87, mode="both_end"), np.array([False, False, False])) mask[0, 0, 0] = True mask[0, 2, 2] = True - npt.assert_array_equal(near_roi(streamlines, mask, mode="both_end"), + npt.assert_array_equal(near_roi(streamlines, affine, mask, mode="both_end"), np.array([False, True, False])) # Test with a generator input: @@ -381,7 +381,7 @@ def generate_sl(streamlines): for sl in streamlines: yield sl - npt.assert_array_equal(near_roi(generate_sl(streamlines), + npt.assert_array_equal(near_roi(generate_sl(streamlines), affine, mask, mode="both_end"), np.array([False, True, False])) @@ -681,26 +681,26 @@ def test_path_length(): # A few tests for basic usage x = np.arange(20) streamlines = [np.array([x, x, x]).T] - pl = path_length(streamlines, aoi, affine=np.eye(4)) + pl = path_length(streamlines, np.eye(4), aoi) expected = x.copy() * np.sqrt(3) # expected[0] = np.inf npt.assert_array_almost_equal(pl[x, x, x], expected) aoi[19, 19, 19] = 1 - pl = path_length(streamlines, aoi, affine=np.eye(4)) + pl = path_length(streamlines, np.eye(4), aoi) expected = np.minimum(expected, expected[::-1]) npt.assert_array_almost_equal(pl[x, x, x], expected) aoi[19, 19, 19] = 0 aoi[1, 1, 1] = 1 - pl = path_length(streamlines, aoi, affine=np.eye(4)) + pl = path_length(streamlines, np.eye(4), aoi) expected = (x - 1) * np.sqrt(3) expected[0] = 0 npt.assert_array_almost_equal(pl[x, x, x], expected) z = np.zeros(x.shape, x.dtype) streamlines.append(np.array([x, z, z]).T) - pl = path_length(streamlines, aoi, affine=np.eye(4)) + pl = path_length(streamlines, np.eye(4), aoi) npt.assert_array_almost_equal(pl[x, x, x], expected) npt.assert_array_almost_equal(pl[x, 0, 0], x) @@ -714,10 +714,10 @@ def test_path_length(): assert (rando > .5).all() assert (rando < 19.5).all() streamlines.append(rando) - pl = path_length(streamlines, aoi, affine=np.eye(4)) + pl = path_length(streamlines, np.eye(4), aoi) npt.assert_array_almost_equal(pl, -1) - pl = path_length(streamlines, aoi, affine=np.eye(4), fill_value=-12.) + pl = path_length(streamlines, np.eye(4), aoi, fill_value=-12.) npt.assert_array_almost_equal(pl, -12.) diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index 2575bd31c9..c47330d8f6 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -530,7 +530,7 @@ def helper(*args, **kwargs): @_with_initialize -def target(streamlines, target_mask, affine, include=True): +def target(streamlines, affine, target_mask, include=True): """Filters streamlines based on whether or not they pass through an ROI. Parameters @@ -538,12 +538,12 @@ def target(streamlines, target_mask, affine, include=True): streamlines : iterable A sequence of streamlines. Each streamline should be a (N, 3) array, where N is the length of the streamline. - target_mask : array-like - A mask used as a target. Non-zero values are considered to be within - the target region. affine : array (4, 4) The mapping between voxel indices and the point space for seeds. The voxel_to_rasmm matrix, typically from a NIFTI file. + target_mask : array-like + A mask used as a target. Non-zero values are considered to be within + the target region. include : bool, default True If True, streamlines passing through `target_mask` are kept. If False, the streamlines not passing through `target_mask` are kept. @@ -580,7 +580,7 @@ def target(streamlines, target_mask, affine, include=True): @_with_initialize -def target_line_based(streamlines, target_mask, affine, include=True): +def target_line_based(streamlines, affine, target_mask, include=True): """Filters streamlines based on whether or not they pass through a ROI, using a line-based algorithm. Mostly used as a replacement of `target` for compressed streamlines. @@ -593,12 +593,12 @@ def target_line_based(streamlines, target_mask, affine, include=True): streamlines : iterable A sequence of streamlines. Each streamline should be a (N, 3) array, where N is the length of the streamline. - target_mask : array-like - A mask used as a target. Non-zero values are considered to be within - the target region. affine : array (4, 4) The mapping between voxel indices and the point space for seeds. The voxel_to_rasmm matrix, typically from a NIFTI file. + target_mask : array-like + A mask used as a target. Non-zero values are considered to be within + the target region. include : bool, default True If True, streamlines passing through `target_mask` are kept. If False, the streamlines not passing through `target_mask` are kept. @@ -683,7 +683,7 @@ def streamline_near_roi(streamline, roi_coords, tol, mode='any'): return np.all(np.min(dist, -1) <= tol) -def near_roi(streamlines, region_of_interest, affine, tol=None, +def near_roi(streamlines, affine, region_of_interest, tol=None, mode="any"): """Provide filtering criteria for a set of streamlines based on whether they fall within a tolerance distance from an ROI @@ -693,12 +693,12 @@ def near_roi(streamlines, region_of_interest, affine, tol=None, streamlines : list or generator A sequence of streamlines. Each streamline should be a (N, 3) array, where N is the length of the streamline. - region_of_interest : ndarray - A mask used as a target. Non-zero values are considered to be within - the target region. affine : array (4, 4) The mapping between voxel indices and the point space for seeds. The voxel_to_rasmm matrix, typically from a NIFTI file. + region_of_interest : ndarray + A mask used as a target. Non-zero values are considered to be within + the target region. tol : float Distance (in the units of the streamlines, usually mm). If any coordinate in the streamline is within this distance from the center @@ -880,7 +880,7 @@ def _min_at(a, index, value): minimum_at = _min_at -def path_length(streamlines, aoi, affine, fill_value=-1): +def path_length(streamlines, affine, aoi, fill_value=-1): """ Computes the shortest path, along any streamline, between aoi and each voxel. diff --git a/doc/examples/fiber_to_bundle_coherence.py b/doc/examples/fiber_to_bundle_coherence.py index e1ae0299ac..b5a3b22b2b 100644 --- a/doc/examples/fiber_to_bundle_coherence.py +++ b/doc/examples/fiber_to_bundle_coherence.py @@ -158,8 +158,7 @@ mask_lgn[35-rad:35+rad, 42-rad:42+rad, 28-rad:28+rad] = True # Select all the fibers that enter the LGN and discard all others -filtered_fibers2 = utils.near_roi(streamlines, mask_lgn, tol=1.8, - affine=affine) +filtered_fibers2 = utils.near_roi(streamlines, affine, mask_lgn, tol=1.8) sfil = [] for i in range(len(streamlines)): diff --git a/doc/examples/path_length_map.py b/doc/examples/path_length_map.py index b52d97c924..bfb5289fdf 100644 --- a/doc/examples/path_length_map.py +++ b/doc/examples/path_length_map.py @@ -118,8 +118,7 @@ path_length_map_base_roi = seed_mask # calculate the WMPL - -wmpl = path_length(streamlines, path_length_map_base_roi, affine) +wmpl = path_length(streamlines, affine, path_length_map_base_roi) # save the WMPL as a nifti path_length_img = nib.Nifti1Image(wmpl.astype(np.float32), affine) diff --git a/doc/examples/streamline_tools.py b/doc/examples/streamline_tools.py index cab529c461..8cc73ffe3c 100644 --- a/doc/examples/streamline_tools.py +++ b/doc/examples/streamline_tools.py @@ -84,10 +84,10 @@ """ cc_slice = labels == 2 -cc_streamlines = utils.target(streamlines, cc_slice, affine=affine) +cc_streamlines = utils.target(streamlines, affine, cc_slice) cc_streamlines = Streamlines(cc_streamlines) -other_streamlines = utils.target(streamlines, cc_slice, affine=affine, +other_streamlines = utils.target(streamlines, affine, cc_slice, include=False) other_streamlines = Streamlines(other_streamlines) assert len(other_streamlines) + len(cc_streamlines) == len(streamlines) From 1046084862054166ec23f58ecf5b7c802c047ab3 Mon Sep 17 00:00:00 2001 From: frheault Date: Mon, 29 Jul 2019 16:32:12 -0400 Subject: [PATCH 04/13] Added back move_streamlines under a new name for precision --- dipy/tracking/local/localtracking.py | 9 +-- dipy/tracking/tests/test_utils.py | 97 +--------------------------- dipy/tracking/utils.py | 47 ++++++++++++-- 3 files changed, 45 insertions(+), 108 deletions(-) diff --git a/dipy/tracking/local/localtracking.py b/dipy/tracking/local/localtracking.py index 02ca5c3ecd..b61d29c425 100644 --- a/dipy/tracking/local/localtracking.py +++ b/dipy/tracking/local/localtracking.py @@ -111,12 +111,9 @@ def _tracker(self, seed, first_step, streamline): def __iter__(self): # Make tracks, move them to point space and return track = self._generate_streamlines() - seeds = None - if self.save_seeds: - track, seeds = zip(*track) - return utils.move_streamlines(track, - self.affine, - seeds=seeds) + + return utils.transform_tracking_output(track, affine, + seeding_activated=self.save_seeds) def _generate_streamlines(self): """A streamline generator""" diff --git a/dipy/tracking/tests/test_utils.py b/dipy/tracking/tests/test_utils.py index 335376eddc..33597e47cc 100644 --- a/dipy/tracking/tests/test_utils.py +++ b/dipy/tracking/tests/test_utils.py @@ -4,14 +4,13 @@ import numpy as np from dipy.io.bvectxt import orientation_from_string -from dipy.tracking.utils import (affine_for_trackvis, connectivity_matrix, +from dipy.tracking.utils import (connectivity_matrix, density_map, length, move_streamlines, ndbincount, reduce_labels, reorder_voxels_affine, seeds_from_mask, random_seeds_from_mask, target, target_line_based, unique_rows, near_roi, - reduce_rois, path_length, flexi_tvis_affine, - get_flexi_tvis_affine, _min_at) + reduce_rois, path_length, _min_at) from dipy.tracking._utils import _to_voxel_coordinates @@ -188,47 +187,6 @@ def test_reduce_labels(): npt.assert_array_equal(lookup, labels.ravel()) -def test_move_streamlines(): - streamlines, seeds = make_streamlines(True) - affine = np.eye(4) - new_streamlines = move_streamlines(streamlines, affine) - for i, test_sl in enumerate(new_streamlines): - npt.assert_array_equal(test_sl, streamlines[i]) - - affine[:3, 3] += (4, 5, 6) - new_streamlines = move_streamlines(streamlines, affine) - for i, test_sl in enumerate(new_streamlines): - npt.assert_array_equal(test_sl, streamlines[i] + (4, 5, 6)) - - affine = np.eye(4) - affine = affine[[2, 1, 0, 3]] - new_streamlines = move_streamlines(streamlines, affine) - for i, test_sl in enumerate(new_streamlines): - npt.assert_array_equal(test_sl, streamlines[i][:, [2, 1, 0]]) - - affine[:3, 3] += (4, 5, 6) - new_streamlines = move_streamlines(streamlines, affine) - undo_affine = move_streamlines(new_streamlines, np.eye(4), - input_space=affine) - for i, test_sl in enumerate(undo_affine): - npt.assert_array_almost_equal(test_sl, streamlines[i]) - - # Test that changing affine does affect moving streamlines - affineA = affine.copy() - affineB = affine.copy() - streamlinesA = move_streamlines(streamlines, affineA) - streamlinesB = move_streamlines(streamlines, affineB) - affineB[:] = 0 - for (a, b) in zip(streamlinesA, streamlinesB): - npt.assert_array_equal(a, b) - - # Test that seeds are also moved - streamlinesA, seedsA = zip(*move_streamlines( - streamlines, affineA, seeds=seeds)) - for (seed, seedA) in zip(seeds, seedsA): - npt.assert_raises(AssertionError, npt.assert_array_equal, seed, seedA) - - def test_target(): streamlines = [np.array([[0., 0., 0.], [1., 0., 0.], @@ -468,13 +426,6 @@ def test_streamline_mapping(): npt.assert_equal(mapping, expected) -def test_affine_for_trackvis(): - voxel_size = np.array([1., 2, 3.]) - affine = affine_for_trackvis(voxel_size) - origin = np.dot(affine, [0, 0, 0, 1]) - npt.assert_array_almost_equal(origin[:3], voxel_size / 2) - - def test_length(): # Generate a simulated bundle of fibers: n_streamlines = 50 @@ -630,50 +581,6 @@ def test_reduce_rois(): npt.assert_equal(exclude_roi, np.zeros((4, 4, 4))) -def test_flexi_tvis_affine(): - sl_vox_order = 'RPI' - grid_affine = np.array( - [[-1.08566022e+00, 1.42664334e-03, 2.43463114e-01, 1.34783203e+02], - [2.43251352e-03, 1.09376717e+00, 1.48301506e-02, -1.07367630e+02], - [1.33170187e-01, -8.34854878e-03, 1.98454463e+00, -9.98151169e+01], - [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) - dim = (256, 256, 86) - voxel_size = np.array([1.09379995, 1.09379995, 1.99947774]) - affine = flexi_tvis_affine(sl_vox_order, grid_affine, dim, voxel_size) - - origin = np.dot(affine, [0, 0, 0, 1]) - npt.assert_array_almost_equal(origin[:3], np.multiply(dim, voxel_size) - - voxel_size / 2) - - -def test_get_flexi_tvis_affine(): - tvis_hdr = {'voxel_order': 'RPI', 'dim': (30, 40, 50), - 'voxel_size': [2, 3, 4]} - - grid_affine = np.array([[-2, 0, 0, 0], - [0, 3, 0, 0], - [0, 0, 4, 0], - [0, 0, 0, 1.]]) - - affine = get_flexi_tvis_affine(tvis_hdr, grid_affine) - - origin = np.dot(affine, [0, 0, 0, 1]) - vsz = np.array(tvis_hdr['voxel_size']) - npt.assert_array_almost_equal(origin[:3], - np.multiply(tvis_hdr['dim'], vsz) - vsz / 2) - - # grid_affine = - tvis_hdr['voxel_order'] = 'ASL' - vsz = tvis_hdr['voxel_size'] = np.array([3, 4, 2.]) - affine = get_flexi_tvis_affine(tvis_hdr, grid_affine) - - vox_point = np.array([9, 8, 7]) - trk_point = np.dot(affine, np.append(vox_point, 1)) - - npt.assert_array_almost_equal(trk_point[:3], - (vox_point[[1, 2, 0]] + 0.5) * vsz) - - def test_path_length(): aoi = np.zeros((20, 20, 20), dtype=bool) aoi[0, 0, 0] = 1 diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index c47330d8f6..fbd40c5e51 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -810,8 +810,46 @@ def unique_rows(in_array, dtype='f4'): diff_in_array = diff_x[un_order] return in_array[diff_in_array] -# affine_for_trackvis -# move_streamlines + +@_with_initialize +def transform_tracking_output(tracking_output, affine, seeding_activated=False): + """Applies a linear transformation, given by affine, to streamlines. + Parameters + ---------- + streamlines : sequence + A set of streamlines to be transformed. + affine : array (4, 4) + The mapping between voxel indices and the point space for seeds. + The voxel_to_rasmm matrix, typically from a NIFTI file. + input_space : array (4, 4), optional + An affine matrix describing the current space of the streamlines, if no + ``input_space`` is specified, it's assumed the streamlines are in the + reference space. The reference space is the same as the space + associated with the affine matrix ``np.eye(4)``. + seeds : np.array, optional + If set, seeds associated to streamlines will be also moved and returned + Returns + ------- + streamlines : generator + A sequence of transformed streamlines. + If return_seeds is True, also return seeds + """ + if seeding_activated: + streamlines, seeds = zip(*tracking_output) + else: + streamlines = tracking_output + + lin_T = affine[:3, :3].T.copy() + offset = affine[:3, 3].copy() + yield + # End of initialization + + if seeds is not None: + for sl, seed in zip(streamlines, seeds): + yield np.dot(sl, lin_T) + offset, np.dot(seed, lin_T) + offset + else: + for sl in streamlines: + yield np.dot(sl, lin_T) + offset def reduce_rois(rois, include): """Reduce multiple ROIs to one inclusion and one exclusion ROI. @@ -854,11 +892,6 @@ def reduce_rois(rois, include): return include_roi, exclude_roi -# flexi_tvis_affine - -# get_flexi_tvis_affine - - def _min_at(a, index, value): index = np.asarray(index) sort_keys = [value] + list(index) From 7761d5ce26c38cf5f18dccd6c537d07eec4d79b9 Mon Sep 17 00:00:00 2001 From: frheault Date: Mon, 29 Jul 2019 17:12:51 -0400 Subject: [PATCH 05/13] First testing phase (test/examples) --- dipy/tracking/local/localtracking.py | 2 +- dipy/tracking/streamline.py | 4 +- dipy/tracking/tests/test_life.py | 6 +- dipy/tracking/tests/test_streamline.py | 7 +-- dipy/tracking/tests/test_utils.py | 76 ++++---------------------- dipy/tracking/utils.py | 19 +++---- 6 files changed, 29 insertions(+), 85 deletions(-) diff --git a/dipy/tracking/local/localtracking.py b/dipy/tracking/local/localtracking.py index b61d29c425..5c6a3b2dd3 100644 --- a/dipy/tracking/local/localtracking.py +++ b/dipy/tracking/local/localtracking.py @@ -112,7 +112,7 @@ def __iter__(self): # Make tracks, move them to point space and return track = self._generate_streamlines() - return utils.transform_tracking_output(track, affine, + return utils.transform_tracking_output(track, self.affine, seeding_activated=self.save_seeds) def _generate_streamlines(self): diff --git a/dipy/tracking/streamline.py b/dipy/tracking/streamline.py index cfc1f9903a..af024346e2 100644 --- a/dipy/tracking/streamline.py +++ b/dipy/tracking/streamline.py @@ -633,8 +633,8 @@ def _extract_vals(data, streamlines, affine=None, threedvec=False): isinstance(streamlines, types.GeneratorType) or isinstance(streamlines, Streamlines)): if affine is not None: - streamlines = ut.move_streamlines(streamlines, - np.linalg.inv(affine)) + streamlines = transform_streamlines(streamlines, + np.linalg.inv(affine)) vals = [] for sl in streamlines: diff --git a/dipy/tracking/tests/test_life.py b/dipy/tracking/tests/test_life.py index d3e4a70984..6b11e05491 100644 --- a/dipy/tracking/tests/test_life.py +++ b/dipy/tracking/tests/test_life.py @@ -11,7 +11,7 @@ import dipy.tracking.life as life from dipy.io.gradients import read_bvals_bvecs -from dipy.tracking.utils import move_streamlines +from dipy.tracking.streamline import transform_streamlines THIS_DIR = op.dirname(__file__) @@ -162,8 +162,8 @@ def test_fit_data(): ni_data = nib.load(fdata) data = ni_data.get_data() tensor_streamlines = nib.streamlines.load(fstreamlines).streamlines - tensor_streamlines = move_streamlines(tensor_streamlines, np.eye(4), - ni_data.affine) + tensor_streamlines = transform_streamlines(tensor_streamlines, + np.linalg.inv(ni_data.affine)) life_model = life.FiberModel(gtab) life_fit = life_model.fit(data, tensor_streamlines) model_error = life_fit.predict() - life_fit.data diff --git a/dipy/tracking/tests/test_streamline.py b/dipy/tracking/tests/test_streamline.py index 8b722b8df0..4fa59229e7 100644 --- a/dipy/tracking/tests/test_streamline.py +++ b/dipy/tracking/tests/test_streamline.py @@ -15,7 +15,6 @@ assert_almost_equal, assert_equal) from dipy.tracking.streamline import Streamlines -import dipy.tracking.utils as ut from dipy.tracking.streamline import (set_number_of_points, length, relist_streamlines, @@ -1110,15 +1109,15 @@ def test_values_from_volume(): affine = np.eye(4) affine[:, 3] = [-100, 10, 1, 1] - x_sl1 = ut.move_streamlines(sl1, affine) - x_sl2 = ut.move_streamlines(sl1, affine) + x_sl1 = transform_streamlines(sl1, affine) + x_sl2 = transform_streamlines(sl1, affine) vv = values_from_volume(data, x_sl1, affine=affine) npt.assert_almost_equal(vv, ans1, decimal=decimal) # The generator has already been consumed so needs to be # regenerated: - x_sl1 = list(ut.move_streamlines(sl1, affine)) + x_sl1 = list(transform_streamlines(sl1, affine)) vv = values_from_volume(data, x_sl1, affine=affine) npt.assert_almost_equal(vv, ans1, decimal=decimal) diff --git a/dipy/tracking/tests/test_utils.py b/dipy/tracking/tests/test_utils.py index 33597e47cc..56afa2a6e7 100644 --- a/dipy/tracking/tests/test_utils.py +++ b/dipy/tracking/tests/test_utils.py @@ -4,10 +4,9 @@ import numpy as np from dipy.io.bvectxt import orientation_from_string -from dipy.tracking.utils import (connectivity_matrix, - density_map, length, move_streamlines, - ndbincount, reduce_labels, - reorder_voxels_affine, seeds_from_mask, +from dipy.tracking.streamline import transform_streamlines +from dipy.tracking.utils import (connectivity_matrix, density_map, length, + ndbincount, reduce_labels, seeds_from_mask, random_seeds_from_mask, target, target_line_based, unique_rows, near_roi, reduce_rois, path_length, _min_at) @@ -242,7 +241,7 @@ def _target(target_f, streamlines, voxel_both_true, voxel_one_true, [0, .2, 0, 0], [0, 0, .4, 0], [0, 0, 0, 1]]) - streamlines = list(move_streamlines(streamlines, affine)) + streamlines = list(transform_streamlines(streamlines, affine)) new = list(target_f(streamlines, affine, mask)) npt.assert_equal(len(new), 1) assert_true(new[0] is streamlines[0]) @@ -273,17 +272,17 @@ def test_near_roi(): np.array([[2, 2, 2], [3, 3, 3]])] - affine = np.eye(4) mask = np.zeros((4, 4, 4), dtype=bool) mask[0, 0, 0] = True mask[1, 0, 0] = True - npt.assert_array_equal(near_roi(streamlines, affine, mask, tol=1), + npt.assert_array_equal(near_roi(streamlines, np.eye(4), mask, tol=1), np.array([True, True, False])) - npt.assert_array_equal(near_roi(streamlines, affine, mask), + npt.assert_array_equal(near_roi(streamlines, np.eye(4), mask), np.array([False, True, False])) # If there is an affine, we need to use it: + affine = np.eye(4) affine[:, 3] = [-1, 100, -20, 1] # Transform the streamlines: x_streamlines = [sl + affine[:3, 3] for sl in streamlines] @@ -304,8 +303,7 @@ def test_near_roi(): # to a very small number gets overridden: with warnings.catch_warnings(): warnings.simplefilter("ignore") - npt.assert_array_equal(near_roi(x_streamlines, affine, - mask, + npt.assert_array_equal(near_roi(x_streamlines, affine, mask, tol=0.1, mode='all'), np.array([False, True, False])) @@ -321,17 +319,17 @@ def test_near_roi(): mask[0, 1, 1] = True mask[3, 2, 2] = True - npt.assert_array_equal(near_roi(streamlines, affine, mask, tol=0.87, + npt.assert_array_equal(near_roi(streamlines, np.eye(4), mask, tol=0.87, mode="either_end"), np.array([True, False, False])) - npt.assert_array_equal(near_roi(streamlines, affine, mask, tol=0.87, + npt.assert_array_equal(near_roi(streamlines, np.eye(4), mask, tol=0.87, mode="both_end"), np.array([False, False, False])) mask[0, 0, 0] = True mask[0, 2, 2] = True - npt.assert_array_equal(near_roi(streamlines, affine, mask, mode="both_end"), + npt.assert_array_equal(near_roi(streamlines, np.eye(4), mask, mode="both_end"), np.array([False, True, False])) # Test with a generator input: @@ -339,61 +337,11 @@ def generate_sl(streamlines): for sl in streamlines: yield sl - npt.assert_array_equal(near_roi(generate_sl(streamlines), affine, + npt.assert_array_equal(near_roi(generate_sl(streamlines), np.eye(4), mask, mode="both_end"), np.array([False, True, False])) -def test_voxel_ornt(): - sh = (40, 40, 40) - sz = (1, 2, 3) - I4 = np.eye(4) - - ras = orientation_from_string('ras') - sra = orientation_from_string('sra') - lpi = orientation_from_string('lpi') - srp = orientation_from_string('srp') - - affine = reorder_voxels_affine(ras, ras, sh, sz) - npt.assert_array_equal(affine, I4) - affine = reorder_voxels_affine(sra, sra, sh, sz) - npt.assert_array_equal(affine, I4) - affine = reorder_voxels_affine(lpi, lpi, sh, sz) - npt.assert_array_equal(affine, I4) - affine = reorder_voxels_affine(srp, srp, sh, sz) - npt.assert_array_equal(affine, I4) - - streamlines = make_streamlines() - box = np.array(sh) * sz - - sra_affine = reorder_voxels_affine(ras, sra, sh, sz) - toras_affine = reorder_voxels_affine(sra, ras, sh, sz) - npt.assert_array_equal(np.dot(toras_affine, sra_affine), I4) - expected_sl = (sl[:, [2, 0, 1]] for sl in streamlines) - test_sl = move_streamlines(streamlines, sra_affine) - for _ in range(len(streamlines)): - npt.assert_array_equal(next(test_sl), next(expected_sl)) - - lpi_affine = reorder_voxels_affine(ras, lpi, sh, sz) - toras_affine = reorder_voxels_affine(lpi, ras, sh, sz) - npt.assert_array_equal(np.dot(toras_affine, lpi_affine), I4) - expected_sl = (box - sl for sl in streamlines) - test_sl = move_streamlines(streamlines, lpi_affine) - for _ in range(len(streamlines)): - npt.assert_array_equal(next(test_sl), next(expected_sl)) - - srp_affine = reorder_voxels_affine(ras, srp, sh, sz) - toras_affine = reorder_voxels_affine(srp, ras, (40, 40, 40), (3, 1, 2)) - npt.assert_array_equal(np.dot(toras_affine, srp_affine), I4) - expected_sl = [sl.copy() for sl in streamlines] - for sl in expected_sl: - sl[:, 1] = box[1] - sl[:, 1] - expected_sl = (sl[:, [2, 0, 1]] for sl in expected_sl) - test_sl = move_streamlines(streamlines, srp_affine) - for _ in range(len(streamlines)): - npt.assert_array_equal(next(test_sl), next(expected_sl)) - - def test_streamline_mapping(): streamlines = [np.array([[0, 0, 0], [0, 0, 0], [0, 2, 2]], 'float'), np.array([[0, 0, 0], [0, 1, 1], [0, 2, 2]], 'float'), diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index fbd40c5e51..7b9046c1c4 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -71,7 +71,7 @@ import nibabel as nib -def density_map(streamlines, vol_dims, affine): +def density_map(streamlines, affine, vol_dims): """Counts the number of unique streamlines that pass through each voxel. Parameters @@ -395,7 +395,7 @@ def seeds_from_mask(mask, affine, density=[1, 1, 1]): seeds = seeds.reshape((-1, 3)) # Apply the spatial transform - if seeds is not None: + if seeds.any(): # Use affine to move seeds into real world coordinates seeds = np.dot(seeds, affine[:3, :3].T) seeds += affine[:3, 3] @@ -506,7 +506,7 @@ def random_seeds_from_mask(mask, affine, seeds_count=1, seeds = seeds[:seeds_count] # Apply the spatial transform - if seeds is not None: + if seeds.any(): # Use affine to move seeds into real world coordinates seeds = np.dot(seeds, affine[:3, :3].T) seeds += affine[:3, 3] @@ -816,17 +816,13 @@ def transform_tracking_output(tracking_output, affine, seeding_activated=False): """Applies a linear transformation, given by affine, to streamlines. Parameters ---------- - streamlines : sequence - A set of streamlines to be transformed. + streamlines : Streamlines generator + Either streamlines (list, ArraySequence) or a tuple with streamlines + and seeds together affine : array (4, 4) The mapping between voxel indices and the point space for seeds. The voxel_to_rasmm matrix, typically from a NIFTI file. - input_space : array (4, 4), optional - An affine matrix describing the current space of the streamlines, if no - ``input_space`` is specified, it's assumed the streamlines are in the - reference space. The reference space is the same as the space - associated with the affine matrix ``np.eye(4)``. - seeds : np.array, optional + seeding_activated : bool, optional If set, seeds associated to streamlines will be also moved and returned Returns ------- @@ -838,6 +834,7 @@ def transform_tracking_output(tracking_output, affine, seeding_activated=False): streamlines, seeds = zip(*tracking_output) else: streamlines = tracking_output + seeds = None lin_T = affine[:3, :3].T.copy() offset = affine[:3, 3].copy() From 6fd641aa3bb37cf9f1fb16dd05ba1a93020917f9 Mon Sep 17 00:00:00 2001 From: frheault Date: Mon, 29 Jul 2019 18:29:54 -0400 Subject: [PATCH 06/13] Flake8 on everything changed --- dipy/tracking/local/localtracking.py | 2 +- dipy/tracking/streamline.py | 3 +-- dipy/tracking/tests/test_life.py | 3 +-- dipy/tracking/tests/test_streamline.py | 4 +--- dipy/tracking/tests/test_utils.py | 24 ++++++++++------------- dipy/tracking/utils.py | 24 +++++++++-------------- dipy/workflows/tracking.py | 5 ++--- doc/examples/afq_tract_profiles.py | 2 +- doc/examples/bundle_extraction.py | 2 +- doc/examples/fiber_to_bundle_coherence.py | 7 +++++-- doc/examples/path_length_map.py | 6 +++--- doc/examples/streamline_formats.py | 16 +++++++-------- doc/examples/tracking_sfm.py | 7 +++---- 13 files changed, 46 insertions(+), 59 deletions(-) diff --git a/dipy/tracking/local/localtracking.py b/dipy/tracking/local/localtracking.py index 5c6a3b2dd3..9901d07ce6 100644 --- a/dipy/tracking/local/localtracking.py +++ b/dipy/tracking/local/localtracking.py @@ -113,7 +113,7 @@ def __iter__(self): track = self._generate_streamlines() return utils.transform_tracking_output(track, self.affine, - seeding_activated=self.save_seeds) + seeding_activated=self.save_seeds) def _generate_streamlines(self): """A streamline generator""" diff --git a/dipy/tracking/streamline.py b/dipy/tracking/streamline.py index af024346e2..8aace2b114 100644 --- a/dipy/tracking/streamline.py +++ b/dipy/tracking/streamline.py @@ -7,8 +7,7 @@ import numpy as np from nibabel.affines import apply_affine from nibabel.streamlines import ArraySequence as Streamlines -from dipy.tracking.streamlinespeed import (set_number_of_points, length, - compress_streamlines) +from dipy.tracking.streamlinespeed import set_number_of_points, length from dipy.tracking.distances import bundles_distances_mdf import dipy.tracking.utils as ut from dipy.core.geometry import dist_to_corner diff --git a/dipy/tracking/tests/test_life.py b/dipy/tracking/tests/test_life.py index 0572d8f2b9..566bd24110 100644 --- a/dipy/tracking/tests/test_life.py +++ b/dipy/tracking/tests/test_life.py @@ -6,7 +6,6 @@ from dipy.io.gradients import read_bvals_bvecs from dipy.io.stateful_tractogram import Space, StatefulTractogram import dipy.tracking.life as life -from dipy.tracking.streamline import transform_streamlines import nibabel as nib import numpy as np import numpy.testing as npt @@ -165,7 +164,7 @@ def test_fit_data(): sft = StatefulTractogram(tensor_streamlines, ni_data, Space.RASMM) sft.to_vox() tensor_streamlines_vox = sft.streamlines - + life_model = life.FiberModel(gtab) life_fit = life_model.fit(data, tensor_streamlines_vox) model_error = life_fit.predict() - life_fit.data diff --git a/dipy/tracking/tests/test_streamline.py b/dipy/tracking/tests/test_streamline.py index 4fa59229e7..3746f15452 100644 --- a/dipy/tracking/tests/test_streamline.py +++ b/dipy/tracking/tests/test_streamline.py @@ -11,7 +11,7 @@ from dipy.testing import assert_true from numpy.testing import (assert_array_equal, assert_array_almost_equal, - assert_raises, run_module_suite, assert_allclose, + assert_raises, assert_allclose, assert_almost_equal, assert_equal) from dipy.tracking.streamline import Streamlines @@ -353,7 +353,6 @@ def test_set_number_of_points_memory_leaks(): streamlines.append(rng.randn(rng.randint(10, 100), 3).astype(dtype)) list_refcount_before = get_type_refcount()["list"] - rstreamlines = set_number_of_points(streamlines, nb_points=2) list_refcount_after = get_type_refcount()["list"] # Calling `set_number_of_points` should increase the refcount of `list` @@ -759,7 +758,6 @@ def test_compress_streamlines_memory_leaks(): streamlines.append(rng.randn(rng.randint(10, 100), 3).astype(dtype)) list_refcount_before = get_type_refcount()["list"] - cstreamlines = compress_streamlines(streamlines) list_refcount_after = get_type_refcount()["list"] # Calling `compress_streamlines` should increase the refcount of `list` by diff --git a/dipy/tracking/tests/test_utils.py b/dipy/tracking/tests/test_utils.py index 56afa2a6e7..3e02e20a44 100644 --- a/dipy/tracking/tests/test_utils.py +++ b/dipy/tracking/tests/test_utils.py @@ -1,9 +1,7 @@ -from __future__ import division, print_function, absolute_import - import warnings import numpy as np -from dipy.io.bvectxt import orientation_from_string +from dipy.tracking import metrics from dipy.tracking.streamline import transform_streamlines from dipy.tracking.utils import (connectivity_matrix, density_map, length, ndbincount, reduce_labels, seeds_from_mask, @@ -12,9 +10,6 @@ reduce_rois, path_length, _min_at) from dipy.tracking._utils import _to_voxel_coordinates - -import dipy.tracking.metrics as metrix - from dipy.tracking.vox2track import streamline_mapping import numpy.testing as npt from dipy.testing import assert_true @@ -329,7 +324,8 @@ def test_near_roi(): mask[0, 0, 0] = True mask[0, 2, 2] = True - npt.assert_array_equal(near_roi(streamlines, np.eye(4), mask, mode="both_end"), + npt.assert_array_equal(near_roi(streamlines, np.eye(4), mask, + mode="both_end"), np.array([False, True, False])) # Test with a generator input: @@ -393,7 +389,7 @@ def test_length(): bundle_lengths = length(bundle) for idx, this_length in enumerate(bundle_lengths): - npt.assert_equal(this_length, metrix.length(bundle[idx])) + npt.assert_equal(this_length, metrics.length(bundle[idx])) def test_seeds_from_mask(): @@ -420,35 +416,35 @@ def test_seeds_from_mask(): def test_random_seeds_from_mask(): mask = np.random.randint(0, 1, size=(4, 6, 3)) - seeds = random_seeds_from_mask(mask, np.eye(4), + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=24, seed_count_per_voxel=True) npt.assert_equal(mask.sum() * 24, len(seeds)) - seeds = random_seeds_from_mask(mask, np.eye(4), + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=0, seed_count_per_voxel=True) npt.assert_equal(0, len(seeds)) mask[:] = False mask[2, 2, 2] = True - seeds = random_seeds_from_mask(mask, np.eye(4), + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=8, seed_count_per_voxel=True) npt.assert_equal(mask.sum() * 8, len(seeds)) assert_true(np.all((seeds > 1.5) & (seeds < 2.5))) - seeds = random_seeds_from_mask(mask, np.eye(4), + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=24, seed_count_per_voxel=False) npt.assert_equal(24, len(seeds)) - seeds = random_seeds_from_mask(mask, np.eye(4), + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=0, seed_count_per_voxel=False) npt.assert_equal(0, len(seeds)) mask[:] = False mask[2, 2, 2] = True - seeds = random_seeds_from_mask(mask, np.eye(4), + seeds = random_seeds_from_mask(mask, np.eye(4), seeds_count=100, seed_count_per_voxel=False) npt.assert_equal(100, len(seeds)) diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index b20fe6486f..714cdc2874 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -60,15 +60,12 @@ from collections import defaultdict import numpy as np -from numpy import (asarray, ceil, dot, empty, eye, sqrt) -from dipy.io.bvectxt import ornt_mapping +from numpy import (asarray, ceil, empty, sqrt) from dipy.tracking import metrics from dipy.tracking.vox2track import _streamlines_in_mask # Import helper functions shared with vox2track from dipy.tracking._utils import (_mapping_to_voxel, _to_voxel_coordinates) -from dipy.io.bvectxt import orientation_from_string -import nibabel as nib def density_map(streamlines, affine, vol_dims): @@ -103,9 +100,6 @@ def density_map(streamlines, affine, vol_dims): the edges of the voxels are smaller than the steps of the streamlines. """ - if affine is None: - affine = np.eye(4) - lin_T, offset = _mapping_to_voxel(affine) counts = np.zeros(vol_dims, 'int') for sl in streamlines: @@ -336,8 +330,8 @@ def seeds_from_mask(mask, affine, density=[1, 1, 1]): affine : array, (4, 4) The mapping between voxel indices and the point space for seeds. The voxel_to_rasmm matrix, typically from a NIFTI file. - A seed point at the center the voxel ``[i, j, k]`` - will be represented as ``[x, y, z]`` where + A seed point at the center the voxel ``[i, j, k]`` + will be represented as ``[x, y, z]`` where ``[x, y, z, 1] == np.dot(affine, [i, j, k , 1])``. density : int or array_like (3,) Specifies the number of seeds to place along each dimension. A @@ -424,8 +418,8 @@ def random_seeds_from_mask(mask, affine, seeds_count=1, affine : array, (4, 4) The mapping between voxel indices and the point space for seeds. The voxel_to_rasmm matrix, typically from a NIFTI file. - A seed point at the center the voxel ``[i, j, k]`` - will be represented as ``[x, y, z]`` where + A seed point at the center the voxel ``[i, j, k]`` + will be represented as ``[x, y, z]`` where ``[x, y, z, 1] == np.dot(affine, [i, j, k , 1])``. seeds_count : int The number of seeds to generate. If ``seed_count_per_voxel`` is True, @@ -450,10 +444,10 @@ def random_seeds_from_mask(mask, affine, seeds_count=1, -------- >>> mask = np.zeros((3,3,3), 'bool') >>> mask[0,0,0] = 1 - >>> random_seeds_from_mask(mask, np.eye(4), seeds_count=1, + >>> random_seeds_from_mask(mask, np.eye(4), seeds_count=1, ... seed_count_per_voxel=True, random_seed=1) array([[-0.0640051 , -0.47407377, 0.04966248]]) - >>> random_seeds_from_mask(mask, np.eye(4), seeds_count=6, + >>> random_seeds_from_mask(mask, np.eye(4), seeds_count=6, ... seed_count_per_voxel=True, random_seed=1) array([[-0.0640051 , -0.47407377, 0.04966248], [ 0.0507979 , 0.20814782, -0.20909526], @@ -462,7 +456,7 @@ def random_seeds_from_mask(mask, affine, seeds_count=1, [ 0.39286015, -0.16802019, 0.32122912], [-0.42369171, 0.27991879, -0.06159077]]) >>> mask[0,1,2] = 1 - >>> random_seeds_from_mask(mask, np.eye(4), + >>> random_seeds_from_mask(mask, np.eye(4), ... seeds_count=2, seed_count_per_voxel=True, random_seed=1) array([[-0.0640051 , -0.47407377, 0.04966248], [-0.27800683, 1.37073231, 1.70671916], @@ -564,7 +558,6 @@ def target(streamlines, affine, target_mask, include=True): See Also -------- density_map - """ target_mask = np.array(target_mask, dtype=bool, copy=True) lin_T, offset = _mapping_to_voxel(affine) @@ -851,6 +844,7 @@ def transform_tracking_output(tracking_output, affine, seeding_activated=False): for sl in streamlines: yield np.dot(sl, lin_T) + offset + def reduce_rois(rois, include): """Reduce multiple ROIs to one inclusion and one exclusion ROI. diff --git a/dipy/workflows/tracking.py b/dipy/workflows/tracking.py index af8670b2ea..1dd0392bd3 100644 --- a/dipy/workflows/tracking.py +++ b/dipy/workflows/tracking.py @@ -2,7 +2,6 @@ from __future__ import division import logging -import numpy as np from dipy.direction import (DeterministicMaximumDirectionGetter, ProbabilisticDirectionGetter, @@ -112,7 +111,7 @@ def _core_run(self, stopping_path, use_binary_mask, stopping_thr, seeds = {} sft = StatefulTractogram(streamlines, seeding_path, Space.RASMM, - data_per_streamline=seeds) + data_per_streamline=seeds) save_tractogram(sft, out_tract, bbox_valid_check=False) logging.info('Saved {0}'.format(out_tract)) @@ -325,6 +324,6 @@ def run(self, pam_files, wm_files, gm_files, csf_files, seeding_files, seeds = {} sft = StatefulTractogram(streamlines, seeding_path, Space.RASMM, - data_per_streamline=seeds) + data_per_streamline=seeds) save_tractogram(sft, out_tract, bbox_valid_check=False) logging.info('Saved {0}'.format(out_tract)) diff --git a/doc/examples/afq_tract_profiles.py b/doc/examples/afq_tract_profiles.py index 32854ab6dd..cab0d9c560 100644 --- a/doc/examples/afq_tract_profiles.py +++ b/doc/examples/afq_tract_profiles.py @@ -112,7 +112,7 @@ """ Read volumetric data from an image corresponding to this subject. -For the purpose of this, we've extracted only the FA within the bundles in +For the purpose of this, we've extracted only the FA within the bundles in question, but in real use, this is where you would add the FA map of your subject. """ diff --git a/doc/examples/bundle_extraction.py b/doc/examples/bundle_extraction.py index 1c159d2dd1..e899de7930 100644 --- a/doc/examples/bundle_extraction.py +++ b/doc/examples/bundle_extraction.py @@ -212,7 +212,7 @@ """ reco_cst_l = StatefulTractogram(target[cst_l_labels], target_header, Space.RASMM) -save_trk(reco_af_l, "CST_L.trk", bbox_valid_check=False) +save_trk(reco_cst_l, "CST_L.trk", bbox_valid_check=False) """ diff --git a/doc/examples/fiber_to_bundle_coherence.py b/doc/examples/fiber_to_bundle_coherence.py index b5a3b22b2b..38ed853f91 100644 --- a/doc/examples/fiber_to_bundle_coherence.py +++ b/doc/examples/fiber_to_bundle_coherence.py @@ -140,7 +140,8 @@ # Perform tracking using Local Tracking from dipy.tracking.local import LocalTracking -streamlines_generator = LocalTracking(prob_dg, classifier, seeds, affine, step_size=.5) +streamlines_generator = LocalTracking(prob_dg, classifier, seeds, affine, + step_size=.5) # Compute streamlines. from dipy.tracking.streamline import Streamlines @@ -242,7 +243,9 @@ ren.add(vol_actor2) # Show original fibers -ren.set_camera(position=(-264, 285, 155), focal_point=(0, -14, 9), view_up=(0, 0, 1)) +ren.set_camera(position=(-264, 285, 155), + focal_point=(0, -14, 9), + view_up=(0, 0, 1)) window.record(ren, n_frames=1, out_path='OR_before.png', size=(900, 900)) if interactive: window.show(ren) diff --git a/doc/examples/path_length_map.py b/doc/examples/path_length_map.py index bfb5289fdf..0f610af615 100644 --- a/doc/examples/path_length_map.py +++ b/doc/examples/path_length_map.py @@ -32,9 +32,9 @@ """ First, we need to generate some streamlines and visualize. For a more complete -description of these steps, please refer to the :ref:`example_probabilistic_fiber_tracking` -and the Visualization of ROI Surface Rendered with Streamlines Tutorials. - +description of these steps, please refer to the +:ref:`example_probabilistic_fiber_tracking` and the Visualization of ROI +Surface Rendered with Streamlines Tutorials. """ hardi_img, gtab, labels_img = read_stanford_labels() diff --git a/doc/examples/streamline_formats.py b/doc/examples/streamline_formats.py index a7321a897a..c6977f7d41 100644 --- a/doc/examples/streamline_formats.py +++ b/doc/examples/streamline_formats.py @@ -120,7 +120,7 @@ """ Once loaded, no matter the original file format, the stateful tractogram is -self-contained and maintains a valid state. By requiring a reference the +self-contained and maintains a valid state. By requiring a reference the tractogram's spatial transformation can be easily manipulated. Let's save all files as TRK to visualize in TrackVis for example. @@ -149,8 +149,8 @@ These functions can be called safely over and over, by knowing in which state the tractogram is operating, and compute only necessary transformations -No matter the state, functions such as ``save_tractogram`` or -``removing_invalid_coordinates`` can be called safely and the transformations +No matter the state, functions such as ``save_tractogram`` or +``removing_invalid_coordinates`` can be called safely and the transformations are handled internally when needed. """ @@ -184,11 +184,11 @@ # Same dimensions for every stateful tractogram, can be re-use affine, dimensions, voxel_sizes, voxel_order = cc_sft.space_attribute -cc_density = density_map(cc_streamlines_vox, dimensions) -laf_density = density_map(laf_streamlines_vox, dimensions) -raf_density = density_map(raf_streamlines_vox, dimensions) -lpt_density = density_map(lpt_streamlines_vox, dimensions) -rpt_density = density_map(rpt_streamlines_vox, dimensions) +cc_density = density_map(cc_streamlines_vox, np.eye(4), dimensions) +laf_density = density_map(laf_streamlines_vox, np.eye(4), dimensions) +raf_density = density_map(raf_streamlines_vox, np.eye(4), dimensions) +lpt_density = density_map(lpt_streamlines_vox, np.eye(4), dimensions) +rpt_density = density_map(rpt_streamlines_vox, np.eye(4), dimensions) """ Replacing streamlines is possible, but if the state was modified between diff --git a/doc/examples/tracking_sfm.py b/doc/examples/tracking_sfm.py index 9cee9a1d04..679525d123 100644 --- a/doc/examples/tracking_sfm.py +++ b/doc/examples/tracking_sfm.py @@ -13,9 +13,9 @@ # Enables/disables interactive visualization from dipy.io.streamline import save_trk from dipy.io.stateful_tractogram import Space, StatefulTractogram -from dipy.tracking.streamline import select_random_set_of_streamlines +from dipy.tracking.streamline import (select_random_set_of_streamlines, + transform_streamlines) from numpy.linalg import inv -from dipy.tracking.utils import move_streamlines from dipy.data import read_stanford_t1 from dipy.viz import window, actor, colormap, has_fury from dipy.tracking.streamline import Streamlines @@ -92,7 +92,6 @@ matter: """ -from dipy.tracking import utils seeds = utils.seeds_from_mask(white_matter, affine, density=[2, 2, 2]) """ @@ -133,7 +132,7 @@ if has_fury: streamlines_actor = actor.streamtube( - list(move_streamlines(plot_streamlines, inv(t1_aff))), + list(transform_streamlines(plot_streamlines, inv(t1_aff))), colormap.line_colors(streamlines), linewidth=0.1) vol_actor = actor.slicer(t1_data) From 2b8dc6d704dd80da1316b70882d4e11a3ff2cca5 Mon Sep 17 00:00:00 2001 From: frheault Date: Mon, 29 Jul 2019 18:58:50 -0400 Subject: [PATCH 07/13] Fixed invalid reference in tracking workflow --- dipy/workflows/tests/test_tracking.py | 4 +--- dipy/workflows/tracking.py | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/dipy/workflows/tests/test_tracking.py b/dipy/workflows/tests/test_tracking.py index 934e5a2dda..6b3626610b 100644 --- a/dipy/workflows/tests/test_tracking.py +++ b/dipy/workflows/tests/test_tracking.py @@ -131,10 +131,8 @@ def test_local_fiber_tracking_workflow(): seeds_path = mask_flow.last_generated_outputs['out_mask'] mask_path = mask_flow.last_generated_outputs['out_mask'] - # Put identity in gfa path to prevent impossible to use - # local tracking because of affine containing shearing. gfa_img = nib.load(gfa_path) - save_nifti(gfa_path, gfa_img.get_data(), np.eye(4), gfa_img.header) + save_nifti(gfa_path, gfa_img.get_data(), vol_img.affine, gfa_img.header) # Test tracking with pam no sh lf_track_pam = LocalFiberTrackingPAMFlow() diff --git a/dipy/workflows/tracking.py b/dipy/workflows/tracking.py index 1dd0392bd3..2ea60e7333 100644 --- a/dipy/workflows/tracking.py +++ b/dipy/workflows/tracking.py @@ -110,7 +110,7 @@ def _core_run(self, stopping_path, use_binary_mask, stopping_thr, streamlines = list(tracking_result) seeds = {} - sft = StatefulTractogram(streamlines, seeding_path, Space.RASMM, + sft = StatefulTractogram(streamlines, stopping_path, Space.RASMM, data_per_streamline=seeds) save_tractogram(sft, out_tract, bbox_valid_check=False) logging.info('Saved {0}'.format(out_tract)) @@ -323,7 +323,7 @@ def run(self, pam_files, wm_files, gm_files, csf_files, seeding_files, streamlines = list(tracking_result) seeds = {} - sft = StatefulTractogram(streamlines, seeding_path, Space.RASMM, + sft = StatefulTractogram(streamlines, wm_path, Space.RASMM, data_per_streamline=seeds) save_tractogram(sft, out_tract, bbox_valid_check=False) logging.info('Saved {0}'.format(out_tract)) From 2706051301210a2a1c541ab9022de98cc56252ae Mon Sep 17 00:00:00 2001 From: frheault Date: Tue, 30 Jul 2019 08:39:37 -0400 Subject: [PATCH 08/13] Updated the api_changes --- dipy/tracking/streamline.py | 3 ++- doc/api_changes.rst | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dipy/tracking/streamline.py b/dipy/tracking/streamline.py index 8aace2b114..33d85b43c4 100644 --- a/dipy/tracking/streamline.py +++ b/dipy/tracking/streamline.py @@ -7,7 +7,8 @@ import numpy as np from nibabel.affines import apply_affine from nibabel.streamlines import ArraySequence as Streamlines -from dipy.tracking.streamlinespeed import set_number_of_points, length +from dipy.tracking.streamlinespeed import (compress_streamlines, length, + set_number_of_points) from dipy.tracking.distances import bundles_distances_mdf import dipy.tracking.utils as ut from dipy.core.geometry import dist_to_corner diff --git a/doc/api_changes.rst b/doc/api_changes.rst index aabc224966..d4d1618505 100644 --- a/doc/api_changes.rst +++ b/doc/api_changes.rst @@ -32,6 +32,16 @@ The API of ``dipy.io.streamlines.load_tractogram`` and When loading trk, tck, vtk, fib, or dpy) a reference nifti file is needed to guarantee proper spatial transformation handling. +**Spatial transformation handling** + +Functions from ``dipy.tracking.utils`` were modified to enforce the +affine parameter and uniformize docstring. ``density_map`` +``connectivity_matrix``, ``seeds_from_mask``, ``random_seeds_from_mask``, +``target``, ``target_line_based``, ``near_roi``, ``length`` and +``path_length`` were all modified. +The function ``affine_for_trackvis``, ``move_streamlines``, +``flexi_tvis_affine`` and ``get_flexi_tvis_affine`` were deleted. + **Simulation** - ``dipy.sims.voxel.SingleTensor`` has been replaced by ``dipy.sims.voxel.single_tensor`` From 1ebc15f6f6f5b040f13c2b95f968377a1a759d97 Mon Sep 17 00:00:00 2001 From: frheault Date: Tue, 30 Jul 2019 09:34:26 -0400 Subject: [PATCH 09/13] Correct typo in docstring, fix example in seeds_from_masks --- dipy/tracking/utils.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index 714cdc2874..424487a641 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -318,7 +318,7 @@ def subsegment(streamlines, max_segment_length): def seeds_from_mask(mask, affine, density=[1, 1, 1]): - """Creates seeds for fiber tracking from a binary mask. + """Create seeds for fiber tracking from a binary mask. Seeds points are placed evenly distributed in all voxels of ``mask`` which are ``True``. @@ -351,21 +351,8 @@ def seeds_from_mask(mask, affine, density=[1, 1, 1]): -------- >>> mask = np.zeros((3,3,3), 'bool') >>> mask[0,0,0] = 1 - >>> seeds_from_mask(mask, np.eye(4), [1,1,1], [1,1,1]) - array([[ 0.5, 0.5, 0.5]]) - >>> seeds_from_mask(mask, np.eye(4), [1,2,3], [1,1,1]) - array([[ 0.5 , 0.25 , 0.16666667], - [ 0.5 , 0.75 , 0.16666667], - [ 0.5 , 0.25 , 0.5 ], - [ 0.5 , 0.75 , 0.5 ], - [ 0.5 , 0.25 , 0.83333333], - [ 0.5 , 0.75 , 0.83333333]]) - >>> mask[0,1,2] = 1 - >>> seeds_from_mask(mask, np.eye(4), [1,1,2]]) - array([[ 0.55 , 0.55 , 0.625], - [ 0.55 , 0.55 , 1.875], - [ 0.55 , 1.65 , 5.625], - [ 0.55 , 1.65 , 6.875]]) + >>> seeds_from_mask(mask, np.eye(4), [1,1,1]) + array([[ 0.0, 0.0, 0.0]]) """ mask = np.array(mask, dtype=bool, copy=False, ndmin=3) if mask.ndim != 3: @@ -402,7 +389,7 @@ def seeds_from_mask(mask, affine, density=[1, 1, 1]): def random_seeds_from_mask(mask, affine, seeds_count=1, seed_count_per_voxel=True, random_seed=None): - """Creates randomly placed seeds for fiber tracking from a binary mask. + """Create randomly placed seeds for fiber tracking from a binary mask. Seeds points are placed randomly distributed in voxels of ``mask`` which are ``True``. From 639d922eeeadd4fdee41afb5a797bb3ebf8d28ee Mon Sep 17 00:00:00 2001 From: frheault Date: Tue, 30 Jul 2019 10:12:48 -0400 Subject: [PATCH 10/13] Reduce line length --- dipy/tracking/local/localtracking.py | 2 +- dipy/tracking/utils.py | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/dipy/tracking/local/localtracking.py b/dipy/tracking/local/localtracking.py index 9901d07ce6..e69b6d5146 100644 --- a/dipy/tracking/local/localtracking.py +++ b/dipy/tracking/local/localtracking.py @@ -113,7 +113,7 @@ def __iter__(self): track = self._generate_streamlines() return utils.transform_tracking_output(track, self.affine, - seeding_activated=self.save_seeds) + save_seeds=self.save_seeds) def _generate_streamlines(self): """A streamline generator""" diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index 424487a641..3add718be6 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -737,12 +737,6 @@ def near_roi(streamlines, affine, region_of_interest, tol=None, return(np.array(out, dtype=bool)) -# reorder_voxels_affine - - -# affine_from_fsl_mat_file - - def length(streamlines): """ Calculate the lengths of many streamlines in a bundle. @@ -795,7 +789,7 @@ def unique_rows(in_array, dtype='f4'): @_with_initialize -def transform_tracking_output(tracking_output, affine, seeding_activated=False): +def transform_tracking_output(tracking_output, affine, save_seeds=False): """Applies a linear transformation, given by affine, to streamlines. Parameters ---------- @@ -813,7 +807,7 @@ def transform_tracking_output(tracking_output, affine, seeding_activated=False): A sequence of transformed streamlines. If return_seeds is True, also return seeds """ - if seeding_activated: + if save_seeds: streamlines, seeds = zip(*tracking_output) else: streamlines = tracking_output From 80c00ec783cd5b2df607fa56ed19ed2777f533fc Mon Sep 17 00:00:00 2001 From: frheault Date: Tue, 30 Jul 2019 12:56:29 -0400 Subject: [PATCH 11/13] Added back unsused variable in test, apparently necessary --- dipy/tracking/tests/test_streamline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dipy/tracking/tests/test_streamline.py b/dipy/tracking/tests/test_streamline.py index 3746f15452..6b0c5cc7b5 100644 --- a/dipy/tracking/tests/test_streamline.py +++ b/dipy/tracking/tests/test_streamline.py @@ -353,6 +353,7 @@ def test_set_number_of_points_memory_leaks(): streamlines.append(rng.randn(rng.randint(10, 100), 3).astype(dtype)) list_refcount_before = get_type_refcount()["list"] + rstreamlines = set_number_of_points(streamlines, nb_points=2) list_refcount_after = get_type_refcount()["list"] # Calling `set_number_of_points` should increase the refcount of `list` @@ -758,6 +759,7 @@ def test_compress_streamlines_memory_leaks(): streamlines.append(rng.randn(rng.randint(10, 100), 3).astype(dtype)) list_refcount_before = get_type_refcount()["list"] + cstreamlines = compress_streamlines(streamlines) list_refcount_after = get_type_refcount()["list"] # Calling `compress_streamlines` should increase the refcount of `list` by From 6f846fbfeea9eaef28c32b604b63af2adb3ee519 Mon Sep 17 00:00:00 2001 From: frheault Date: Tue, 30 Jul 2019 16:20:20 -0400 Subject: [PATCH 12/13] Fixed doctest error --- dipy/tracking/tests/test_streamline.py | 2 +- dipy/tracking/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dipy/tracking/tests/test_streamline.py b/dipy/tracking/tests/test_streamline.py index 6b0c5cc7b5..26b4435429 100644 --- a/dipy/tracking/tests/test_streamline.py +++ b/dipy/tracking/tests/test_streamline.py @@ -1117,7 +1117,7 @@ def test_values_from_volume(): # The generator has already been consumed so needs to be # regenerated: - x_sl1 = list(transform_streamlines(sl1, affine)) + x_sl1 = transform_streamlines(sl1, affine) vv = values_from_volume(data, x_sl1, affine=affine) npt.assert_almost_equal(vv, ans1, decimal=decimal) diff --git a/dipy/tracking/utils.py b/dipy/tracking/utils.py index 3add718be6..eb5b66a07c 100644 --- a/dipy/tracking/utils.py +++ b/dipy/tracking/utils.py @@ -352,7 +352,7 @@ def seeds_from_mask(mask, affine, density=[1, 1, 1]): >>> mask = np.zeros((3,3,3), 'bool') >>> mask[0,0,0] = 1 >>> seeds_from_mask(mask, np.eye(4), [1,1,1]) - array([[ 0.0, 0.0, 0.0]]) + array([[ 0., 0., 0.]]) """ mask = np.array(mask, dtype=bool, copy=False, ndmin=3) if mask.ndim != 3: From 7ca62f552befcfba9691e69bf9b90d899277fbdb Mon Sep 17 00:00:00 2001 From: frheault Date: Wed, 31 Jul 2019 12:00:51 -0400 Subject: [PATCH 13/13] Remove cast for transform_streamlines --- dipy/tracking/tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dipy/tracking/tests/test_utils.py b/dipy/tracking/tests/test_utils.py index 3e02e20a44..a56ae100a1 100644 --- a/dipy/tracking/tests/test_utils.py +++ b/dipy/tracking/tests/test_utils.py @@ -236,7 +236,7 @@ def _target(target_f, streamlines, voxel_both_true, voxel_one_true, [0, .2, 0, 0], [0, 0, .4, 0], [0, 0, 0, 1]]) - streamlines = list(transform_streamlines(streamlines, affine)) + streamlines = transform_streamlines(streamlines, affine) new = list(target_f(streamlines, affine, mask)) npt.assert_equal(len(new), 1) assert_true(new[0] is streamlines[0])