Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat s3 img reader #286

Merged
merged 3 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/deep_neurographs/generate_proposals.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@author: Anna Grim
@email: [email protected]

Module used to generate edge proposals.
Module used to generate edge proposals for a fragments graph.

"""

Expand Down
88 changes: 31 additions & 57 deletions src/deep_neurographs/utils/graph_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,20 @@
@email: [email protected]


Routines for loading fragments and building a fragments_graph.
Overview
--------
Code that reads and preprocesses neuron fragments stored as swc files, then
constructs a custom graph object called a "FragmentsGraph".

Graph Construction Algorithm:
1. Read Neuron Fragments
to do...

2. Preprocess Fragments and Extract Irreducibles
to do...

3. Build FragmentsGraph
to do...

Terminology
------------
Expand All @@ -31,12 +43,7 @@
from tqdm import tqdm

from deep_neurographs import geometry
from deep_neurographs.utils import img_util, swc_util, util

MIN_SIZE = 30
NODE_SPACING = 1
SMOOTH_BOOL = True
PRUNE_DEPTH = 20
from deep_neurographs.utils import swc_util, util


class GraphLoader:
Expand All @@ -48,36 +55,35 @@ class GraphLoader:
def __init__(
self,
anisotropy=[1.0, 1.0, 1.0],
min_size=MIN_SIZE,
node_spacing=NODE_SPACING,
min_size=30,
node_spacing=1,
progress_bar=False,
prune_depth=PRUNE_DEPTH,
smooth_bool=SMOOTH_BOOL,
prune_depth=20,
smooth_bool=True,
):
"""
Builds a FragmentsGraph by reading swc files stored either on the
cloud or local machine, then extracting the irreducible components.

Parameters
----------
anisotropy : list[float], optional
Scaling factors applied to xyz coordinates to account for the
anisotropy of microscope. The default is [1.0, 1.0, 1.0].
anisotropy : List[float], optional
Image to physical coordinates scaling factors to account for the
anisotropy of the microscope. The default is [1.0, 1.0, 1.0].
min_size : float, optional
Minimum path length of swc files which are stored as connected
components in the FragmentsGraph. The default is 30ums.
components in the FragmentsGraph. The default is 30.0 (microns).
node_spacing : int, optional
Spacing (in microns) between nodes. The default is the global
variable "NODE_SPACING".
Spacing (in microns) between nodes. The default is 1.
progress_bar : bool, optional
Indication of whether to print out a progress bar while building
graph. The default is True.
prune_depth : int, optional
Branches less than "prune_depth" microns are pruned if "prune" is
True. The default is the global variable "PRUNE_DEPTH".
True. The default is 20.0 (microns).
smooth_bool : bool, optional
Indication of whether to smooth branches from swc files. The
default is the global variable "SMOOTH".
default is True.

Returns
-------
Expand All @@ -90,12 +96,9 @@ def __init__(
self.progress_bar = progress_bar
self.prune_depth = prune_depth
self.smooth_bool = smooth_bool

self.reader = swc_util.Reader(anisotropy, min_size)

def run(
self, fragments_pointer, img_patch_origin=None, img_patch_shape=None
):
def run(self, fragments_pointer):
"""
Builds a FragmentsGraph by reading swc files stored either on the
cloud or local machine, then extracting the irreducible components.
Expand All @@ -105,12 +108,6 @@ def run(
fragments_pointer : dict, list, str
Pointer to swc files used to build an instance of FragmentsGraph,
see "swc_util.Reader" for further documentation.
img_patch_origin : list[int], optional
An xyz coordinate which is the upper, left, front corner of the
image patch that contains the swc files. The default is None.
img_patch_shape : list[int], optional
Shape of the image patch which contains the swc files. The default
is None.

Returns
-------
Expand All @@ -120,12 +117,13 @@ def run(
"""
from deep_neurographs.fragments_graph import FragmentsGraph

# Load fragments and extract irreducibles
self.img_bbox = img_util.init_bbox(img_patch_origin, img_patch_shape)
# Step 1: Read Neuron Fragments
swc_dicts = self.reader.load(fragments_pointer)

# Step: Preprocess Fragments and Extract Irreducibles
irreducibles = self.schedule_processes(swc_dicts)

# Build FragmentsGraph
# Step 3: Build FragmentsGraph
fragments_graph = FragmentsGraph(node_spacing=self.node_spacing)
while len(irreducibles):
irreducible_set = irreducibles.pop()
Expand Down Expand Up @@ -186,15 +184,14 @@ def get_irreducibles(self, swc_dict):

Returns
-------
list
List[dict]
List of dictionaries such that each is the set of irreducibles in
a connected component of the graph corresponding to "swc_dict".

"""
# Build dense graph
swc_dict["idx"] = dict(zip(swc_dict["id"], range(len(swc_dict["id"]))))
graph, _ = swc_util.to_graph(swc_dict, set_attrs=True)
self.clip_branches(graph, swc_dict["swc_id"])
self.prune_branches(graph)

# Extract irreducibles
Expand All @@ -210,28 +207,6 @@ def get_irreducibles(self, swc_dict):
irreducibles.append(result)
return irreducibles

def clip_branches(self, graph, swc_id):
"""
Deletes all nodes from "graph" that are not contained in "img_bbox".

Parameters
----------
graph : networkx.Graph
Graph to be searched

Returns
-------
None

"""
if self.img_bbox:
delete_nodes = set()
for i in graph.nodes:
xyz = img_util.to_voxels(graph.nodes[i]["xyz"], self.to_anisotropy)
if not util.is_contained(self.img_bbox, xyz):
delete_nodes.add(i)
graph.remove_nodes_from(delete_nodes)

def prune_branches(self, graph):
"""
Prunes all short branches from "graph". A short branch is a path
Expand Down Expand Up @@ -316,7 +291,6 @@ def get_component_irreducibles(self, graph, swc_dict):
# Visit j
attrs = upd_edge_attrs(swc_dict, attrs, j)
if j in leafs or j in branchings:
# Check whether to smooth
attrs["length"] = branch_length
attrs = to_numpy(attrs)
if self.smooth_bool:
Expand Down
26 changes: 14 additions & 12 deletions src/deep_neurographs/utils/img_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
@author: Anna Grim
@email: [email protected]

Helper routines for working with images.

Helper routines for processing images.

"""

Expand Down Expand Up @@ -313,29 +314,29 @@ def to_physical(voxel, anisotropy, shift=[0, 0, 0]):
return tuple([voxel[i] * anisotropy[i] - shift[i] for i in range(3)])


def to_voxels(xyz, anisotropy, downsample_factor=0):
def to_voxels(xyz, anisotropy, multiscale=0):
"""
Converts coordinates from world to voxel.

Parameters
----------
xyz : ArrayLike
xyz coordinate to be converted to voxels.
Physical coordiante to be converted to a voxel coordinate.
anisotropy : ArrayLike
Image to physical coordinates scaling factors to account for the
anisotropy of the microscope.
downsample_factor : int, optional
Downsampling factor that accounts for which level in the image pyramid
the voxel coordinates must index into. The default is 0.
multiscale : int, optional
Level in the image pyramid that the voxel coordinate must index into.
The default is 0.

Returns
-------
numpy.ndarray
Coordinates converted to voxels.
Voxel coordinate of the input.

"""
downsample_factor = 1.0 / 2 ** downsample_factor
voxel = downsample_factor * (xyz / np.array(anisotropy))
scaling_factor = 1.0 / 2 ** multiscale
voxel = scaling_factor * xyz / np.array(anisotropy)
return np.round(voxel).astype(int)


Expand All @@ -348,9 +349,10 @@ def init_bbox(origin, shape):
Parameters
----------
origin : tuple[int]
Origin of bounding box which is assumed to be top, front, left corner.
shape : tuple[int]
Shape of bounding box.
Voxel coordinate of the origin of the bounding box, which is assumed
to be top-front-left corner.
shape : Tuple[int]
Shape of the bounding box.

Returns
-------
Expand Down
3 changes: 2 additions & 1 deletion src/deep_neurographs/utils/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
@author: Anna Grim
@email: [email protected]

General helper routines for various tasks.

Miscellaneous helper routines.

"""

Expand Down
Loading