Multi-view light sheet microscopy image processing pipeline
Project description
Isoview Pipeline: MATLAB -> Python
Conversion/Validation TODO
- readKLB.m
- clusterPT_RC.m
- clusterPT with zarr benchmarks
- clusterMF.m
Note: Multiprocessing is not yet implemented, as it is in the MATLAB pipeline.
readKLB.m -> pyklb
Using our fork of pyklb, on pypi.
1. Generate MATLAB Reference
matlab -batch \
"run('C://Users//RBO//repos//isoview//excludes//save_matlab_klb.m')"
2. Validate with Python
uv run --no-sync python excludes/test_klb_matlab_python.py
| File | MATLAB Shape | Python Shape | Max Diff |
|---|---|---|---|
| SPM00_TM000000_CM00_CHN00.klb | (2048, 2048, 543) | (543, 2048, 2048) -> (2048, 2048, 543) | 0.0 |
| SPM00_TM000000_CM01_CHN00.klb | (2048, 2048, 543) | (543, 2048, 2048) -> (2048, 2048, 543) | 0.0 |
| SPM00_TM000000_CM02_CHN01.klb | (2048, 2048, 592) | (592, 2048, 2048) -> (2048, 2048, 592) | 0.0 |
| SPM00_TM000000_CM03_CHN01.klb | (2048, 2048, 592) | (592, 2048, 2048) -> (2048, 2048, 592) | 0.0 |
Total: 4/4 files exactly equal (100%)
- MATLAB: Stores volumes as
(Y, X, Z)=(2048, 2048, 543/592) - Python pyklb: Returns volumes as
(Z, Y, X)=(543/592, 2048, 2048)
clusterPT_RC.m
D:\W2_DATA\foconnell\isoview_development\mosquito-larva_20250930_165806.corrected\SPM00\TM000000
File structure
project_root\
SPM00\
Background_0.tif (one per camera)
Background_1.tif
Background_2.tif
Background_3.tif
TM00000\ (one folder per timepoint)
ch0.xml (rename from ch00_spec00.xml)
ch1.xml (rename from ch01_spec00.xml)
ANG000\
SPC00_TM00000_ANG000_CM0_CHN00_PH0.stack
SPC00_TM00000_ANG000_CM1_CHN00_PH0.stack
SPC00_TM00000_ANG000_CM2_CHN01_PH0.stack
SPC00_TM00000_ANG000_CM3_CHN01_PH0.stack
inputFolder = 'D:\W2_DATA\foconnell\isoview_development\mosquito-larva_20250930_165806';
inputType = 2;
specimen = 0;
% Run 1: Cameras 0,1 with Channel 0
cameras = [0 1];
channels = 0;
% Run 2: Cameras 2,3 with Channel 1
cameras = [2 3];
channels = 1;
- Background TIFFs: Place in SPM00 root (one per camera)
- XML files: Rename ch00_spec00.xml to ch0.xml, ch01_spec00.xml to ch1.xml
- XML files: Copy to each TM folder (TM00000, TM00001, etc.)
Comparison
See the full notebook here
Most of the differences happen in the non-dense regions on the edge of the FOV:
clusterMF.m
Multi-view fusion pipeline. Python implementation in isoview/fusion.py.
MATLAB equivalent
inputFolder = 'D:\W2_DATA\foconnell\isoview_development\mosquito-larva_20250930_165806.corrected_python_zarr';
specimen = 0;
timepoints = 0;
cameras = [0 1 2 3];
channels = [0 1];
% Fusion parameters
fusionType = 1; % adaptive blending
blendingRange = [20 4]; % [channel, camera]
cameraPairs = [0 1; 2 3];
flipH = true;
flipV = false;
Python equivalent
from isoview import ProcessingConfig, fuse
config = ProcessingConfig(
input_dir=Path("D:/W2_DATA/.../mosquito-larva_20250930_165806.corrected_python_zarr"),
output_dir=Path("D:/W2_DATA/.../mosquito-larva_20250930_165806.corrected_python_zarr"),
specimen=0,
timepoints=[0],
cameras=[0, 1, 2, 3],
channels=[0, 1],
fusion_enable=True,
fusion_type="adaptive_blending",
fusion_blending_range=(20, 4),
fusion_camera_pairs=[(0, 1), (2, 3)],
fusion_flip_h=True,
fusion_flip_v=False,
)
fuse(config, estimate_params=True, apply_fusion=True)
Feature Flags
All MATLAB clusterMF features are available as config flags (disabled by default):
| Feature | MATLAB | Python Flag |
|---|---|---|
| Temporal smoothing | rloess | fusion_temporal_smoothing=True |
| Smoothing window | smoothingRange | fusion_smoothing_window=100 |
| Static parameters | staticFlag | fusion_static=True |
| Mask fusion mode | maskFusionMode | fusion_mask_fusion_mode=1 |
| Mask padding | padding | fusion_mask_padding=2 |
| Small object removal | bwareaopen | fusion_mask_min_object_size=1e-5 |
| Slab processing | slabSize | fusion_slab_size_cameras=3 |
| Median filtering | medianFilterRange | fusion_median_filter_range=100 |
| Gaussian precision | preciseGauss | fusion_precise_gauss=True |
| Lookup tables | generateLUT | fusion_generate_lookup_table=True |
See MATLAB_FEATURES.md for complete documentation.
Diagnostic Output
Pipeline generates diagnostic PNGs when save_diagnostics=True (default):
output_dir/
diagnostics/
TM000000/
cam0_1/
registration.png
intensity_correction.png
fusion_result.png
blending_weights.png
fused_overview.png
Zarr I/O Integration and Benchmarks
Dataset Parameters
- Data volume: (543, 2048, 2048) uint16
- Uncompressed size: 4344.00 MB (4.242 GB)
- Pixel spacing: [2.0, 0.406, 0.406] um
- Chunk size: (10, 128, 128)
Quick Compression Performance
Based on a single raw .stack from a mosquito recorded on isoview: mosquito-larva_20250930_165806
| Method | Compression | Level | Write (s) | Read (s) | Size (MB) | Ratio | Write Speed (GB/s) | Read Speed (GB/s) |
|---|---|---|---|---|---|---|---|---|
| blosc-zstd-5-sharded | blosc-zstd | 5 | 42.71 | 2.55 | 1780.3 | 2.44x | 0.099 | 1.663 |
| blosc-zstd-9-sharded | blosc-zstd | 9 | 52.96 | 2.52 | 1679.5 | 2.59x | 0.080 | 1.682 |
| blosc-lz4-3-sharded | blosc-lz4 | 3 | 40.12 | 2.50 | 2205.0 | 1.97x | 0.106 | 1.698 |
| blosc-zstd-5-no-shard | blosc-zstd | 5 | 44.99 | 2.25 | 1780.3 | 2.44x | 0.094 | 1.887 |
| blosc-lz4-3-no-shard | blosc-lz4 | 3 | 44.01 | 2.50 | 2205.0 | 1.97x | 0.096 | 1.698 |
| none-sharded | none | 0 | 45.34 | 2.28 | 4344.0 | 1.00x | 0.094 | 1.863 |
| none-no-shard | none | 0 | 52.18 | 1.90 | 4344.0 | 1.00x | 0.081 | 2.237 |
Pipeline Compression Performance
Now, instead of converting a .stack, we run the full clusterPT pipeline and compare .tiff, .klb and .zarr.
From the KLB source code (keller-lab-block-filetype/src/klb_imageIO.cpp):
int BWTblockSize = 9; // maximum compression
// compress the memory buffer (blocksize=9*100k, verbose=0, worklevel=30)
int ret = BZ2_bzBuffToBuffCompress(bufferOutPtr, &sizeCompressed,
bufferIn, gcount, BWTblockSize, 0, 30);
KLB uses bzip2 with level 9 (block size 9x100k = 900,000 bytes)
Testing 11 configurations:
Baselines:
KLB_bzip2_9 - KLB format with bzip2, level 9 (block size 9x100k)
TIFF_uncompressed - Uncompressed TIFF for size reference
Zarr configurations (all with sharding: 10 frames/shard, 1 frame/chunk, full FOV):
Zarr_bzip2_9 - bzip2 level 9 (match KLB)
Zarr_zstd_6 - blosc-zstd at level 6
Zarr_zstd_9 - blosc-zstd at level 9
Zarr_lz4_6 - blosc-lz4 at level 6
Zarr_lz4_9 - blosc-lz4 at level 9
Zarr_lz4hc_6 - blosc-lz4hc at level 6
Zarr_lz4hc_9 - blosc-lz4hc at level 9
Zarr_gzip_6 - gzip at level 6
Zarr_gzip_9 - gzip at level 9
Compression Benchmark Results
Tested on dataset: (543, 2048, 2048) uint16, ~4.24 GB uncompressed
| Format | Compression | Level | Size (MB) | Ratio | vs Uncompressed |
|---|---|---|---|---|---|
| KLB_bzip2_9 | bzip2 | 9 | 1107.99 | 3.92x | 74.5% reduction |
| Zarr_bzip2_9 | bzip2 | 9 | 1127.56 | 3.85x | 74.0% reduction |
| Zarr_zstd_9 | blosc-zstd | 9 | 1255.15 | 3.46x | 71.1% reduction |
| Zarr_zstd_6 | blosc-zstd | 6 | 1297.95 | 3.35x | 70.1% reduction |
| Zarr_lz4hc_9 | blosc-lz4hc | 9 | 1332.07 | 3.26x | 69.3% reduction |
| Zarr_lz4hc_6 | blosc-lz4hc | 6 | 1337.21 | 3.25x | 69.2% reduction |
| Zarr_gzip_9 | gzip | 9 | 1434.98 | 3.03x | 67.0% reduction |
| Zarr_gzip_6 | gzip | 6 | 1457.96 | 2.98x | 66.4% reduction |
| Zarr_lz4_9 | blosc-lz4 | 9 | 1517.57 | 2.86x | 65.1% reduction |
| Zarr_lz4_6 | blosc-lz4 | 6 | 1519.42 | 2.86x | 65.0% reduction |
| TIFF_uncompressed | none | - | 4344.13 | 1.00x | - |
Module Overview
Core Pipeline
| Module | Description | Key Functions |
|---|---|---|
pipeline.py |
Main processing orchestrator | IsoviewProcessor, process_dataset() |
config.py |
All configuration flags | ProcessingConfig dataclass |
io.py |
File I/O (klb, tiff, zarr, stack) | read_volume(), write_volume(), read_xml_metadata() |
array.py |
Lazy loader for processed data | IsoviewArray class |
Image Processing
| Module | Description | Key Functions |
|---|---|---|
corrections.py |
Dead pixel detection/correction | correct_dead_pixels(), estimate_background() |
segmentation.py |
Foreground segmentation | segment_foreground(), fuse_masks(), create_coordinate_masks() |
transforms.py |
Geometric transforms | rotate_volume(), flip_volume(), crop_volume(), estimate_registration(), apply_registration() |
Fusion Pipeline
| Module | Description | Key Functions |
|---|---|---|
fusion.py |
Multi-view fusion | fuse(), blend_views() |
temporal.py |
Temporal parameter processing | smooth_parameters_rloess(), apply_temporal_averaging(), create_lookup_table() |
masks.py |
Mask processing for fusion | combine_masks(), pad_mask_to_center(), apply_bwareaopen() |
intensity.py |
Intensity correction/filtering | apply_median_filter(), apply_gauss_filter() |
Utilities
| Module | Description | Key Functions |
|---|---|---|
viz.py |
Diagnostic visualization | plot_projections(), plot_registration_result(), plot_fusion_result(), plot_volume_overview() |
Public API
from isoview import (
ProcessingConfig, # configuration dataclass
IsoviewProcessor, # main processor class
process_dataset, # process clusterPT pipeline
fuse, # run clusterMF fusion
blend_views, # blend two registered views
temporal, # temporal processing submodule
viz, # visualization submodule
)
IsoviewArray
Lazy loader for processed data with napari/visualization tool compatibility:
from isoview.array import IsoviewArray
arr = IsoviewArray("path/to/output/TM000000")
# Shape: (Z, Views, Y, X) for single timepoint
# Shape: (T, Z, Views, Y, X) for multi-timepoint
print(arr.shape) # (543, 4, 2048, 2048)
print(arr.views) # [(0, 0), (1, 0), (2, 1), (3, 1)]
print(arr.metadata) # microscope metadata dict
# Lazy indexing
frame = arr[100, 0] # single Z-slice, first view
volume = arr[:, 0] # full Z-stack, first view
# Access labels/projections (consolidated structure)
mask = arr.get_labels(timepoint=0, camera=0, label_type='segmentation')
proj = arr.get_projection(timepoint=0, camera=0, proj_type='xy')
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file isoview-0.1.0.tar.gz.
File metadata
- Download URL: isoview-0.1.0.tar.gz
- Upload date:
- Size: 2.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb2467b9efb886d7262d1c671ef8aa13a490df4930cd20d3ca43e53722926e9b
|
|
| MD5 |
0c5fa9480a9fe8c4e0f7a04565279d48
|
|
| BLAKE2b-256 |
7155ffa1313a9bbaf022c6f4c0301e1cb1838e48c74da077bc6a60d9a7cc7aad
|
File details
Details for the file isoview-0.1.0-py3-none-any.whl.
File metadata
- Download URL: isoview-0.1.0-py3-none-any.whl
- Upload date:
- Size: 56.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a9c2114ec747abeb65629ed2fde4f15210d553b6cb8d888952ce29e226efc306
|
|
| MD5 |
9b67e3d30217b31dc245a473e0c0c2b1
|
|
| BLAKE2b-256 |
f72147b439349270f804d17f8a47a9dc295ddda74a831b3c44257ebf47994405
|