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

Output directory: {input_dir.name}{corrected_suffix} as sibling of input.

All below result path's use the default corrected_suffix .corrected.

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.corrected/Results/MultiFused_adaptive/SPM00/TM000000/ SPM00_TM000000_CM00_CM01_VW00.ome.tif
Tiled root.corrected/Results/MultiFused_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 / Results/*/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.4.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.4-py3-none-any.whl (91.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: isoview-0.1.4.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.4.tar.gz
Algorithm Hash digest
SHA256 b64954d43cacb3ae82fdb31369e58c005bcfaa394c68e5461fabb559a1ee3c5c
MD5 14beac428da8833f915ff8bd1f3e4680
BLAKE2b-256 ef95ce0cb5d5d542ecde966155942f17738f069263085b21bc061921d620316b

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for isoview-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 db789e74aa7d019e7293c2d2455abf3e30bc67083f2a8c9ca5613ea4a5869256
MD5 f5e6b92349261f388865f6f5d5186114
BLAKE2b-256 c09a7bb98cf13bd31acf3c09d83a38b99dd3e8aa54faeaaa85b028d520083c5b

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