Algorithms

Fragment Generation

class brainlit.algorithms.generate_fragments.state_generation(image_path: Union[str, Path], new_layers_dir: Union[str, Path], ilastik_program_path: str, ilastik_project_path: str, fg_channel: int = 0, chunk_size: List[float] = [375, 375, 125], soma_coords: List[list] = [], resolution: List[float] = [0.3, 0.3, 1], parallel: int = 1, prob_path: Union[str, Path] = None, fragment_path: Union[str, Path] = None, tiered_path: Union[str, Path] = None, states_path: Union[str, Path] = None)

This class encapsulates the processing that turns an image into a set of fragments with endpoints etc. needed to perform viterbrain tracing.

Parameters:
  • image_path (str or pathlib.Path) -- Path to image zarr.

  • new_layers_dir (str or pathlib.Path) -- Path to directory where new layers will be written.

  • ilastik_program_path (str) -- Path to ilastik program.

  • ilastik_project_path (str) -- Path to ilastik project for segmentation of image.

  • fg_channel (int) -- Channel of image taken to be foreground.

  • chunk_size (List[float]) -- Chunk size too be used in parallel processing. Defaults to [375, 375, 125].

  • soma_coords (List[list]) -- List of coordinates of soma centers. Defaults to [].

  • resolution (List[float) -- Resolution of image in microns. Defaults to [0.3, 0.3, 1].

  • parallel (int) -- Number of threads to use for parallel processing. Defaults to 1.

  • prob_path (str or pathlib.Path) -- Path to alrerady computed probability image (ilastik output). Defaults to None.

  • fragment_path (str or pathlib.Path) -- Path to alrerady computed fragment image. Defaults to None.

  • tiered_path (str or pathlib.Path) -- Path to alrerady computed tiered image. Defaults to None.

  • states_path (str or pathlib.Path) -- Path to alrerady computed states file. Defaults to None.

image_path

Path to image zarr.

Type:

str

new_layers_dir

Path to directory where new layers will be written.

Type:

str

ilastik_program_path

Path to ilastik program.

Type:

str

ilastik_project_path

Path to ilastik project for segmentation of image.

Type:

str

fg_channel

Channel of image taken to be foreground.

Type:

int

chunk_size

Chunk size too be used in parallel processing.

Type:

List[float], optional

soma_coords

List of coordinates of soma centers.

Type:

List[list], optional

resolution

Resolution of image in microns.

Type:

List[float], optional

parallel

Number of threads to use for parallel processing.

Type:

int, optional

prob_path

Path to alrerady computed probability image (ilastik output).

Type:

str, optional

fragment_path

Path to alrerady computed fragment image.

Type:

str, optional

tiered_path

Path to alrerady computed tiered image.

Type:

str, optional

states_path

Path to alrerady computed states file.

Type:

str, optional

Raises:
  • ValueError -- Image must be four dimensional (cxyz)

  • ValueError -- Chunks must include all channels and be 4D.

  • ValueError -- Already computed images must match image in spatial dimensions.

compute_bfs(self)

Compute bfs from highest degree node

compute_edge_weights(self)

Create viterbrain object and compute edge weights

compute_frags(self)

Compute all fragments for image

compute_image_tiered(self)

Compute entire tiered image then reassemble and save as zarr

compute_soma_lbls(self)

Compute fragment ids of soma coordinates.

compute_states(self, alg: str = 'nb')

Compute entire collection of states

Parameters:

alg (string, optional) -- algorithm to use for endpoint estimation. "nb" for neighborhood method, "pc" for principal curves method. Defaults to "nb"

Raises:

ValueError -- erroneously computed endpoints of soma state

predict(self, data_bin: str)

Run ilastik on zarr image

Parameters:

data_bin (str) -- path to directory to store intermediate files

Connect Fragments

class brainlit.algorithms.connect_fragments.ViterBrain(G: nx.Graph, tiered_path: str, fragment_path: str, resolution: List[float], coef_curv: float, coef_dist: float, coef_int: float, parallel: int = 1)
compute_all_costs_dist(self, frag_frag_func: Callable, frag_soma_func: Callable)

Splits up transition computation tasks then assembles them into networkx graph

Parameters:
  • frag_frag_func (function) -- function that computes transition cost between fragments

  • frag_soma_func (function) -- function that computes transition cost between fragments

compute_all_costs_int(self)

Splits up transition computation tasks then assembles them into networkx graph

frag_frag_dist(self, pt1: List[float], orientation1: List[float], pt2: List[float], orientation2: List[float], verbose: bool = False)

Compute cost of transition between two fragment states

Parameters:
  • pt1 (list of floats) -- first coordinate

  • orientation1 (list of floats) -- orientation at first coordinate

  • pt2 (list of floats) -- second coordinate

  • orientation2 (list of floats) -- orientation at second coordinate

  • verbose (bool, optional) -- Print transition cost information. Defaults to False.

Raises:
  • ValueError -- if an orientation is not unit length

  • ValueError -- if distance or curvature cost is nan

Returns:

cost of transition

Return type:

[float]

frag_soma_dist(self, point: List[float], orientation: List[float], soma_lbl: int, verbose: bool = False)

Compute cost of transition from fragment state to soma state

Parameters:
  • point (list of floats) -- coordinate on fragment

  • orientation (list of floats) -- orientation at fragment

  • soma_lbl (int) -- label of soma component

  • verbose (bool, optional) -- Prints cost values. Defaults to False.

Raises:
  • ValueError -- if either distance or curvature cost is nan

  • ValueError -- if the computed closest soma coordinate is not on the soma

Returns:

cost of transition [list of floats]: closest soma coordinate

Return type:

[float]

shortest_path(self, coord1: List[int], coord2: List[int])

Compute coordinate path from one coordinate to another.

Parameters:
  • coord1 (list) -- voxel coordinate of start point

  • coord2 (list) -- voxel coordinate of end point

Raises:

ValueError -- if state sequence contains a soma state that is not at the end

Returns:

list of voxel coordinates of path

Return type:

list

Trace Analysis

brainlit.algorithms.trace_analysis.speed(x: np.ndarray, t: np.ndarray, c: np.ndarray, k: np.integer, aux_outputs: bool = False)

Compute the speed of a B-Spline.

The speed is the norm of the first derivative of the B-Spline.

Parameters:
  • x -- A 1xL array of parameter values where to evaluate the curve. It contains the parameter values where the speed of the B-Spline will be evaluated. It is required to be non-empty, one-dimensional, and real-valued.

  • t -- A 1xm array representing the knots of the B-spline. It is required to be a non-empty, non-decreasing, and one-dimensional sequence of real-valued elements. For a B-Spline of degree k, at least 2k + 1 knots are required.

  • c -- A dxn array representing the coefficients/control points of the B-spline. Given n real-valued, d-dimensional points ::math::x_k = (x_k(1),...,x_k(d)), c is the non-empty matrix which columns are ::math::x_1^T,...,x_N^T. For a B-Spline of order k, n cannot be less than m-k-1.

  • k -- A non-negative integer representing the degree of the B-spline.

Returns:

A 1xL array containing the speed of the B-Spline evaluated at x

Return type:

speed

References: .. [Rbbccb9c002d5-1] Kouba, Parametric Equations.

brainlit.algorithms.trace_analysis.curvature(x: np.ndarray, t: np.ndarray, c: np.ndarray, k: np.integer, aux_outputs: bool = False)

Compute the curvature of a B-Spline.

The curvature measures the failure of a curve, r(u), to be a straight line. It is defined as

\[k = \lVert \frac{dT}{ds} \rVert,\]

where T is the unit tangent vector, and s is the arc length:

\[T = \frac{dr}{ds},\quad s = \int_0^t \lVert r'(u) \rVert du,\]

where r(u) is the position vector as a function of time.

The curvature can also be computed as

\[k = \lVert r'(t) \times r''(t)\rVert / \lVert r'(t) \rVert^3.\]
Parameters:
  • x -- A 1xL array of parameter values where to evaluate the curve. It contains the parameter values where the curvature of the B-Spline will be evaluated. It is required to be non-empty, one-dimensional, and real-valued.

  • t -- A 1xm array representing the knots of the B-spline. It is required to be a non-empty, non-decreasing, and one-dimensional sequence of real-valued elements. For a B-Spline of degree k, at least 2k + 1 knots are required.

  • c -- A dxn array representing the coefficients/control points of the B-spline. Given n real-valued, d-dimensional points ::math::x_k = (x_k(1),...,x_k(d)), c is the non-empty matrix which columns are ::math::x_1^T,...,x_N^T. For a B-Spline of order k, n cannot be less than m-k-1.

  • k -- A non-negative integer representing the degree of the B-spline.

Returns:

A 1xL array containing the curvature of the B-Spline evaluated at x

Return type:

curvature

References: .. [Rce97e449f49f-1] Máté Attila, The Frenet–Serret formulas.

brainlit.algorithms.trace_analysis.torsion(x: np.ndarray, t: np.ndarray, c: np.ndarray, k: np.integer, aux_outputs: bool = False)

Compute the torsion of a B-Spline.

The torsion measures the failure of a curve, r(u), to be planar. If the curvature k of a curve is not zero, then the torsion is defined as

\[\tau = -n \cdot b',\]

where n is the principal normal vector, and b' the derivative w.r.t. the arc length s of the binormal vector.

The torsion can also be computed as

\[\tau = \lvert r'(t), r''(t), r'''(t) \rvert / \lVert r'(t) \times r''(t) \rVert^2,\]

where r(u) is the position vector as a function of time.

Parameters:
  • x -- A 1xL array of parameter values where to evaluate the curve. It contains the parameter values where the torsion of the B-Spline will be evaluated. It is required to be non-empty, one-dimensional, and real-valued.

  • t -- A 1xm array representing the knots of the B-spline. It is required to be a non-empty, non-decreasing, and one-dimensional sequence of real-valued elements. For a B-Spline of degree k, at least 2k + 1 knots are required.

  • c -- A dxn array representing the coefficients/control points of the B-spline. Given n real-valued, d-dimensional points ::math::x_k = (x_k(1),...,x_k(d)), c is the non-empty matrix which columns are ::math::x_1^T,...,x_N^T. For a B-Spline of order k, n cannot be less than m-k-1.

  • k -- A non-negative integer representing the degree of the B-spline.

Returns:

A 1xL array containing the torsion of the B-Spline evaluated at x

Return type:

torsion

References: .. [R8b689f5f8f91-1] Máté Attila, The Frenet–Serret formulas.

class brainlit.algorithms.trace_analysis.CubicHermiteChain(x: np.array, y: np.array, left_dydx: np.array, right_dydx: np.array, extrapolate=None)

A third order spline class (continuous piecewise cubic representation), that is fit to a set of positions and one-sided derivatives. This is not a standard spline class (e.g. b-splines), because the derivatives are not necessarily continuous at the knots.

A subclass of PPoly, a piecewise polynomial class from scipy.

class brainlit.algorithms.trace_analysis.GeometricGraph(df: pd.DataFrame = None, root=1)

The shape of the neurons are expressed and fitted with splines in this undirected graph class.

The geometry of the neurons are projected on undirected graphs, based on which the trees of neurons consisted for splines is constructed. It is required that each node has a loc attribute identifying that points location in space, and the location should be defined in 3-dimensional cartesian coordinates. It extends nx.Graph and rejects duplicate node input.

fit_spline_tree_invariant(self, spline_type: Union[BSpline, CubicHermiteSpline] = BSpline, k=3)

Construct a spline tree based on the path lengths.

Parameters:

spline_type -- BSpline or CubicHermiteSpline, spline type that will be fit to the data. BSplines are typically used to fit position data only, and CubicHermiteSplines can only be used if derivative, and independent variable information is also known.

Raises:
  • ValueError -- check if every node is unigue in location

  • ValueError -- check if every node is assigned to at least one edge

  • ValueError -- check if the graph contains undirected cycle(s)

  • ValueErorr -- check if the graph has disconnected segment(s)

Returns:

nx.DiGraph a parent tree with the longest path in the directed graph

Return type:

spline_tree

Soma Detection

brainlit.algorithms.detect_somas.find_somas(volume: np.ndarray, res: list)

Find bright neuron somas in an input volume.

This simple soma detector assumes that somas are brighter than the rest of the objects contained in the input volume.

To detect somas, these steps are performed:

  1. Check input volume shape. This detector requires the x and y dimensions of the input volumes to be larger than 20 pixels.

  2. Zoom volume. We found that this simple soma detector works best when then input volume has size 160 x 160 x 50. We use ndimage.zoom to scale the input volume size to the desired shape.

  3. Binarize volume. We use Otsu thresholding to binarize the image.

  4. Erode the binarized image. We erode the binarized image with a structuring element which size is directly proportional to the maximum zoom factor applied to the input volume.

  5. Remove unreasonable connected components. After erosion, we compute the equivalent diameter d of each connected component, and only keep those ones such that 5mu m leq d < 21 mu m

  6. Find relative centroids. Finally, we compute the centroids of the remaining connected components. The centroids are in voxel units, relative to the input volume.

Parameters:
  • volume (numpy.ndarray) -- The 3D image array to run the detector on.

  • res (list) -- A 1 x 3 list containing the resolution of each voxel in nm.

Returns:

  • label (bool) -- A boolean value indicating whether the detector found any somas in the input volume.

  • rel_centroids (numpy.ndarray) -- A N x 3 array containing the relative voxel positions of the detected somas.

  • out (numpy.ndarray) -- A 160 x 160 x 50 array containing the detection mask.

Examples

>>> # download a volume
>>> dir = "s3://open-neurodata/brainlit/brain1"
>>> dir_segments = "s3://open-neurodata/brainlit/brain1_segments"
>>> volume_keys = "4807349.0_3827990.0_2922565.75_4907349.0_3927990.0_3022565.75"
>>> mip = 1
>>> ngl_sess = NeuroglancerSession(
>>>     mip=mip, url=dir, url_segments=dir_segments, use_https=False
>>> )
>>> res = ngl_sess.cv_segments.scales[ngl_sess.mip]["resolution"]
>>> volume_coords = np.array(os.path.basename(volume_keys).split("_")).astype(float)
>>> volume_vox_min = np.round(np.divide(volume_coords[:3], res)).astype(int)
>>> volume_vox_max = np.round(np.divide(volume_coords[3:], res)).astype(int)
>>> bbox = Bbox(volume_vox_min, volume_vox_max)
>>> img = ngl_sess.pull_bounds_img(bbox)
>>> # apply soma detector
>>> label, rel_centroids, out = find_somas(img, res)