Analyse My Data

Validation · Mira image analysis

How we tested Mira's image analysis

Mira analyses microscope pictures inside your browser, and the pictures never leave your computer. It can also run published AI models that find cells and nuclei. We wanted to answer two questions. First, does each AI model find the same cells in the browser as in its original Python version? Second, how close are Mira's guided tasks (counting cells, measuring a wound and measuring stained area) to what experts marked by hand on public data sets? All numbers on this page were measured by us. When we tuned a setting on the same pictures that we then scored, we say so.

Summary

IoU 0.9999+
between the browser and the original Python versions of StarDist, Cellpose nuclei, Cellpose cyto3 and InstanSeg. All 10,074 objects were found again.
F1 0.95
for StarDist and Cellpose on the BBBC039 nuclei test set (0.85 to 0.90 on the harder Kromp 2020 set).
2.9 points
average wound-gap error compared with experts on 54 SN15 pictures (4.0 on 12 HEK293 pictures). Before our fix it was 28.7.
6.5 points
average error in DAB-stained area compared with pathologists, over four nuclear stains. Before our fix it was 12.8.
109
unit tests passed on 20 October 2026, including tests on the real example pictures that come with Mira.

Two things to keep in mind. The AI accuracy numbers were measured with the original Python programs. Since the browser versions give the same results (see "AI parity"), the numbers also apply to Mira. The wound and stained-area fixes were found and tuned on these same data sets, so those results show how well the tuning worked. They are not an independent test.

Data we used

Data setWhat it containsWhat we used it forLicence
BBBC039v1 (Caicedo et al. 2019, Broad Bioimage Benchmark Collection)U2OS cells stained with Hoechst, 16-bit fluorescence pictures of 520 × 696 pixels, with every nucleus outlined by experts. The test part has 50 picturesAI parity and accuracy, and cell countingCC0
Kromp et al. 2020 (Scientific Data)37 annotated fluorescence pictures of tissue sections and cell lines, from 10× to 63× magnificationAI accuracy on harder pictures that are new to the modelsPublished with the paper; we do not share copies
BBBC019v2 (Zaritsky et al. 2013)Wound-healing (scratch) assays in DIC and bright-field, with a hand-drawn cell mask for every picture (12 HEK293 and 54 SN15 pictures)Scratch / wound areaCC BY 3.0
IHC TMA data set (Wang et al., Zenodo 7647846)256 × 256 pixel pieces of lung-cancer tissue microarrays, where pathologists marked every positive and negative nucleus. 25 pieces each for Ki67, P53, cyclin D1 and CDK4Measure stained area (DAB)CC BY 4.0

Eight of these pictures come with Mira as examples, unchanged. The credits are in public/examples/mira/NOTICE.txt.

AI parity: browser compared with the original program

To run the models in a browser, we converted each network to ONNX and run it with ONNX Runtime Web (on WebGPU, or WebAssembly if WebGPU is not available). The steps before and after the network are written in Mira's own code. These include the StarDist overlap removal, the Cellpose flow tracking and size model, and the InstanSeg clustering. To compare, we matched objects that overlap with IoU above 0.5 and averaged the IoU in both directions. We only offer a model in Mira if every picture scores at least 0.98 and the average is at least 0.99.

ModelOriginal versionPicturesObjects (Python → browser)Mean IoUWorst picture
StarDist versatile_fluoStarDist 0.9.2 (TensorFlow)202,054 → 2,0540.999950.99896
Cellpose nuclei (automatic diameter)Cellpose 3.1.1.2 (PyTorch)202,061 → 2,0611.000001.00000
Cellpose cyto3 (automatic diameter)Cellpose 3.1.1.2 (PyTorch)202,122 → 2,1221.000001.00000
InstanSeg brightfield_nucleiInstanSeg v0.1.1 (TorchScript)203,837 → 3,8370.999990.99994

For StarDist and Cellpose we used 20 BBBC039 test pictures. For InstanSeg we used its own example tile in five versions (as it is, flipped two ways, rotated, and as a 2 × 2 mosaic) plus 15 BBBC039 and Kromp pictures recoloured to look like bright-field. This only tests parity, not real tissue. The automatic cell diameters in the browser were the same as in Python to two decimals on every picture. We also checked on the Python side that the ONNX networks match the original networks on 25 pictures each (Cellpose flows within 2.1 × 10⁻⁴ and identical masks; StarDist and InstanSeg identical labels).

AI accuracy on labelled test sets

ModelTest setPicturesAP@0.5F1@0.5AP@0.75Mean IoU of matchesCount error
StarDist versatile_fluoBBBC039 test*500.9060.9510.8540.9128.5 %
StarDist versatile_fluoKromp 2020370.7320.8450.5170.82525.8 %
Cellpose nucleiBBBC039 test500.8980.9460.8640.93310.6 %
Cellpose nucleiKromp 2020370.8170.8990.5810.8288.1 %
Cellpose cyto3BBBC039 test500.9180.9570.8790.9315.7 %
Cellpose cyto3Kromp 2020370.8150.8980.6020.83611.2 %
InstanSeg brightfieldNot measured, because neither labelled set is bright-field. Mira tells users that this model is "not yet validated on a labelled dataset".

AP@0.5 = TP / (TP + FP + FN) at IoU 0.5. Count error is the average difference in the number of objects. All runs used automatic settings. * StarDist versatile_fluo was trained on nuclei from the Data Science Bowl 2018, which includes U2OS pictures similar to BBBC039, so its BBBC039 score is not fully independent. Kromp 2020 was not part of its training. We did not check whether Cellpose was trained on these pictures. Kromp 2020 AP@0.5 by magnification (10× / 20× / 40× / 63×): StarDist 0.90 / 0.70 / 0.82 / 0.65, Cellpose nuclei 0.93 / 0.78 / 0.85 / 0.82, Cellpose cyto3 0.94 / 0.74 / 0.83 / 0.79.

Speed

ModelNetworkTotal per picture
StarDist versatile_fluo0.29 s0.6 s
InstanSeg brightfield_nuclei3.1 s3.4 s
Cellpose nuclei (automatic diameter, three network passes)23 s25 s
Cellpose cyto3 (automatic diameter, three network passes)39 s41 s

These are median times over the 20 parity pictures (mostly 520 × 696 pixels), using ONNX Runtime Web with WebAssembly and 4 threads in Node on an Apple M2 laptop. The total includes the steps before and after the network. During the cyto3 run another job was using the processor, so its times are probably a bit too high. If you type in the typical cell diameter, Cellpose needs only one network pass instead of three. We have not finished timing inside the browser (WebGPU) yet.

Counting cells on real nuclei pictures

Three BBBC039 test pictures come with Mira as examples. We ran "Count cells" on them with its default threshold method (Otsu threshold and watershed splitting). Cells touching the edge were kept so the count can be compared with the expert masks.

PictureExpert countMira (threshold method)Difference
Sparse (IXMtest_I23_s5)3634−6 %
Typical (IXMtest_C23_s2)119107−10 %
Crowded (IXMtest_I12_s1)202182−10 %

The threshold method joins some nuclei that touch each other, so it counts a little too low. For crowded pictures, "Find cells with AI" works better (StarDist reaches F1 0.95 on this test set). These counts are checked every time the tests run, in mira/src/tasks/realExamples.test.ts.

Scratch / wound area compared with expert masks (BBBC019)

We compared the gap that Mira finds (with default settings) with the expert gap, which is 100 % minus the cell area in the hand-drawn mask. We did this for all 66 pictures that have a mask.

VersionHEK293 (12): mean |Δ gap| / mean IoUSN15 (54): mean |Δ gap| / mean IoU
Before: Otsu cutoff on the local texture2.6 points / 0.8728.7 points / 0.49
Now: Otsu limited to 5 × the noise level, with over-exposed areas left out4.0 points / 0.862.9 points / 0.76

The old method did badly on wounds that were almost closed. In one case it reported an 80 % gap where the experts saw 10 %. The reason is that Otsu always splits the histogram into two parts, so when there is hardly any gap, it splits the texture of the cells themselves. We tried 11 variants of the fix on these same pictures and picked the best one.

Example picture in MiraExpert gapMira
SN15 position 10, start37.2 %35.3 %
SN15 position 10, later11.7 %5.7 %
HEK293 picture33.6 %32.4 %

For the SN15 pair, Mira gives 84 % closure while the experts give 69 %. So for late, almost closed wounds Mira still finds too little gap. Please look at the overlay on late time points and increase "Gap sensitivity" if the gap looks too small.

Stained area (DAB) compared with pathologists' masks

For the four nuclear stains, we compared Mira's DAB "% area" with the area of the positive nuclei that the pathologists marked (25 pictures per stain). Mira first separates the brown DAB colour from the blue haematoxylin (colour deconvolution) and then applies a threshold.

Cutoff on the DAB channel (optical density): mean |Δ area| in points / IoUCDK4Cyclin D1P53Ki67
Otsu only (before)17.8 / 0.3514.9 / 0.4011.7 / 0.366.7 / 0.63
Otsu, but at least 0.2 OD (default now)11.5 / 0.354.1 / 0.423.8 / 0.426.7 / 0.63
Fixed 0.3 OD (set by hand)21.6 / 0.312.6 / 0.603.1 / 0.542.5 / 0.69

Because Otsu always splits the histogram, pictures with no brown stain at all used to show some stained area. Adding a lower limit of 0.2 OD fixed this. We took this value from QuPath, where it is the usual DAB positivity level, so it was not fitted to this data. For purely nuclear stains such as Ki67, a fixed cutoff of 0.3 OD comes closer to the pathologists. CDK4 also stains the cytoplasm, which the masks do not include, so "% area" stays higher than the positive-nucleus area for this stain.

Example pictures in Mira (the picture with the median positive area for each stain): Ki67 5.5 % stained compared with 15.8 % positive-nucleus area (too low), and P53 6.9 % compared with 8.1 %. Note that "% area" is not the same as a Ki67 index (positive nuclei divided by all nuclei). Mira cannot count positive nuclei yet.

Limits

How to repeat our tests

  1. In mira/, run npx vitest run. This runs the 109 unit tests, including the example pictures (src/tasks/realExamples.test.ts).
  2. Wound area: download BBBC019v2 and run MIRA_BBBC019=<folder> npx vitest run src/tasks/woundValidation.test.ts.
  3. Stained area: download the IHC TMA data set and run MIRA_IHC=<folder> npx vitest run src/tasks/ihcValidation.test.ts. Add MIRA_IHC_FLOORS=0,0.2 to compare cutoffs.
  4. AI parity: make reference results with StarDist 0.9.2, Cellpose 3.1.1.2 and InstanSeg, then run MIRA_AI_REF=<folder> MIRA_AI_N=20 npx vitest run src/ai/validation/e2e.parity.test.ts.

The full report is in mira/docs/AI-VALIDATION.md, and the model licences are in public/models/THIRD-PARTY-NOTICES.txt.