Skip to content

Releases: alxndrkalinin/cubic

v0.9.0a1 — repository-wide bug sweep (77 bugs)

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 30 Jul 01:15

First pre-release of the 0.9 series. Repository-wide bug sweep: 77 bugs fixed across all seven modules, plus stale-code removal, simplification, and tooling changes. Test suite 401 → 791 passing.

Shipped as an alpha rather than 0.9.0 final: several fixes change previously-returned numbers, ~24 public symbols are gone, and two correctness questions in the single-image FRC/FSC split are still open (see Known issues). pip install cubic continues to resolve 0.8.0 until 0.9.0 ships.

Highlights

  • Silently-wrong results fixed. The worst class in the sweep: functions that returned plausible numbers instead of failing, so no test caught them. morphology_correlations read true-vs-true entries and never touched the prediction (identical inputs scored 0.921 instead of 1.0). Sectioned FSC reported 0.1225 µm at 0.13 µm sampling — below the physical floor. Every binomial FRC returned NaN. ms_ssim wrapped uint8 arithmetic mod 256. Empty GLCM directions were averaged in as zeros, flipping a texture correlation's sign.
  • Even-shaped PSFs in create_backprojector were wrong two independent ways: centered grids used (S-1)/2 where ifftshift puts S//2 at DC (non-Hermitian mask, np.real discarding a large imaginary part), and f[::-1] maps j → -j-1 on even axes so the flipped PSF was not the conjugate OTF. Imaginary leakage 5.32e-1 → 1.46e-17. Odd shapes stay bit-identical to the reference.
  • Code that had never worked: five_crop_resolution/grid_crop_resolution raised IndexError unconditionally; Image.to_cpu() and cross-device to_same_device rejected CuPy input; remove_touching_objects failed on every GPU and every 2-D array; the skimage proxy had no host fallback.
  • Input mutation. richardson_lucy_xp did image *= mask, and img_as_float returns the same object for float input, so it destroyed the caller's array. Same class of bug in five other functions.
  • Performance, all byte-identical: remove_touching_objects 426× (5.0 s → 0.012 s), find_objects 165×, mesh extraction 11×, GLCM peak GPU pool 7.5× smaller (3.95 GB → 0.53 GB at 256³).

Resolution metrics

  • Sectioned FSC now projects a sector's shell radius onto Z rather than reporting it as an axial period, and uses the Koho et al. (2019) eq. (5) correction on isotropically resampled input. Reproduces the paper's Fig. 4b pollen stack at XY 0.586 µm / Z 4.38 µm against a published 0.59 / 3.91.
  • New axial_floor_factor (default 2.0) reports z as nan when the result falls below the pre-resampling axial Nyquist limit.
  • The one-image checkerboard calibration factor is clamped at 1.0. The Koho fit is an exponential centred on 0.98 that passes 1.0 at a crossing of ~0.925 and reaches 1.82 at the band edge, so a near-Nyquist crossing was reported up to 45% below the sampling limit — in both directions, and xy has no floor guard of its own.
  • spacing=None now means cycles-per-pixel consistently between radial_edges and radial_bin_id; previously it clipped every non-DC voxel into the last bin.
  • ssim gains normalize, which it had silently ignored while psnr and nrmse honoured it.

Breaking changes

This is not a patch release. ~24 removed public symbols, 13 signatures with a parameter removed, mask now keyword-only on pcc/nrmse/psnr/ssim, extract_features returning three values, clahe(kernel_size→n_tiles), and ~14 inputs that were previously accepted and now raise. The cubic.metrics.frc shims are gone.

Fixes that change previously-returned numbers — re-running an analysis will not reproduce prior values:

  • remove_thin_objects changed size_z <= min_z to < min_z, matching its docstring. min_z is defaulted, so every existing caller changes: at min_z=2, objects spanning 1/2/3/4 Z planes went from keeping {3,4} to keeping {2,3,4}.
  • band_limited_pcc, band_limited_ssim and spectral_pcc return nan for degenerate input, matching pcc.
  • clear_xy_borders no longer relabels in 3-D, so cellpose_segment ids can be gapped where they used to be contiguous.
  • get_true_features no longer derives feature ranges from the ground truth when feature_ranges is None — the old path normalized the true side but not the prediction.

Tooling

ruff selected only D and I, so pyflakes never ran and unused imports had accumulated; now ["D", "F", "I"]. rtree added to the mesh extra — extract_mesh_features raised ModuleNotFoundError for anyone following the documented install.

Known issues

  • Single-image checkerboard split is optimistic. Against a synthetic known band limit, two-image FRC is accurate to 1–2% but the checkerboard split reads ~20% too fine, and it collapses once the true limit approaches the split halves' Nyquist — which is half the image's, since the halves are 2× coarser per axis. On interpolated input it is far worse: 0.68× after a subpixel shift, 0.35× after a Gaussian smooth, and no threshold crossing at all after 2× upsampling. The binomial split (split_type="binomial") tracks the two-image reference to ~3% in all of those cases and is the better choice wherever photon counts are available; it is not reliable on deskewed/upsampled data either (0.40×).
  • Near-axis sectioned FSC does not decorrelate. With the default disable_3d_sum=False, checkerboard_split sums consecutive Z pairs before splitting in Y/X, so both halves share their Z content exactly and FSC on the pure k_z line is identically 1.0. axial_floor_factor catches the downstream symptom; the split geometry is the cause.

Numbers above were measured against scikit-image 0.26.0, while CI resolves 0.25.2. The library handles both, but DCR curve shapes differ enough between them that one test asserts a version-independent invariant instead of a fixture-specific value.

Install

pip install cubic==0.9.0a1

Full changelog: v0.8.0...v0.9.0a1

v0.8.0

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 24 Jul 01:07

First stable release of the 0.8 series, consolidating the two v0.8.0 alpha pre-releases (v0.8.0a1–a2). 5 commits since v0.7.0.

Highlights

  • Cellpose v4 DINO support — the GPU-resident segmentation path now covers all four v4 models: the SAM backbones (cpsam, cpsam_v2) and the DINOv3 backbones (cpdino, cpdino-vitb).
  • Wiener-Butterworth back projector for Richardson-Lucy deconvolution — converges in ~1–2 iterations instead of 10–50 (Guo et al. 2020), with the matched path byte-for-byte unchanged by default.

New features

Segmentation

  • segment_cellpose is now the canonical GPU-resident entry point, supporting all four Cellpose v4 backbones (SAM + DINO). segment_cpsam is kept as a deprecated alias (emits DeprecationWarning, slated for removal after 0.8). (#51)
  • Tunable tile size via a new bsize parameter (defaults 256 for SAM, 384 for DINO), centralized in _resolve_bsize with cellpose's SAM→256 guard and non-positive-bsize validation. (#51)

Preprocessing — deconvolution

  • create_backprojector (cubic.preprocessing) — device-agnostic NumPy/CuPy port of BackProjector.m, supporting traditional, gaussian, butterworth, wiener, and wiener-butterworth types. (#52)
  • backprojector toggle on richardson_lucy_xp, threaded through decon_xpy, richardson_lucy_iter, and deconv_iter_num_finder. Faithful unmatched RL update (no H^T1, no correction<0 clip, estimate floored at 1e-3, both projectors sum-normalized); circulant only, and the default (None) leaves the matched path unchanged. (#52)

Packaging

  • Require cellpose>=4.2.0 (the release that first ships cpsam_v2/cpdino).
  • New cellpose-dino extra for the dinov3 dependency (pip install cubic[cellpose-dino]).

Docs & examples

  • New notebook deconvolution_wb_backprojector_3d.ipynb — matched-vs-WB convergence by PSNR/SSIM and absolute FSC resolution (+ paired script + README row).
  • 3D feature-extraction notebook gains a CPU-vs-GPU comparison.

Install

pip install cubic==0.8.0

Full changelog: v0.7.0...v0.8.0

v0.8.0a2 — Wiener-Butterworth back projector for fast RL deconvolution

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 19 Jun 05:37

Adds an unmatched Wiener-Butterworth (WB) back projector to Richardson-Lucy deconvolution (Guo et al. 2020, Nat. Biotechnol. 38:1337), converging in ~1–2 iterations instead of 10–50. The matched path is byte-for-byte unchanged by default.

Highlights

  • create_backprojector (cubic.preprocessing) — device-agnostic NumPy/CuPy port of BackProjector.m: traditional, gaussian, butterworth, wiener, wiener-butterworth.
  • backprojector toggle on richardson_lucy_xp, threaded through decon_xpy, richardson_lucy_iter, and deconv_iter_num_finder. Faithful unmatched RL update (no H^T1, no correction<0 clip, estimate floored at 1e-3, both projectors sum-normalized); circulant only.
  • Example notebook deconvolution_wb_backprojector_3d.ipynb (+ paired script + README row).

Validation

  • Matched path byte-exact vs pre-change on CPU/GPU; CPU/GPU parity for the WB path ≤ 4e-8.
  • On real astrocyte data (A40 GPU): WB@2 reaches matched@~10 quality with sharper absolute FSC resolution.
  • ruff, ruff format, mypy, full pytest (397 passed) green.

Full Changelog: v0.8.0a1...v0.8.0a2

v0.8.0a1 — Cellpose v4 DINO model support

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 15 Jun 21:44
6dbf90e

Features

  • Cellpose v4 DINO models: the GPU-resident segmentation path now supports all four Cellpose v4 models — the SAM backbones (cpsam, cpsam_v2) and the DINOv3 backbones (cpdino, cpdino-vitb). The canonical entry point is now segment_cellpose; segment_cpsam is kept as a deprecated alias (slated for removal after 0.8).
  • Tunable tile size: segment_cellpose exposes a bsize parameter (defaults to 256 for the SAM backbone, 384 for DINO), centralized in _resolve_bsize with cellpose's SAM→256 guard and non-positive-bsize validation.

Packaging

  • Require cellpose>=4.2.0 (the release that first ships cpsam_v2/cpdino).
  • The DINO backbones additionally require dinov3, which is published only on GitHub: pip install git+https://github.com/facebookresearch/dinov3.

Notes

  • Resident masks match stock CellposeModel.eval (AP@0.5 ≥ 0.95) for all four models in 2D and 3D.

Full changes in #51.

v0.7.0

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 12 Jun 16:45

First stable release of the 0.7 series, consolidating work from 13 alpha pre-releases (v0.7.0a1–a13). 79 commits since v0.6.0.

Highlights

  • Expanded cubic.metrics — a full device-agnostic metrics suite: resolution (FRC/FSC/DCR, band-limited), image quality (PSNR, SSIM, MS-SSIM, MicroSSIM/MicroMS3IM), and Pearson correlation (PCC).
  • GPU-resident Cellpose-SAM segmentation with the v4 API.
  • Device-agnostic GLCM texture features and regionprops extra_properties forwarding.
  • torch interop in the device layer — zero-copy CUDA↔CuPy bridging.

New features

Metrics — resolution

  • DCR, histogram FSC, and band-limited metrics (#32)
  • Binomial splitting for single-image FRC/FSC (#40)

Metrics — image quality

  • MicroSSIM / MicroMS3IM port and a general-purpose ms_ssim (Wang 2003, torchmetrics-compatible), with compute_ssim_elements, an RI-factor solver (bracket + bisection on dS/dα), and image_processing helpers
  • alpha_min / alpha_max kwargs for MicroSSIM (#41)
  • pcc (Pearson correlation coefficient)
  • normalize='min_max' for psnr/nrmse; spatial_dims for 5-D SSIM inputs
  • return_iou passthrough in average_precision

Feature extraction

  • Device-agnostic GLCM texture features
  • extra_properties forwarded through regionprops / regionprops_table

Segmentation

  • GPU-resident Cellpose-SAM eval + v4 API migration (#46)

Device layer & examples

  • torch tensors recognized in asnumpy / get_device; CUDA tensors route to CuPy (zero-copy)
  • Shared device-routing helpers across the scipy/skimage proxies; proxies now scan all args for device
  • Segmentation & feature-extraction example notebooks (#33); Zenodo + pooch auto-download for example data (#48)

Notable fixes

  • SSIM mask footprint moved to the mask's device for cuCIM erosion (GPU per-cell SSIM)
  • FSC/FRC: mean-center before Hamming window (#42); return NaN when the curve never legitimately crosses threshold (#45); honor use_max_nyquist
  • Segmentation: handle empty FOVs, migrate off deprecated skimage min_size= (#44); np.isin for numpy ≥2.2 (#43)
  • average_precision counts distinct labels
  • crop_corner correctness for single-axis and bottom-right crops
  • Rank-agnostic deconvolution slicing with a faithful observer path
  • GLCM: float64 counts, empty-pair directions on CuPy, distance validation

Install

```bash
pip install cubic==0.7.0
```

Full changelog: v0.6.0...v0.7.0

v0.7.0a13 — fix GPU masked SSIM (cuCIM erosion footprint device)

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 11 Jun 05:29

Fixes

  • GPU masked SSIM: move the erosion footprint onto the mask's device before morphology.erosion. morphology.square/cube receive only an int, so the device-agnostic proxy returned a host footprint; cuCIM's erosion rejected a NumPy footprint paired with a GPU mask (footprint must be either an ndarray or Sequence). Per-cell SSIM now runs on GPU. (1cd5f08)

Full changelog: v0.7.0a12...v0.7.0a13

v0.7.0a12

v0.7.0a12 Pre-release
Pre-release

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 05 Jun 20:39

Alpha release adding device-agnostic texture features for the dynacell CP feature track.

Highlights

  • cubic.feature.glcm_features (new): device-agnostic Haralick GLCM texture features for 2D (H, W) and 3D (D, H, W) images (NumPy + CuPy). Matches skimage.feature.graycoprops to ≤1e-9 on the seven properties (contrast, dissimilarity, homogeneity, ASM, energy, correlation, entropy), with per-image scale-invariant quantization, an optional foreground mask, and robust handling of empty-pair directions on CuPy.
  • regionprops / regionprops_table extra_properties passthrough: forward user-defined func(regionmask, intensity) callables to skimage/cucim.
  • Fix: regionprops_table now preserves requested property/column order deterministically (was hash-seed-dependent across process workers).

Full diff: #49

v0.7.0a11

v0.7.0a11 Pre-release
Pre-release

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 04 Jun 00:50

Pre-release.

Features

  • average_precision(..., return_iou=True) — expose the object-overlap IoU matrix that average_precision already computes internally (via compute_matches) as an optional fifth return element. Lets a caller that also needs a Dice/overlap metric reuse the single overlap pass instead of recomputing it. compute_matches gains @overload signatures so the (matches) vs (matches, iou) return is statically typed. Default return_iou=False preserves the existing 4-tuple contract.

v0.7.0a10

v0.7.0a10 Pre-release
Pre-release

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 02 Jun 22:57

Pre-release.

Examples / data

  • Deconvolution example data moved to Zenodo (#48). The dead Google Drive links for the 3D astrocyte stack and theoretical PSF are replaced by a CC-BY-4.0 Zenodo deposit (10.5281/zenodo.20514102). deconvolution_iterations_3d.ipynb now auto-downloads both files via pooch with sha256 verification on first run — no manual download step. Adds scripts/zenodo_upload.py + metadata for republishing future example datasets.
  • Re-executed the deconvolution notebook from a clean GPU kernel; all reported resolution values unchanged (PSNR iter 35, SSIM iter 37, FSC iter 41, DCR XY 919→785 nm / Z 974→874 nm).

Closes #47.

v0.7.0a9

v0.7.0a9 Pre-release
Pre-release

Choose a tag to compare

@alxndrkalinin alxndrkalinin released this 01 Jun 23:38

Pre-release.

Fixes

  • FRC/FSC preprocessing: mean-center images before the Hamming window and before cube-padding to remove the DC × window artifact at low frequencies (#42).
  • clear_border: switch from removed np.in1d to np.isin for NumPy ≥ 2.2 compatibility (#43).
  • cleanup_segmentation: handle empty FOVs without asserting, and migrate off the deprecated skimage min_size= parameter with backend-aware dispatch for cucim (#44).
  • FSC/FRC resolution: return NaN instead of a spurious value (e.g. Nyquist or wildly large numbers from unbounded spline extrapolation) when the correlation curve never legitimately crosses the threshold (#45).

Features

  • GPU-resident Cellpose-SAM evaluation (segment_cpsam): migrate the Cellpose wrapper to the v4 CellposeModel (SAM) API, add a GPU-resident eval that avoids host round-trips, port tile-norm + sharpen normalization to the GPU path, fall back to CPU flow-QC on very large masks, and add 3D + stitch parity tests (#46).

Examples

  • 2D resolution notebook: use asnumpy() for plt.imshow on CuPy arrays.
  • 3D resolution notebook: refresh outputs with post-mean-center FSC values.