Spaces:
Running on Zero
Running on Zero
Download tests/test_peak_rule.py from stevafernandes/cellquant: direct link, hf CLI and curl.
- Browser
- Download file 3.76 kB
-
https://huggingface.co/spaces/stevafernandes/cellquant/resolve/main/tests/test_peak_rule.py
- Command line
-
hf download hf://spaces/stevafernandes/cellquant/tests/test_peak_rule.py
-
curl -L -o test_peak_rule.py https://huggingface.co/spaces/stevafernandes/cellquant/resolve/main/tests/test_peak_rule.py
3.76 kB
| """Tests for the peak-distance rejection rule (PostConfig.min_peak_dist) and the | |
| per-image post-processing overrides of evaluate.py.""" | |
| import json | |
| import numpy as np | |
| from cellquant.data import distance_target | |
| from cellquant.postprocess import PostConfig, analyze, drop_low_peaks, peak_dist, segment_cells | |
| def _disc(h, w, cy, cx, r): | |
| yy, xx = np.mgrid[:h, :w] | |
| return (yy - cy) ** 2 + (xx - cx) ** 2 <= r * r | |
| def _scene(): | |
| """A bright annotated-looking nucleus (distance peak 1) and a dim blob the | |
| distance head only half believes in (peak 0.4); both are solid foreground.""" | |
| h = w = 96 | |
| d1, d2 = _disc(h, w, 30, 30, 14), _disc(h, w, 66, 66, 12) | |
| cell = np.zeros((3, h, w), np.float32) | |
| cell[1][d1 | d2] = 0.9 | |
| cell[0] = 1 - cell[1] | |
| gt = np.zeros((h, w), np.int32) | |
| gt[d1] = 1 | |
| gt[d2] = 2 | |
| dist = distance_target(gt) | |
| dist[d2] *= 0.4 | |
| return cell, dist, d1, d2 | |
| def test_peak_dist_and_drop_low_peaks(): | |
| inst = np.zeros((10, 10), np.int32) | |
| inst[1:4, 1:4] = 1 | |
| inst[6:9, 6:9] = 2 | |
| dist = np.zeros((10, 10), np.float32) | |
| dist[2, 2] = 0.9 | |
| dist[7, 7] = 0.3 | |
| pk = peak_dist(inst, dist) | |
| assert pk.shape == (3,) and pk[0] == 0 and np.isclose(pk[1], 0.9) and np.isclose(pk[2], 0.3) | |
| out = drop_low_peaks(inst, dist, 0.5) | |
| assert set(np.unique(out)) == {0, 1} and (out[6:9, 6:9] == 0).all() and (inst[6:9, 6:9] == 2).all() # input untouched | |
| assert drop_low_peaks(inst, dist, 0.0) is inst | |
| assert peak_dist(np.zeros((4, 4), np.int32), dist[:4, :4]).tolist() == [0.0] | |
| def test_min_peak_dist_drops_only_low_peak_nuclei(): | |
| cell, dist, d1, d2 = _scene() | |
| both = segment_cells(cell, PostConfig(min_peak_dist=0.0), dist) | |
| assert both.max() == 2 | |
| assert PostConfig().min_peak_dist == 0.64 # shipped default (reports/cv_v3/rule_study.md) | |
| assert segment_cells(cell, PostConfig(), dist).max() == 1 | |
| kept = segment_cells(cell, PostConfig(min_peak_dist=0.6), dist) | |
| assert kept.max() == 1 and (kept[d1] > 0).mean() > 0.95 and (kept[d2] == 0).all() | |
| # a threshold below the dim blob's peak keeps both; 0 switches the rule off | |
| assert segment_cells(cell, PostConfig(min_peak_dist=0.3), dist).max() == 2 | |
| assert segment_cells(cell, PostConfig(min_peak_dist=0.0), dist).max() == 2 | |
| # without a distance map (8-channel checkpoints) the rule is not applied | |
| assert segment_cells(cell, PostConfig(min_peak_dist=0.9)).max() == 2 | |
| def test_analyze_applies_rule_and_records_it(): | |
| cell, dist, d1, d2 = _scene() | |
| h, w = cell.shape[1:] | |
| probs = {"cell": cell, "antibody": np.full((h, w), 0.9, np.float32), "cellnos": np.zeros((h, w), np.float32), | |
| "nos": np.stack([np.ones((h, w)), np.zeros((h, w)), np.zeros((h, w))]).astype(np.float32), "dist": dist} | |
| res = analyze(probs, PostConfig(min_peak_dist=0.6)) | |
| assert len(res.cells) == 1 and res.config["min_peak_dist"] == 0.6 | |
| assert len(analyze(probs, PostConfig(min_peak_dist=0.0)).cells) == 2 | |
| def test_evaluate_post_config_overrides(tmp_path): | |
| import evaluate as ev | |
| assert ev.load_post_config("") == {} | |
| g = ev.post_config_for(ev.load_post_config('{"min_peak_dist": 0.63}'), "C100") | |
| assert g.min_peak_dist == 0.63 and g.min_cell_area == PostConfig().min_cell_area | |
| p = tmp_path / "pc.json" | |
| p.write_text(json.dumps({"C100": {"min_peak_dist": 0.61}, "F99": {"min_peak_dist": 0.6, "min_cell_area": 40}})) | |
| o = ev.load_post_config(str(p)) | |
| assert ev.post_config_for(o, "C100").min_peak_dist == 0.61 | |
| assert ev.post_config_for(o, "F99").min_cell_area == 40 | |
| assert ev.post_config_for(o, "C110") == PostConfig() # no entry -> defaults | |
| import pytest | |
| with pytest.raises(SystemExit): | |
| ev.post_config_for({"no_such_field": 1}, "C100") | |