def orient_by_streamline(streamlines, standard, n_points=12, in_place=False, as_generator=False, affine=None): """ Orient a bundle of streamlines to a standard streamline. Parameters ---------- streamlines : Streamlines, list The input streamlines to orient. standard : Streamlines, list, or ndarrray This provides the standard orientation according to which the streamlines in the provided bundle should be reoriented. n_points: int, optional The number of samples to apply to each of the streamlines. in_place : bool Whether to make the change in-place in the original input (and return a reference), or to make a copy of the list and return this copy, with the relevant streamlines reoriented. Default: False. as_generator : bool Whether to return a generator as output. Default: False affine : ndarray Affine transformation from voxels to streamlines. Default: identity. Returns ------- Streamlines : with each individual array oriented to be as similar as possible to the standard. """ # Start by resampling, so that distance calculation is easy: fgarray = set_number_of_points(streamlines, n_points) std_array = set_number_of_points([standard], n_points) if as_generator: if in_place: w_s = "Cannot return a generator when in_place is set to True" raise ValueError(w_s) return _orient_by_sl_generator(streamlines, std_array, fgarray) # If it's a generator on input, we may as well generate it # here and now: if isinstance(streamlines, types.GeneratorType): out = Streamlines(streamlines) elif in_place: out = streamlines else: # Make a copy, so you don't change the output in place: out = deepcopy(streamlines) return _orient_by_sl_list(out, std_array, fgarray)
def read_tracks(self): """ read the entire tractography """ I = self.offsets[:] TR = self.tracks[:] tracks = Streamlines() for i in range(len(I) - 1): off0, off1 = I[i:i + 2] tracks.append(TR[off0:off1]) return tracks
def values_from_volume(data, streamlines, affine=None): """Extract values of a scalar/vector along each streamline from a volume. Parameters ---------- data : 3D or 4D array Scalar (for 3D) and vector (for 4D) values to be extracted. For 4D data, interpolation will be done on the 3 spatial dimensions in each volume. streamlines : ndarray or list If array, of shape (n_streamlines, n_nodes, 3) If list, len(n_streamlines) with (n_nodes, 3) array in each element of the list. affine : ndarray, shape (4, 4) Affine transformation from voxels (image coordinates) to streamlines. Default: identity. For example, if no affine is provided and the first coordinate of the first streamline is ``[1, 0, 0]``, data[1, 0, 0] would be returned as the value for that streamline coordinate Return ------ array or list (depending on the input) : values interpolate to each coordinate along the length of each streamline. Notes ----- Values are extracted from the image based on the 3D coordinates of the nodes that comprise the points in the streamline, without any interpolation into segments between the nodes. Using this function with streamlines that have been resampled into a very small number of nodes will result in very few values. """ data = np.asarray(data) if len(data.shape) == 4: if data.shape[-1] == 3: return _extract_vals(data, streamlines, affine=affine, threedvec=True) if isinstance(streamlines, types.GeneratorType): streamlines = Streamlines(streamlines) vals = [] for ii in range(data.shape[-1]): vals.append( _extract_vals(data[..., ii], streamlines, affine=affine)) if isinstance(vals[-1], np.ndarray): return np.swapaxes(np.array(vals), 2, 1).T else: new_vals = [] for sl_idx in range(len(streamlines)): sl_vals = [] for ii in range(data.shape[-1]): sl_vals.append(vals[ii][sl_idx]) new_vals.append(np.array(sl_vals).T) return new_vals elif len(data.shape) == 3: return _extract_vals(data, streamlines, affine=affine) else: raise ValueError("Data needs to have 3 or 4 dimensions")
def orient_by_rois(streamlines, roi1, roi2, in_place=False, as_generator=False, affine=None): """Orient a set of streamlines according to a pair of ROIs Parameters ---------- streamlines : list or generator List or generator of 2d arrays of 3d coordinates. Each array contains the xyz coordinates of a single streamline. roi1, roi2 : ndarray Binary masks designating the location of the regions of interest, or coordinate arrays (n-by-3 array with ROI coordinate in each row). in_place : bool Whether to make the change in-place in the original list (and return a reference to the list), or to make a copy of the list and return this copy, with the relevant streamlines reoriented. Default: False. as_generator : bool Whether to return a generator as output. Default: False affine : ndarray Affine transformation from voxels to streamlines. Default: identity. Returns ------- streamlines : list or generator The same 3D arrays as a list or generator, but reoriented with respect to the ROIs Examples -------- >>> streamlines = [np.array([[0, 0., 0], ... [1, 0., 0.], ... [2, 0., 0.]]), ... np.array([[2, 0., 0.], ... [1, 0., 0], ... [0, 0, 0.]])] >>> roi1 = np.zeros((4, 4, 4), dtype=bool) >>> roi2 = np.zeros_like(roi1) >>> roi1[0, 0, 0] = True >>> roi2[1, 0, 0] = True >>> orient_by_rois(streamlines, roi1, roi2) [array([[ 0., 0., 0.], [ 1., 0., 0.], [ 2., 0., 0.]]), array([[ 0., 0., 0.], [ 1., 0., 0.], [ 2., 0., 0.]])] """ # If we don't already have coordinates on our hands: if len(roi1.shape) == 3: roi1 = np.asarray(np.where(roi1.astype(bool))).T if len(roi2.shape) == 3: roi2 = np.asarray(np.where(roi2.astype(bool))).T if affine is not None: roi1 = apply_affine(affine, roi1) roi2 = apply_affine(affine, roi2) if as_generator: if in_place: w_s = "Cannot return a generator when in_place is set to True" raise ValueError(w_s) return _orient_by_roi_generator(streamlines, roi1, roi2) # If it's a generator on input, we may as well generate it # here and now: if isinstance(streamlines, types.GeneratorType): out = Streamlines(streamlines) elif in_place: out = streamlines else: # Make a copy, so you don't change the output in place: out = deepcopy(streamlines) return _orient_by_roi_list(out, roi1, roi2)