Coordinate Systems Guide¶
aind-zarr-utils represents point coordinates with two pieces of information:
a named
(N, 3)array stored inPoints.valuesan explicit
Spacetag describing what those three columns mean
Asset.transform(points, to=...) moves points between supported spaces.
Supported Spaces¶
from aind_zarr_utils import Space
Space |
Meaning |
|---|---|
|
Continuous level-0 |
|
Light-sheet coordinates after multiplying indices by spacing |
|
Raw Zarr anatomical LPS millimeters |
|
Pipeline-corrected anatomical LPS millimeters |
|
Allen CCF LPS millimeters |
Basic Transform¶
import numpy as np
from aind_zarr_utils import Asset, Points, Space
asset = Asset.from_zarr("s3://aind-open-data/dataset/image.ome.zarr/0")
points = Points(
{"soma": np.array([[100, 200, 50]])},
Space.ZARR_INDICES,
)
raw_lps = asset.transform(points, to=Space.LS_ANATOMICAL_MM)
pipeline_lps = asset.transform(points, to=Space.LS_PIPELINE_ANATOMICAL_MM)
ccf = asset.transform(points, to=Space.CCF_MM)
Points validates every array as (N, 3) and coerces values to floating
point, so sub-voxel coordinates are preserved.
LPS Physical Coordinates¶
Physical outputs use ITK LPS millimeters:
positive X moves left
positive Y moves posterior
positive Z moves superior
Raw anatomical space and pipeline anatomical space are both LPS millimeter spaces. They differ in the header used to interpret Zarr indices:
Space.LS_ANATOMICAL_MMuses the raw Zarr metadata headerSpace.LS_PIPELINE_ANATOMICAL_MMuses the pipeline-corrected header fromprocessing.json
Neuroglancer¶
Neuroglancer annotations enter the graph as Zarr indices:
from aind_zarr_utils import Asset, Points, Space
asset = Asset.from_neuroglancer(ng_state)
points = Points.from_neuroglancer(ng_state)
ccf = asset.transform(points, to=Space.CCF_MM)
Descriptions from annotation layers are preserved on the returned Points
object when available.
SWC¶
SWC coordinates enter as spacing-scaled light-sheet millimeters:
points = Points.from_swc(
swc_array,
axis_order="zyx",
units="micrometer",
)
indices = asset.transform(points, to=Space.ZARR_INDICES)
ccf = asset.transform(points, to=Space.CCF_MM)
Unlike the legacy SWC helper, Points.from_swc() does not round to integer
indices.
Images And Stubs¶
Use images when you need pixels:
sitk_img = asset.image(level=3)
ants_img = asset.image(level=3, library="ants")
Use stubs when you need only the coordinate system:
stub, native_size_ijk = asset.stub(level=0)
pipeline_stub, native_size_ijk = asset.stub(pipeline=True)
SimpleITK and ANTs expose image size/shape differently, but the physical domain is the same for matching asset, level, and pipeline settings.
Legacy Helpers¶
The older helpers are still available for explicit-metadata workflows:
from aind_zarr_utils.annotations import annotation_indices_to_anatomical
from aind_zarr_utils.zarr import zarr_to_sitk_stub
stub, native_size_ijk = zarr_to_sitk_stub(zarr_uri, metadata, level=0)
raw_lps = annotation_indices_to_anatomical(stub, {"soma": indices})
New code should prefer Points and Asset.transform() so the coordinate space
is carried with the data.