Releases: alxndrkalinin/cubic
Release list
v0.9.0a1 — repository-wide bug sweep (77 bugs)
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_correlationsread 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_ssimwrappeduint8arithmetic mod 256. Empty GLCM directions were averaged in as zeros, flipping a texture correlation's sign. - Even-shaped PSFs in
create_backprojectorwere wrong two independent ways: centered grids used(S-1)/2whereifftshiftputsS//2at DC (non-Hermitian mask,np.realdiscarding a large imaginary part), andf[::-1]mapsj → -j-1on 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_resolutionraisedIndexErrorunconditionally;Image.to_cpu()and cross-deviceto_same_devicerejected CuPy input;remove_touching_objectsfailed on every GPU and every 2-D array; the skimage proxy had no host fallback. - Input mutation.
richardson_lucy_xpdidimage *= mask, andimg_as_floatreturns 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_objects426× (5.0 s → 0.012 s),find_objects165×, 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) reportszasnanwhen 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
xyhas no floor guard of its own. spacing=Nonenow means cycles-per-pixel consistently betweenradial_edgesandradial_bin_id; previously it clipped every non-DC voxel into the last bin.ssimgainsnormalize, which it had silently ignored whilepsnrandnrmsehonoured 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_objectschangedsize_z <= min_zto< min_z, matching its docstring.min_zis defaulted, so every existing caller changes: atmin_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_ssimandspectral_pccreturnnanfor degenerate input, matchingpcc.clear_xy_bordersno longer relabels in 3-D, socellpose_segmentids can be gapped where they used to be contiguous.get_true_featuresno longer derives feature ranges from the ground truth whenfeature_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_splitsums consecutive Z pairs before splitting in Y/X, so both halves share their Z content exactly and FSC on the purek_zline is identically 1.0.axial_floor_factorcatches 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.0a1Full changelog: v0.8.0...v0.9.0a1
v0.8.0
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_cellposeis now the canonical GPU-resident entry point, supporting all four Cellpose v4 backbones (SAM + DINO).segment_cpsamis kept as a deprecated alias (emitsDeprecationWarning, slated for removal after 0.8). (#51)- Tunable tile size via a new
bsizeparameter (defaults 256 for SAM, 384 for DINO), centralized in_resolve_bsizewith cellpose's SAM→256 guard and non-positive-bsizevalidation. (#51)
Preprocessing — deconvolution
create_backprojector(cubic.preprocessing) — device-agnostic NumPy/CuPy port ofBackProjector.m, supportingtraditional,gaussian,butterworth,wiener, andwiener-butterworthtypes. (#52)backprojectortoggle onrichardson_lucy_xp, threaded throughdecon_xpy,richardson_lucy_iter, anddeconv_iter_num_finder. Faithful unmatched RL update (noH^T1, nocorrection<0clip, 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 shipscpsam_v2/cpdino). - New
cellpose-dinoextra for thedinov3dependency (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.0Full changelog: v0.7.0...v0.8.0
v0.8.0a2 — Wiener-Butterworth back projector for fast RL deconvolution
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 ofBackProjector.m:traditional,gaussian,butterworth,wiener,wiener-butterworth.backprojectortoggle onrichardson_lucy_xp, threaded throughdecon_xpy,richardson_lucy_iter, anddeconv_iter_num_finder. Faithful unmatched RL update (noH^T1, nocorrection<0clip, 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, fullpytest(397 passed) green.
Full Changelog: v0.8.0a1...v0.8.0a2
v0.8.0a1 — Cellpose v4 DINO model support
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 nowsegment_cellpose;segment_cpsamis kept as a deprecated alias (slated for removal after 0.8). - Tunable tile size:
segment_cellposeexposes absizeparameter (defaults to 256 for the SAM backbone, 384 for DINO), centralized in_resolve_bsizewith cellpose's SAM→256 guard and non-positive-bsizevalidation.
Packaging
- Require
cellpose>=4.2.0(the release that first shipscpsam_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
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
regionpropsextra_propertiesforwarding. - 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), withcompute_ssim_elements, an RI-factor solver (bracket + bisection on dS/dα), andimage_processinghelpers alpha_min/alpha_maxkwargs for MicroSSIM (#41)pcc(Pearson correlation coefficient)normalize='min_max'forpsnr/nrmse;spatial_dimsfor 5-D SSIM inputsreturn_ioupassthrough inaverage_precision
Feature extraction
- Device-agnostic GLCM texture features
extra_propertiesforwarded throughregionprops/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.isinfor numpy ≥2.2 (#43) average_precisioncounts distinct labelscrop_cornercorrectness 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)
Fixes
- GPU masked SSIM: move the erosion footprint onto the mask's device before
morphology.erosion.morphology.square/cubereceive only an int, so the device-agnostic proxy returned a host footprint; cuCIM'serosionrejected 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
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). Matchesskimage.feature.graycopropsto ≤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_tableextra_propertiespassthrough: forward user-definedfunc(regionmask, intensity)callables to skimage/cucim.- Fix:
regionprops_tablenow preserves requested property/column order deterministically (was hash-seed-dependent across process workers).
Full diff: #49
v0.7.0a11
Pre-release.
Features
average_precision(..., return_iou=True)— expose the object-overlap IoU matrix thataverage_precisionalready computes internally (viacompute_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_matchesgains@overloadsignatures so the(matches)vs(matches, iou)return is statically typed. Defaultreturn_iou=Falsepreserves the existing 4-tuple contract.
v0.7.0a10
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.ipynbnow auto-downloads both files viapoochwith sha256 verification on first run — no manual download step. Addsscripts/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
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 removednp.in1dtonp.isinfor NumPy ≥ 2.2 compatibility (#43).cleanup_segmentation: handle empty FOVs without asserting, and migrate off the deprecated skimagemin_size=parameter with backend-aware dispatch for cucim (#44).- FSC/FRC resolution: return
NaNinstead 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 v4CellposeModel(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()forplt.imshowon CuPy arrays. - 3D resolution notebook: refresh outputs with post-mean-center FSC values.