-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Summary
Add a format‑aware image export pipeline that lets users configure how image data are normalized, cast, and written, with options that adapt to the chosen file format (PNG, TIFF, JPEG/JP2, NPY, …).
Scope includes:
- A new Export Image dialog in DataLab (format‑specific UI).
- Backend support in Sigima (
sigima.io) to prepare data (normalize/clip/cast) and to pass format constraints. - An optional graphical preview showing the image as it would be exported (write to a temp file, reload, display).
Motivation
Currently, ClassicsImageFormat (see sigima/io/image/formats.py) hard‑casts to uint8 for BMP/JPEG/PNG and to uint8/uint16 for JPEG2000 before calling skimage.io.imsave, without normalization. When the source array is float or spans a wide dynamic range, this causes unexpected clipping or loss. Scientific formats (NPY, some TIFF) can keep raw data but there is no unified way to choose behavior from DataLab.
We want:
- Predictable exports (explicit normalization and dtype choice).
- Format‑aware UI (only relevant options per selected format).
- A clean backend API so DataLab delegates to Sigima.
DataLab – Export dialog (format‑aware)
The dialog dynamically shows options relevant to the chosen format:
Data → Normalization
- Mode:
None/Min–Max/Percentile (p_low–p_high)/Manual (range_min–range_max) - Behavior:
ClipvsRescale - NaN/Inf policy:
error/clip/replace(with replacement value) - Optional:
Gamma(apply before/after scaling),Invert
Data → Target dtype
- If supported by the format:
uint8,uint16,float32,float64, …
Format‑specific options (progressive rollout)
- PNG: compression level
- JPEG: quality
- TIFF: compression (
none,LZW,Deflate,JPEG), bit depth (8/16/32F), multi‑page - JP2: bit depth (8/16)
- NPY: raw export (no normalization) or explicit normalization if requested
Metadata
- Include DataLab/Sigima metadata (embed if supported, or sidecar JSON).
Batch / stack export
- Single image, stack to multi‑page TIFF, or sequence with naming pattern.
Preview (optional but recommended)
- Button to render a graphical preview by exporting to a temporary file using current settings, reopening it, and displaying the exact result. This removes ambiguity vs. “report‑only” approaches.
Sigima – Backend API (non‑breaking)
To keep the public API stable, extend the existing function:
# sigima/io/__init__.py
def write_image(filename: str, image: ImageObj, param: ImageExportParam | None = None) -> None:
...
- If
param is None, behavior is unchanged (backward compatible). - If
paramis provided, data are prepared (normalize/clip/cast) before delegating to the format writer.
New parameter class
Introduce a format-aware export preparation layer so the UI can pass one object describing export choices:
- New parameter object (DataSet)
ImageExportParam:normalization_mode: Enum('none', 'minmax', 'percentile', 'manual')range_min: float | None,range_max: float | None(manual)percentile_low: float,percentile_high: floatscale_behavior: Enum('clip', 'rescale')target_dtype: np.dtype | str | Nonenan_policy: Enum('error', 'clip', 'replace')nan_replacement: float | Nonegamma: float | Noneinvert: boolformat_options: dict[str, Any](passed through to the writer when supported; e.g.quality,compress_level,compression)
Export preparation
# sigima/io/image/export.py
def prepare_image_for_export(data: np.ndarray, ext: str, param: ImageExportParam) -> np.ndarray:
"""
Applies normalization/range policy, gamma/invert, dtype casting, and
enforces per‑format constraints (e.g. PNG/JPEG require uint8, JP2 allows uint8/uint16, TIFF allows 8/16/32F, NPY any).
Returns the final array ready for writing.
"""
Write path (no API break)
Implementation sketch in sigima/io/__init__.py:
- Resolve format via
ImageIORegistry.get_format(filename, IOAction.SAVE). - If
param is not None:data2 = prepare_image_for_export(image.data, ext, param)- Create a shallow copy of
imagewithdata2(to preserve metadata). - Delegate to the resolved format’s
write(...)(unchanged signature).
- Else: current behavior (call registry
writedirectly).
Note: For phase 1, we focus on normalization/dtype (which can be handled entirely in
prepare_image_for_export).
Phase 2 will add optional propagation ofparam.format_options(e.g., TIFF compression, JPEG quality, PNG compress level). That may require small refactors in concretewrite_data(...)implementations to accept and forward writer kwargs. This can be done incrementally per format without breaking the public API.
Per‑format rules (enforced in preparation)
- PNG/JPEG: require
uint8. Ifparam.normalization_mode == 'none'and input isn’tuint8, either error or auto min–max (configurable project default). - JP2: allow
uint8oruint16; normalize/cast accordingly. - TIFF: support
uint8/uint16/float32(andfloat64where supported). - NPY: raw by default; if
paramrequests normalization or dtype change, apply then save.
Preview design (DataLab)
- “Preview” button in the dialog:
- Calls
write_image(tempfile, image, param)→ reopens → displays. - Shows the actual exported result for maximum clarity.
- Cleans up temp files automatically.
- Calls
Testing
Sigima (unit tests):
- Synthetic ramps/patterns with float → PNG/JPEG (
uint8min–max and percentile). - Wide dynamic range float → TIFF as
float32(raw) vsuint16(scaled). - JP2: verify
uint8vsuint16. - Edge cases: NaN/Inf handling, manual range, gamma, invert, clip vs rescale.
DataLab (integration/UI tests):
- Option enable/disable by format.
- Preview renders exactly what the export produces (temp file round‑trip).
Open questions
- Default policy when exporting non‑
uint8to 8‑bit formats:- strict (error) vs permissive (auto min–max). Propose a global config default and a clear notice in the dialog.
- Rollout strategy for format_options (TIFF compression, JPEG quality, PNG compress level): per‑format incremental support in phase 2.
Benefits
- Predictable, format‑appropriate results; less accidental data loss.
- A single extensible dialog in DataLab rather than ad‑hoc prompts.
- Clear separation of concerns: UI declares intent; Sigima prepares data and enforces constraints; writers remain stable.