Usage¶
Overview¶
tile is a command-line tool for stitching tomographic mosaic datasets — sets of overlapping scans that together cover a field of view larger than a single detector frame.
The full pipeline from raw HDF5 files to a reconstructed 3D volume has the following steps. Not all steps are required for every dataset; the table below shows which are optional.
# |
Command |
Required? |
What it does |
|---|---|---|---|
1 |
|
Yes |
Verify the dataset — print tile grid, image size, nominal overlap |
2 |
|
Optional |
Spatially bin raw files to reduce data volume before processing |
3 |
|
Optional |
Collect a flat field basis for per-projection NNLS flat correction |
4 |
|
Optional |
Quick visual check — save one stitched projection to a tiff |
5 |
|
Yes |
Find the rotation axis location (trial reconstruction stack) |
6 |
|
Yes |
Fine-tune horizontal tile positions |
7 |
|
Yes |
Horizontally stitch all tiles in each y-row → |
8 |
|
Multi-row only |
Vertically stitch the per-row |
9 |
|
360° scans only |
Convert 360° dataset to 180° by stitching paired projections |
10 |
|
Yes |
Final 3D reconstruction |
HDF5 metadata requirements¶
tile reads the following metadata from each HDF5 file to sort tiles by position and compute the nominal overlap:
Sample X position (mm):
/measurement/instrument/sample_motor_stack/setup/xSample Y position (mm):
/measurement/instrument/sample_motor_stack/setup/yImage resolution (µm/px):
/measurement/instrument/detection_system/objective/resolutionOriginal file name:
/measurement/sample/file/full_name
These paths follow the dxfile convention used at 2-BM, 7-BM, and 32-ID.
If your metadata is stored elsewhere, override the paths at runtime:
tile show --sample-x '/your/path/to/x' --sample-y '/your/path/to/y'
Note
At 2-BM, flat fields are collected at the end of each scan with the sample moved to
SampleOutX. Because the HDF attribute is written OnFileClose, the motor RBV at
that moment reflects the flat-field position rather than the scan position. The correct
tile X positions are stored in /process/acquisition/flat_fields/sample/in_x and are
read automatically by tile. If you collected data before this fix was in place, pass the
correct path explicitly:
tile show --sample-x /process/acquisition/flat_fields/sample/in_x
Step 1 — Verify the dataset (tile show)¶
Read the HDF metadata from every tile file, sort them by motor position, and print the tile grid layout, image size, and nominal overlap:
(tile) tomo@tomo4 $ tile show --folder-name /data/2021-12/Duchkov/mosaic/
2022-02-16 11:33:38,485 - Started tile
2022-02-16 11:33:38,485 - Saving log at /home/beams/TOMO/logs/tile_2022-02-16_11_33_38.log
2022-02-16 11:33:38,485 - checking tile files ...
2022-02-16 11:33:38,485 - Checking directory: /data/2021-12/Duchkov/mosaic for a tile scan
2022-02-16 11:33:38,780 - tile file sorted
2022-02-16 11:33:38,780 - x0y0: x = -0.0001; y = 28.0, file name = .../mosaic_2073.h5
2022-02-16 11:33:38,780 - x1y0: x = 0.8499; y = 28.0, file name = .../mosaic_2074.h5
...
2022-02-16 11:33:38,918 - image size (x, y) in pixels: (2448, 2048)
2022-02-16 11:33:38,918 - tile shift (x, y) in pixels: (2428, 0)
2022-02-16 11:33:38,918 - tile overlap (x, y) in pixels: (20, 2048)
2022-02-16 11:33:38,918 - tile file name grid:
y_0
x_0 /data/2021-12/Duchkov/mosaic/mosaic_2073.h5
x_1 /data/2021-12/Duchkov/mosaic/mosaic_2074.h5
...
Check that:
All expected tiles are present and in the correct row/column positions.
The nominal overlap (
tile overlap) is a reasonable fraction of the tile width (typically 5–20%).
Warning
--reverse-grid True (the default at 2-BM) reverses the tile order within each row,
so that tile x0 is placed at the left of the stitched image. This matches the 2-BM
detector geometry where positive motor X moves the sample to the left in the image.
Pass --reverse-grid False if positive X moves the sample to the right.
Step 2 — Bin raw files (tile bin) — optional¶
For large datasets (e.g. 6000 projections × 4852 × 6464 px per tile) it is practical to work on a spatially-binned copy during the alignment steps (center search, shift tuning). Once the parameters are confirmed on the binned data the final stitch can be done at full resolution.
tile bin copies all .h5 files from --folder-name, applies 2**binning × 2**binning
spatial binning to the exchange datasets, and optionally subsamples every --bin-stepth
projection. Output files are written to <folder-name>/bin<N>x<N>/ by default:
(tile) tomo@tomo4 $ tile bin --folder-name /data/raw/ --binning 1 --bin-step 2
# → outputs to /data/raw/bin2x2/ (2×2 spatial bin, every 2nd projection)
(tile) tomo@tomo4 $ tile bin --folder-name /data/raw/ --binning 2 --bin-step 1
# → outputs to /data/raw/bin4x4/ (4×4 spatial bin, all projections)
For a multi-row mosaic where each row lives in a separate subfolder, run tile bin once per
row folder:
for ydir in y0 y1 y2 y3; do
tile bin --folder-name /data/raw/$ydir/ --binning 1 --bin-step 2
done
Key parameters:
|
Spatial bin factor = 2N (0=none, 1=2×2, 2=4×4, …) |
|
Keep every Nth projection (1 = keep all) |
|
Override the default output directory |
Step 3 — Collect flat field basis (tile dump-flats) — optional¶
tile dump-flats collects flat fields from all tile HDF5 files and saves them as a basis
file for per-projection NNLS flat correction. For each input file it writes two averaged
frames: the mean of the first half and the mean of the second half of the flat field frames.
This basis is then passed to subsequent commands via --flats-file.
Use this when:
Flat field illumination varies significantly across the scan (beam intensity drift, ring artifacts from a specific flat, etc.).
You want per-projection flat correction rather than a simple averaged flat.
For a single-folder dataset:
(tile) tomo@tomo4 $ tile dump-flats --folder-name /data/raw/bin2x2/ \
--dump-flats-output flats.h5
# → writes /data/raw/bin2x2/flats.h5
For a multi-row dataset where each row lives in a subfolder:
(tile) tomo@tomo4 $ tile dump-flats --folder-name /data/raw/bin2x2/ \
--y-folders y0,y1,y2,y3 \
--dump-flats-output flats.h5
# → collects flats from y0/, y1/, y2/, y3/ and writes /data/raw/bin2x2/flats.h5
The resulting flats.h5 is passed to tile center, tile shift, and tile stitch
via the --flats-file option.
Key parameters:
|
Comma-separated subfolder names (e.g. |
|
Output filename inside |
|
Flip the X direction when reading flats ( |
Step 4 — Quick panoramic inspection (tile panoramic) — optional¶
Before running the time-consuming center search, use tile panoramic to visually confirm
the tile layout. It reads a single projection (at the angle set by --nprojection, default
0.5 = midpoint) from each tile, normalises it, and saves a wide stitched image to
tile/panoramic.tif in the dataset folder:
(tile) tomo@tomo4 $ tile panoramic --flat-linear True
Open the result in Fiji ImageJ to confirm:
All tiles are present and in the correct left-to-right order.
The nominal overlap looks approximately correct (seam regions may not be perfect yet).
The sample fills the expected field of view.
Once you have the correct shifts from tile shift, you can regenerate the panoramic with
the corrected positions to verify the alignment:
(tile) tomo@tomo4 $ tile panoramic --flat-linear True --x-shifts "[0, 5430, 5419]"
Pass --show to display the image interactively in a matplotlib window (requires a display).
Step 5 — Find the rotation center (tile center)¶
tile center stitches all horizontal tiles in the top row of the mosaic using the
nominal overlap from the HDF file, then reconstructs a stack of trial slices, each with a
slightly different rotation axis position. You inspect the stack and pick the sharpest image.
The sinogram row used is controlled by --nsino (0 = top, 1 = bottom, default 0.5 =
vertical centre of the detector). With --binning N, 2**N consecutive rows are
averaged to improve signal.
Warning
Only the centre of the reconstructed image is reliable at this stage. The outer regions may look blurry because the nominal tile overlap is only approximate. Ignore those regions and focus on the centre when selecting the rotation axis.
Warning
--file-type double_fov (the default) tells tomocupy to treat the input as a 360°
scan and mirror the sinogram. This is the standard mode at 2-BM for 360° acquisitions.
Pass --file-type standard for ordinary 180° scans.
Recommended workflow — two passes:
Pass 1 — coarse search (wide step, large range):
(tile) tomo@tomo4 $ tile center --recon-engine tomocupy \
--rotation-axis 400 --center-search-width 200 --center-search-step 10 \
--file-type double_fov --binning 2 --nsino-per-chunk 2 --flat-linear True
Open the try-center stack from:
/path/to/data/tile_rec/try_center/tmp/recon*
in Fiji (File → Import → Image Sequence). Zoom into the centre of the image and move the slider until the reconstruction looks sharp and ring-free. Note the rotation axis value shown in the top-left corner of the best image.
Pass 2 — fine search (small step, narrow range):
(tile) tomo@tomo4 $ tile center --recon-engine tomocupy \
--rotation-axis 656 --center-search-width 10 --center-search-step 1 \
--file-type double_fov --binning 2 --nsino-per-chunk 2 --flat-linear True
Record the final rotation axis value (e.g. 650) for the next step.
Key parameters:
|
Starting guess for the rotation axis (pixels). Use -1 to default to image centre. |
|
Half-width of the search range (pixels). |
|
Step size between trials (pixels). |
|
Relative vertical position of the sinogram row (0–1). |
|
Spatial binning (0=none, 1=2×, 2=4×). |
|
Number of sinogram rows averaged per chunk (increase for better SNR). |
|
Enable linear interpolation of flat fields across the scan. |
|
Use per-projection NNLS flat correction from a |
|
|
|
|
Step 6 — Fine-tune tile shifts (tile shift)¶
tile center used the nominal overlap stored in the HDF file. tile shift refines each
horizontal tile position one boundary at a time, keeping all previously fixed tiles fixed and
sliding only the next tile.
For each boundary between adjacent tiles, it reconstructs a stack of slices by shifting the
overlap by --shift-search-width pixels in steps of --shift-search-step on either side
of the nominal position. A colour-coded index map is printed:
green = negative offset (tiles closer than nominal)
red = 0 offset (perfect motor positioning = nominal overlap)
yellow = positive offset (tiles farther than nominal)
(tile) tomo@tomo4 $ tile shift --rotation-axis 650 --flat-linear True \
--shift-search-width 60 --shift-search-step 1
...
Please enter rotation center (656.2): 650
...
Please enter id for tile 1 shift [nominal: 60] ...: 74
2026-03-25 15:47:02,348 - Selected offset for tile 1: +14 px (index 74)
2026-03-25 15:47:02,349 - Current shifts: [0 5430 5416]
...
Please enter id for tile 2 shift [nominal: 60] ...: 63
2026-03-25 16:02:20,813 - Selected offset for tile 2: +3 px (index 63)
2026-03-25 16:02:20,813 - Current shifts: [0 5430 5419]
2026-03-25 16:02:20,814 - Center 650
2026-03-25 16:02:20,815 - Relative shifts [0, 5430, 5419]
Inspect the try-recon stack or the stitched projection stack in Fiji. Zoom into the boundary region between the two tiles and move the slider until the seam is sharp and artifact-free. The file name in Fiji’s title bar gives the index to enter (pressing Enter accepts the nominal).
Record the final shift list (e.g. [0, 5430, 5419]) for the next step.
Key parameters:
|
Rotation axis found in Step 5. |
|
Half-width of the shift search in pixels (default 20). |
|
Step size between shift trials in pixels (default 1). |
|
As in Step 5. |
|
Provide pre-computed shifts to skip the interactive search (e.g. from a previous run). |
Step 7 — Horizontal stitch (tile stitch)¶
tile stitch merges all tiles for each y-row into a single HDF5 file (tile.h5) using
the confirmed x-shifts. The output file has flat/dark correction already applied
(data_white=1, data_dark=0) so that subsequent steps (vstitch, double-fov,
reconstruction) do not need to repeat it.
For a single-row mosaic:
(tile) tomo@tomo4 $ tile stitch --folder-name /data/mosaic/ \
--x-shifts "[0, 2450, 2450, 2452, 2454]" \
--rotation-axis 1246 --flat-linear True
For a multi-row mosaic, run tile stitch once per y-row:
for k in 0 1 2 3; do
tile stitch --folder-name /data/bin2x2/y$k/ \
--x-shifts "[0, 2752, 2752]" \
--rotation-axis 324 --flat-linear True \
--flats-file /data/bin2x2/flats.h5 --zinger-level 0.08
done
Each run writes <folder-name>/tile/tile.h5.
Key parameters:
|
Cumulative pixel shifts from Step 6, e.g. |
|
Rotation axis from Step 5 (used when |
|
Linear flat-field interpolation per projection. |
|
Per-projection NNLS flat correction (from |
|
Zinger removal threshold as fraction above local temporal median (0 = disabled, 0.08 = 8%). A value of 0 disables zinger removal. |
|
Projections processed per chunk (increase for faster I/O, at the cost of memory). |
|
Number of parallel threads for chunk processing. |
|
Process only a subset of projections (useful for splitting a large job). |
|
Whether to also run a quick reconstruction after stitching (default True). |
Step 8 — Vertical stitch (tile vstitch) — multi-row only¶
For a mosaic with multiple y-rows, tile vstitch stacks the per-row tile.h5 files
vertically into a single vstitch.h5. It uses quintic blending in the overlap region and
applies per-projection intensity scale calibration between adjacent rows to smooth brightness
differences.
Determine the y-shifts between rows (in pixels) by inspecting a single projection from each
row’s tile.h5 and measuring the vertical overlap:
(tile) tomo@tomo4 $ tile vstitch \
--folder-name /data/bin2x2/ \
--y-folders y0,y1,y2,y3 \
--y-shifts "[0, 450, 450, 450]" \
--vstitch-output vstitch.h5
Alternatively, pass an explicit glob pattern:
(tile) tomo@tomo4 $ tile vstitch \
--folder-name /data/bin2x2/ \
--vstitch-pattern "/data/bin2x2/y*/tile/tile.h5" \
--y-shifts "[0, 450, 450, 450]"
Output: <folder-name>/vstitch.h5 (or as set by --vstitch-output).
Key parameters:
|
Cumulative y-shifts between rows in pixels, e.g. |
|
Comma-separated subfolder names (e.g. |
|
Explicit glob pattern overriding |
|
Output filename relative to |
|
Projections processed per chunk. |
|
Number of parallel threads. |
Step 9 — 360° to 180° conversion (tile double-fov) — 360° scans only¶
For 360° acquisitions, tile double-fov converts the dataset to an effective 180° scan
by stitching projection i with fliplr(projection[i + N/2]). The rotation axis position
controls the amount of overlap/shift between the two halves.
The output is a half-sized projection stack (N/2 projections × full stitched width) ready for standard 180° reconstruction:
(tile) tomo@tomo4 $ tile double-fov \
--folder-name /data/bin2x2/ \
--double-fov-input vstitch.h5 \
--double-fov-output double_fov.h5 \
--rotation-axis 1627
Key parameters:
|
Rotation axis position in the input file (pixels from left edge). Required. |
|
Input HDF5 file (relative to |
|
Output HDF5 file (default |
|
Projections processed per chunk. |
|
Number of parallel threads. |
Step 10 — Reconstruction¶
Once the final stitched file is ready, reconstruct with tomocupy or tomopy/tomopycli.
Single-row mosaic (tile/tile.h5, 180° scan):
(tomocupy) tomo@tomo4 $ tomocupy recon \
--file-name /data/mosaic/tile/tile.h5 \
--rotation-axis 1246 \
--reconstruction-type full \
--file-type standard \
--binning 0 --nsino-per-chunk 8 \
--rotation-axis-auto manual
Multi-row 360° mosaic (double_fov.h5, already converted to 180°):
(tomocupy) tomo@tomo4 $ tomocupy recon \
--file-name /data/bin2x2/double_fov.h5 \
--rotation-axis 1627 \
--reconstruction-type full \
--file-type standard \
--binning 0 --nsino-per-chunk 8 \
--rotation-axis-auto manual
Note
After tile double-fov the file is already a 180° dataset, so pass
--file-type standard. Use --file-type double_fov only if you are passing the
raw stitched tile.h5 directly to tomocupy without the explicit double-fov conversion.
For all options:
(tile) tomo@tomo4 $ tile -h
(tile) tomo@tomo4 $ tile stitch -h
(tile) tomo@tomo4 $ tile vstitch -h
(tile) tomo@tomo4 $ tile double-fov -h
Complete workflow example — 4×3 mosaic, 360° scan¶
This example follows the processing of a 4-row × 3-column coffee bean mosaic collected at
2-BM in March 2026. Each row lives in a separate subfolder y0–y3 under the data
directory and the scan is a 360° acquisition.
DATA=/data/raw # raw files in DATA/y0/, DATA/y1/, DATA/y2/, DATA/y3/
BIN=/data/bin2x2 # working directory (2×2 binned, every 2nd projection)
# 1. Verify the dataset (use any y-row)
tile show --folder-name $DATA/y0/
# 2. Bin all rows
for k in 0 1 2 3; do
tile bin --folder-name $DATA/y$k/ --binning 1 --bin-step 2
done
# 3. Collect flat field basis
tile dump-flats --folder-name $BIN --y-folders y0,y1,y2,y3 \
--dump-flats-output flats.h5
# 4. Quick panoramic (top row only)
tile panoramic --folder-name $BIN/y0/ --flat-linear True
# 5. Find rotation center (coarse)
tile center --folder-name $BIN/y0/ --recon-engine tomocupy \
--rotation-axis 400 --center-search-width 200 --center-search-step 10 \
--file-type double_fov --binning 0 --nsino-per-chunk 2 --flat-linear True
# → open $BIN/y0/tile_rec/try_center/tmp/recon* in Fiji, pick best frame → e.g. 324
# 5b. Fine search
tile center --folder-name $BIN/y0/ --recon-engine tomocupy \
--rotation-axis 324 --center-search-width 10 --center-search-step 1 \
--file-type double_fov --binning 0 --nsino-per-chunk 2 --flat-linear True
# → confirmed rotation axis = 324
# 6. Find tile shifts
tile shift --folder-name $BIN/y0/ --rotation-axis 324 --flat-linear True \
--shift-search-width 60 --shift-search-step 1
# → confirmed x-shifts = [0, 2752, 2752]
# 7. Stitch all rows
for k in 0 1 2 3; do
tile stitch --folder-name $BIN/y$k/ \
--x-shifts "[0, 2752, 2752]" \
--rotation-axis 324 --flat-linear True \
--flats-file $BIN/flats.h5 --zinger-level 0.08
done
# → $BIN/y*/tile/tile.h5
# 8. Vertical stitch
tile vstitch --folder-name $BIN \
--y-folders y0,y1,y2,y3 \
--y-shifts "[0, 450, 450, 450]" \
--vstitch-output vstitch.h5
# → $BIN/vstitch.h5
# 9. 360° → 180° conversion
tile double-fov --folder-name $BIN \
--double-fov-input vstitch.h5 \
--double-fov-output double_fov.h5 \
--rotation-axis 1627
# → $BIN/double_fov.h5
# 10. Reconstruct
tomocupy recon \
--file-name $BIN/double_fov.h5 \
--rotation-axis 1627 \
--reconstruction-type full \
--file-type standard \
--binning 0 --nsino-per-chunk 8 \
--rotation-axis-auto manual