Skip to main content

Multi-view light sheet microscopy image processing pipeline

Project description

IsoView Light Sheet Microscopy Pipeline

Acquisition Modes

Raw input is always flat — SPC##_TM#####_ANG###_CM#_CHN##_PH#.stack files in a single directory. Mode is auto-detected from SPC/TM counts:

Condition Mode Description
Multiple TM values timelapse time series, any number of specimens
Single TM + multiple SPC tiled spatial tiles, one timepoint
Single TM + single SPC single treated as timelapse with 1 timepoint

Filename Tags

Tag Meaning Raw Corrected
SPC## / SPM## specimen / tile SPC00 SPM00
TM##### timepoint TM00000 TM000000
CM# camera CM0 CM00
CHN## channel (raw) CHN00, CHN01
VW## view (corrected) VW00 (z-scan), VW90 (y-scan)
ANG### illumination angle ANG000 — (dropped)
PH# phase PH0 — (dropped)

Output Layout

Correction writes to {input_dir.name}{corrected_suffix} (default .corrected) and fusion writes to a sibling {input_dir.name}{fused_suffix} (default .fused), both as siblings of the raw input directory.

Correction (correct_stack.py)

Mode Path Filename
Timelapse root.corrected/SPM00/TM000000/ SPM00_TM000000_CM00_VW00.ome.tif
Tiled root.corrected/SPM00/ SPM00_CM00_VW00.ome.tif

Each tile will have a SPM0N folder, where N is the tile index.

Fusion (multi_fuse)

Mode Path Filename
Timelapse root.fused/adaptive/SPM00/TM000000/ SPM00_TM000000_CM00_CM01_VW00.ome.tif
Tiled root.fused/adaptive/SPM00/ SPM00_CM00_CM01_VW00.ome.tif

Default pairs: [(0, 1), (2, 3)] — cameras 0,1 share CHN00/VW00; cameras 2,3 share CHN01/VW90. Only the second camera in each pair gets rotation/flip transforms.

Supported Output Formats

Format Extension Notes
OME-TIFF .ome.tif with metadata, optional resolution pyramids
Zarr v3 ome.zarr OME-NGFF metadata
KLB .klb Keller Lab Block (bzip2)

XML Metadata

read_xml_metadata(xml_path) parses one push_config XML; read_all_xml_metadata(input_dir, specimen) returns (common, per_camera) — fields equal across cameras vs camera-specific.

Field Type Source Notes
data_header str @data_header acquisition session label
specimen_name str @specimen_name
timestamp str @timestamp acquisition datetime
time_point int @time_point
specimen_XYZT str @specimen_XYZT also parsed → stage_x/y/z (float, µm)
angle float @angle
camera_index str @camera_index comma-separated per camera
camera_type str @camera_type
camera_roi str @camera_roi
wavelength str @wavelength emission, per camera
illumination_arms str @illumination_arms per camera
illumination_filter str @illumination_filter
exposure_time float @exposure_time ms
detection_filter str @detection_filter
detection_objective str @detection_objective also parsed → objective_mag (float)
dimensions ndarray @dimensions (n_cameras, 3) from "WxHxD,WxHxD,…"
z_step float @z_step µm; VW00 (Z-scan)
y_step float @y_step µm; VW90 (Y-scan)
stack_direction str @stack_direction drives camera_view_map
planes str @planes
laser_power str @laser_power
experiment_notes str @experiment_notes
zplanes int derived dimensions[0][-1]
fps float derived 1000.0 / exposure_time
vps float derived fps / zplanes
camera_pixel_size_um float constant 6.5 (Hamamatsu C11440-22C)
pixel_resolution_um float derived camera_pixel_size_um / objective_mag
axial_step float merged unifies z_step / y_step across XMLs
camera_view_map dict synthesized from stack_direction: Z-scan → {0:0,1:0}, Y-scan → {2:90,3:90}

XML discovery order (in read_all_xml_metadata): ch*_spec{NN}.xmlch*.xml*_CHN*.xml*_VW*.xml (legacy), also under SPM##/. Channel inferred from filename via ch(\d+)CHN(\d+)VW(\d+).

Companion Files

For each corrected/fused volume <base>.<ext>:

File Location Format
<base>.segmentationMask.<ext> corrected dir 3D mask, same ext as volume
<base>.xyMask.<ext>, <base>.xzMask.<ext> corrected dir 2D per-axis masks
<base>.{xy,xz,yz}Projection.tif corrected/fused dir 2D projection
<base>.minIntensity.npz corrected dir numpy archive
<base>.mask.<ext> fused dir 3D segmentation
<base>.fusionMask.tif fused dir 2D blending mask
Background_*.tif raw root shared per dataset; read_background_values(files, percentile=3.0) → list of floats
SPM##[_TM######]_CHN##.xml / _VW##.xml (legacy) corrected dir per-channel XML copy

Project Contents

detect_project_contents(root, corrected_suffix=".corrected", specimen=0) returns a single tagged manifest:

# timepoint mode
{"mode": "timepoint", "root": Path,
 "backgrounds": [Path, ...],
 "timepoints": {tp_int: {
    "raw_dir": Path,
    "raw_stacks": {(cam, chn): Path},
    "xml": {ch: Path},
    "corrected": {                  # or None
        "dir": Path,
        "volumes": {cam: Path},
        "masks": {cam: {"segmentation": Path, "xy": Path, "xz": Path}},
        "projections": {cam: {"xy": Path, "xz": Path, "yz": Path}},
        "min_intensity": {cam: Path},
        "xml": {ch: Path},
    },
    "fusion": {method: {"dir": Path,
        "pairs": {(cam0, cam1, vw): {
            "fused": Path, "mask": Path, "fusion_mask": Path,
            "projections": {"xy": Path, "xz": Path, "yz": Path},
        }}}},
 }}}

# tiled mode
{"mode": "tiled", "root": Path,
 "tiles": {"SPM00": {<same as timepoint entry, plus "backgrounds">}}}

.stack Reading

Raw .stack is little-endian uint16, shape (D, H, W), memmappable. (W, H) from XML @dimensions[0]; D derived from file size (stat().st_size // 2 // (H*W)) — XML's D may be stale on aborted acquisitions.

isoview_config.json

Written next to data; tracks microscope params + every correction/fusion run.

{
  "paths": {"raw": str, "corrected": str},
  "microscope": {                   # from XML + ProcessingConfig
    "pixel_spacing_camera": 6.5, "pixel_spacing_xy": float, "pixel_spacing_z": float,
    "detection_objective_mag": float, "camera_view_map": {str: int}, "camera_pairs": [[int,int]],
    "wavelength", "exposure_time", "fps", "specimen_name",
  },
  "corrections": {"<label>": {"config_diff": {...}, "run": {"isoview_version",
                  "started_at", "completed_at", "elapsed_seconds", "status", "summary"}}},
  "fusions":     {"<label>/<blending>": {"config_diff": {...}, "run": {...}}},
}

Bootstrap from correction_run.json / fusion_run.json / *.fused/*/run.json via IsoviewConfig.from_directory(root).

Quickstart

  1. isoview init <path/to/raw> — scaffolds a scripts/ folder next to the raw data with correct_stack.py, multi_fuse.py, pipeline.ipynb, and parameters.md.
  2. Open scripts/ in VSCode and run correct_stack.py then multi_fuse.py, or open pipeline.ipynb and run both cells.
  3. Each step appends its config + isoview_version to isoview_config.json next to the data, so every run is reproducible.

See examples/compression_demo.py for a full end-to-end run on 10 timepoints. Full parameter reference: parameters.md.

Usage

Entrypoints: pipeline/correct_stack.py (correction) and pipeline/multi_fuse.py (fusion).

from pathlib import Path
from isoview import ProcessingConfig, correct_stack, multi_fuse

config = ProcessingConfig(
    input_dir=Path(r"E:\isoview\dataset"),
    # specimens=None,                       # auto-detect from SPC## in filenames
    # timepoints=None,                      # auto-detect from TM## in filenames
    corrected_suffix=".corrected",          # output folder suffix
    specimen=0,                             # default specimen index
    camera_pairs=[(0, 1), (2, 3)],          # ortho camera pairs to fuse

    # output
    output_format="tif",                    # tif, zarr, or klb
    compression="zstd",                     # zstd, lzw, deflate, or None
    compression_level=3,                    # 1-22 for zstd, 1-9 for others

    # transforms (applied to second camera in each pair)
    rotation=0,                             # 0=none, 1=90cw, -1=90ccw
    flip_horizontal=False,
    flip_vertical=False,

    # correction
    median_kernel=(3, 3),                   # dead pixel filter, None to disable
    background_percentile=5.0,
    mask_percentile=1.0,
    segment_mode=1,                         # 0=none, 1=segment+mask, 2=masks, 3=global

    # fusion
    blending_method="adaptive",             # adaptive, geometric, average, wavelet
    blending_range=20,                      # transition zone width (z-planes)

    # per-specimen overrides (tiled mode)
    # tile_crops={"SPM00": {"crop_depth": {0: 450}}}
    # view_orientation={"SPM00": {"flip_axis": 1}, "SPM01": {"flip_axis": 0}}
)

correct_stack(config)
multi_fuse(config)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

isoview-0.1.5.tar.gz (2.7 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

isoview-0.1.5-py3-none-any.whl (91.0 kB view details)

Uploaded Python 3

File details

Details for the file isoview-0.1.5.tar.gz.

File metadata

  • Download URL: isoview-0.1.5.tar.gz
  • Upload date:
  • Size: 2.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for isoview-0.1.5.tar.gz
Algorithm Hash digest
SHA256 389e64aee783825883962ffe5cb6c20f6fc582bfd5bfd406c0a4797c1dc4903d
MD5 7e8fa9a99d7ff8274197fbd15f1fcf51
BLAKE2b-256 ad1277a3d0fa3ab03c8d9bfc91e0c04b8bdebffa58ef0f6afee957c51c413f4a

See more details on using hashes here.

File details

Details for the file isoview-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: isoview-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 91.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for isoview-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 63152538f1aa6a6913e57a877f8f0277d66252b83ce2b1c6e819d3979d9218b7
MD5 58bcf7a4651645f92517addd4ee4e85d
BLAKE2b-256 37d1dfd298d62575fc2e7cca5002699c9a2ab8494d6acf4edf19d1f33f32731e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page