Stitch reconstructed volumes#
Use the stitch_volumes workflow to align an ordered list of reconstructed
volumes and save three stitched orthogonal slice previews.
The workflow has two tasks:
RefineVolumePositionrefines the relative[z, x, y]displacement between consecutive volumes.StitchMatchedSlicesextracts matchingXY,YZ, andXZslices from the refined positions and stitches each slice set into one TIFF image.
Inputs#
The main inputs are:
volume_paths: ordered list of TIFF volume files or TIFF volume directories.guess_distances_mm: estimated relative displacement in millimetres, ordered as[z, x, y]. Provide one vector for all pairs or one vector per consecutive pair.voxel_size_um: voxel size in micrometres. Provide one scalar, one[z, x, y]vector, or one vector per volume.search_radius_px: local refinement radius in pixels around the guessed displacement. It accepts the same scalar/vector/per-pair forms.correlation_window_shape_px: optional[z, x, y]correlation block shape in pixels. When omitted, the task derives a window fromsearch_radius_px.downsample_factor: X/Y downsampling factor used by the coarse correlation step.output_path: optional output directory for the stitched slices.
All volume axes and displacements use this convention:
axis 0 = z
axis 1 = x
axis 2 = y
Stitching model#
Each volume is treated as a 3D array in local coordinates:
p = [z, x, y]
For two consecutive volumes, the initial displacement guess is provided in millimetres:
g_mm = [g_z, g_x, g_y]
The task converts this guess to pixels using the voxel size in micrometres:
g_px = round(1000 * g_mm / voxel_size_um)
The refinement step searches for a residual pixel shift r_px around this
guess. For a local overlap block R from the reference volume and M from the
moving volume, the task computes a normalized cross-correlation:
C(delta) = sum_p R_norm(p) * M_norm(p - delta)
where:
R_norm = (R - mean(R)) / std(R)
M_norm = (M - mean(M)) / std(M)
Only shifts inside search_radius_px are considered. The residual is the shift
with the highest correlation score:
r_px = argmax_delta C(delta)
The refined pairwise displacement is then:
s_pair = g_px + r_px
For more than two volumes, pairwise shifts are accumulated relative to the first volume:
S_0 = [0, 0, 0]
S_i = S_{i-1} + s_pair_i
These cumulative shifts S_i define a common global coordinate system. The task
then finds one global point P that belongs to the overlap of every shifted
volume. For each axis a, the common overlap interval is:
start_a = max_i S_i[a]
end_a = min_i S_i[a] + shape_i[a]
P_a = start_a + floor((end_a - start_a) / 2)
The local assembly point for volume i is:
A_i = P - S_i
These A_i coordinates select corresponding slices from all volumes.
For example, for the stitched XY preview:
slice_i = volume_i[A_i[z], :, :]
row shift = S_i[x]
col shift = S_i[y]
For YZ, the fixed coordinate is x, rows follow z, and columns follow y.
For XZ, the fixed coordinate is y, rows follow z, and columns follow x.
Each extracted 2D slice is placed on an output canvas using its row and column shift. If several slices overlap, the task first fits a linear intensity match:
reference ~= scale * moving + offset
on the overlapping pixels. It then blends the overlap with cosine weights so the transition between slices is gradual rather than a hard replacement.
Example inputs#
For two volumes with an expected displacement of 0.2 mm in z, 0.3 mm in x,
and -0.4 mm in y:
{
"volume_paths": [
"/data/volume_0001.tiff",
"/data/volume_0002.tiff"
],
"guess_distances_mm": [0.2, 0.3, -0.4],
"voxel_size_um": [100.0, 100.0, 100.0],
"search_radius_px": [2, 24, 24],
"downsample_factor": 8,
"output_path": "/data/stitched/volume_0001_0002"
}
For more than two volumes, provide one guess per consecutive pair when the relative motion is not constant:
{
"volume_paths": [
"/data/volume_0001.tiff",
"/data/volume_0002.tiff",
"/data/volume_0003.tiff"
],
"guess_distances_mm": [
[0.2, 0.3, -0.4],
[0.2, 0.3, -0.4]
],
"voxel_size_um": 100.0
}
Outputs#
RefineVolumePosition produces:
pair_refined_shifts_pixelspair_refined_shifts_mmvolume_shifts_pixelsvolume_shifts_mmassembly_points_pixels
StitchMatchedSlices writes these files in output_path:
stitched_xy.tiffstitched_yz.tiffstitched_xz.tiffmetadata.json
The metadata.json file stores the refined volume shifts and assembly points
used to create the stitched previews.