Detection and quantification of biomolecular condensates in confocal
microscopy, built for PDIA6 / endoplasmic-reticulum liquid–liquid phase
separation: Olympus .oir → lossless 16-bit TIFF → condensate detection →
per-cell counts, sizes and IN/OUT intensity ratios.
Every parameter is a physical quantity — micrometres, sigmas above background — never a grey level or a fraction of the image's own maximum, so a setting means the same thing on a bright field and a dim one.
conda env create -f environment.yml && conda activate demixs
pip install -e ".[gui]"or, into an existing environment:
pip install -r requirements.txt
pip install -e ".[gui]"environment.yml is preferred on macOS — OpenCV and scikit-image install more
cleanly from conda-forge than from pip.
Eight packages are required: numpy, scipy, opencv, scikit-image, matplotlib, pandas, tifffile, pillow. Two extras are optional:
.[gui]→ PySide6, fordemixs gui.[oir]→ JPype1, for reading.oirfrom Python. JPype is only a bridge — the actual reader is the Bio-Formats jars and the JDK inside a Fiji install, which pip cannot provide. SetFIJI_HOMEif Fiji is not in one of the usual places.
python check_env.py # verifies every import, prints versions, locates FijiThree environment variables are read: FIJI_HOME (where Fiji is),
DEMIXS_TEST_DATA (where the imaging data is, for the golden tests) and
DEMIXS_SETTINGS_DIR (where the GUI keeps its "Recent" entries — set it to
keep per-project state side by side).
demixs gui # interactive explorer (Detection, IN/OUT ratio)
demixs detect image.tif # one field
demixs ratio image.tif # IN/OUT signal fraction
demixs batch "dir/*.tif" # many, under one frozen parameter set
demixs convert <dir> --verify # .oir -> TIFF, checked bit-identical
demixs aggregate <dir> # pool per-image summaries into one table
demixs describe --json # the parameter schema, for agents and scriptsdemixs/ is the working code: a pure engine with a GUI and a CLI on top. See
demixs/README.md for the module layout.
- Top-hat at a physical radius removes the smooth cytoplasmic background.
- Background and noise are estimated per image from the non-zero pixels;
the intensity cut is
median + k·sigma, sokis the only knob and it is in sigmas. - Laplacian-of-Gaussian blob seeding over a radius range in µm.
- Watershed splits touching blobs; boundaries are taken at each object's half-maximum, not at the threshold, so size does not drift with the cut.
- Filters on size (µm), solidity and peak SNR.
- Cell segmentation (threshold → close → fill holes → area filter) labels cells once per field; each condensate is assigned by its centroid.
Detection is run once per field, never per cropped cell — the background estimate is per image, so cropping would silently measure cells in the same field at different sensitivities.
02_detection/NOTES_condensate_detection.md is the development log: what was
measured, what was tried and rejected, and what is still unvalidated. Read it
before changing a parameter.
Folders are numbered in the order data flows through them. They hold the
original standalone scripts the package was extracted from; they still run, and
tests/golden/ holds their output as the reference the engine is checked
against.
| folder | what it does | |
|---|---|---|
| — | demixs/ |
the package — engine, GUI, CLI |
| 01 | 01_conversion/ |
.oir → 16-bit TIFF (Fiji macros), verified bit-identical |
| 02 | 02_detection/ |
condensate detection + cell assignment |
| 03 | 03_ratio/ |
IN/OUT signal fraction per cell |
| 04 | 04_frap/ |
FRAP recovery curve fitting |
| 05 | 05_aggregate/ |
pool per-image CSVs into one table |
| 06 | 06_training/ |
plan for learning the detection filter from hand labels |
| — | legacy/ |
superseded, and one other modality. Not for new work. |
| — | tests/ |
149 tests, incl. byte-identical golden output |
Conversion writes two trees and they are not interchangeable:
RAW/— 16-bit, greyscale, unannotated. Quantify this.FIG/— 8-bit with a burned-in scale bar. Figures only. The bar is compact and high-solidity, so it gets counted as a condensate, and it drags the background estimate up.
pytest149 tests. Most run on synthetic images and need no data. The golden tests
reproduce the standalone scripts' output byte for byte and need the imaging
dataset — point DEMIXS_TEST_DATA at a copy, otherwise they skip:
DEMIXS_TEST_DATA=/path/to/data pytestThe suite redirects the GUI's persistent state into a temp directory, so running it cannot overwrite your own "Recent" entries.
Stated plainly, because they change how the numbers should be read.
- Saturation. In the source dataset, 99 of 130 fields reach the 4095
detector ceiling. This is in the
.oir; no processing recovers it. Counts survive this; sizes do not. Acquire at lower gain. - Touching cells merge. Cell segmentation gives an excellent outer boundary
but merges cells that touch — ~16% of regions are >3× the median area, and
per-cell counts are wrong there. Use condensates per µm² of cell area.
Cellpose was tested for this and rejected (unstable
diameteron dim flat cells, boundaries far too tight). - Border-clipped cells. Per-cell counts and total area are truncated for any cell touching the frame edge; per-cell median size is not.
- Two-channel images have no zero background. Channel 1 floors at exact
zero; channel 2 floors around 127. Any code assuming
img > 0means "inside a cell" is wrong on channel 2. - The IN/OUT ratio definition is provisional. Problems are documented at
the top of
03_ratio/p_quantification_ratio_v2.py: the denominator excludes most cell pixels, and the condensate threshold scales with each cell's own mean. 05_aggregate/extract_average_std.pyneeds a one-word fix (numeric_only=True) before it reads v3/v4 output on pandas 2+.
Imaging data is not in this repository. The .oir originals and converted
TIFFs are ~8 GB; 06_training/IMAGE_SOURCES.md has the full inventory with
per-condition counts. tests/golden/ is the one exception — small derived CSVs,
tracked deliberately as the regression reference.
See CITATION.cff.
MIT — see LICENSE.