neu_lib.piece¶
An array and the frame that says where it is: Piece.
piece.shape # (364, 244, 244) piece.bbox # BBox in the frame’s voxels: where it sits in its parent piece.bounds_nm # the same box in nm, as floats piece.crop(box) # a sub-piece, its origin shifted to match piece.kind # “segmentation”: what the voxels mean, if the source said piece.name # “gt/vol_03700”: what it is called, if the source said piece.to_numpy() # the voxels in CPU memory
Keeping the array and its origin in one object is the point: carried separately, the origin is easy to drop, and the data then lands at nm zero with no error.
Coordinates are the frame’s voxels, not array indices: a piece read from voxel 7819 of
a level has bbox.lo == 7819, the number needed to place it back or compare it with a
sibling. bbox is an integer BBox; bounds_nm is floats and
deliberately not a BBox, since rounding a physical box to integers would move it.
Attributes¶
Classes¶
A 3-D zyx array, optionally with a leading channel axis, and its |
Module Contents¶
- class neu_lib.piece.Piece¶
A 3-D zyx array, optionally with a leading channel axis, and its
Frame.frame.origin_nmis where the array’s(0, 0, 0)sits in nm, so a piece cropped out of a volume stays in that volume’s coordinates.kind(one ofKINDS, orNoneif unknown) is never guessed from the dtype: a uint8 label array looks exactly like an image.nameis a label for display, not an identity;neu_vol.read_piece()fills both in from the source.The array may be any array type with
shape,dtypeandndim, including cupy, dask, zarr and h5py. The piece is frozen but the array is not copied or made read-only:piece.array[...] = 0mutates it, and whatever it is a view of. Usecopy()before editing in place.- apply(fn: Any, *args, frame: neu_lib.frame.Frame | None = None, kind: Any = _UNSET, name: Any = _UNSET, **kwargs) Piece¶
fn(array, *args, **kwargs)as a new piece, keeping everything else.piece.apply(lambda a: a > 0.5, kind=”segmentation”) piece.apply(scipy.ndimage.gaussian_filter, sigma=2) piece.apply(dilate).apply(label, kind=”segmentation”)
The frame, kind and name carry over, with two guards:
A change of spatial shape needs ``frame=``. A 2x downsample halves the shape and doubles the voxel size; keeping the old frame would place the result at half its real size. No factor is guessed, since real pyramids are anisotropic.
A change of dtype needs ``kind=``: a member of
KINDS,"same", orNonefor unknown. A dtype change is the visible sign that the meaning may have changed (a probability map thresholded to a mask, a mask labelled), and carrying"probability"through it would later allow averaging label ids.
namecarries over unless given;name=Noneclears it.
- copy(**changes) Piece¶
A copy, with any field replaced — and the array copied too.
out = piece.copy(array=gaussian(piece.array)) # a transform, same frame out = piece.copy(kind=”probability”) # relabel what it is out = piece.copy(); out.array[mask] = 0 # then edit in place, safely
Unlike
dataclasses.replace, which pairs the same array with new metadata, so that editing the result edits the original. Passingarray=skips the copy. The frame is shared, which is safe because it is frozen. Fields are validated as usual.
- crop(box: Any) Piece¶
The sub-piece inside
box(aBBoxor(lo, hi)), given in the frame’s voxels likebbox, not in array indices. The result’s origin is shifted to match, so it stays in the parent’s coordinates.
- to_nm(points_zyx: Sequence | numpy.ndarray) numpy.ndarray¶
Voxel coordinates of this piece’s array, zyx, to nm.
- to_numpy() numpy.ndarray¶
The voxels as a CPU numpy array; for a cupy array, a copy off the GPU.
plt.imshow(piece.to_numpy()[32])
to_cpu()does the same but keeps the piece. There is deliberately noto_gpu: it would need cupy, and this package depends on numpy alone. Useneu_proc.ops.backend.to_gpu.
- with_frame(frame: neu_lib.frame.Frame) Piece¶
The same array in a different frame — for a source that recorded none.
- array: numpy.ndarray¶
- property bbox: neu_lib.grid.BBox¶
Where the piece sits, as a half-open box in the frame’s voxels (not array indices).
- property bounds_nm: tuple[tuple[float, float, float], tuple[float, float, float]]¶
(lo, hi)in nm, as floats. Not aBBox, whose bounds are integers.
- property channel_axis: bool¶
Whether there is a leading channel axis (the array is 4-D).
- property channels: int¶
- property dtype: numpy.dtype¶
- frame: neu_lib.frame.Frame¶
- property is_segmentation: bool¶
Whether coarsening this must take a mode rather than a mean. False when
kindis unknown.
- kind: str | None = None¶
- name: str | None = None¶
- property origin_nm: tuple[float, float, float]¶
- property origin_voxel: tuple[int, int, int]¶
Where the array starts, in the frame’s voxels (what HDF5 pieces record as
voxel_offset). Raises if the origin is not on the voxel grid, rather than rounding and shifting the piece by up to half a voxel.
- property shape: tuple[int, ...]¶
The array’s full shape, channel axis included.
- property spatial_shape: tuple[int, int, int]¶
The three spatial extents, zyx, whether or not there is a channel axis.
- property voxel_size_nm: tuple[float, float, float]¶
- neu_lib.piece.KINDS = ('image', 'probability', 'segmentation')¶