cellquant / tests /test_metrics.py
stevafernandes's picture
Deploy CellQuant
5d31c67 verified
Raw History Blame Contribute Delete
2.72 kB
import numpy as np
from cellquant.metrics import count_errors, evaluate_cells, evaluate_nostrils, match_by_centroid, match_by_iou, micro_average
def _two_squares():
inst = np.zeros((50, 50), np.int32)
inst[5:15, 5:15] = 1
inst[30:45, 30:45] = 2
return inst
def test_perfect_prediction_scores_one():
inst = _two_squares()
labels = ["", "Cell, Antibody +", "Cell, Antibody -"]
r = evaluate_cells(inst, labels, inst.copy(), list(labels))
assert r["detection"]["f1"] == 1.0 and r["attribute_accuracy"]["both"] == 1.0
assert r["per_class"]["Cell, Antibody +"]["f1"] == 1.0
def test_wrong_label_counts_as_fp_and_fn_for_classes_but_detected():
inst = _two_squares()
gt = ["", "Cell, Antibody +", "Cell, Antibody -"]
pred = ["", "Cell, Antibody +", "Cell, Antibody +"]
r = evaluate_cells(inst, gt, inst.copy(), pred)
assert r["detection"]["tp"] == 2
assert r["per_class"]["Cell, Antibody -"]["fn"] == 1 and r["per_class"]["Cell, Antibody +"]["fp"] == 1
assert r["attribute_accuracy"]["antibody"] == 0.5
def test_shifted_prediction_fails_iou_but_passes_centroid():
gt = _two_squares()
pred = np.zeros_like(gt)
pred[9:19, 9:19] = 1 # IoU with square 1 = 36/164 < 0.5, centroid (14,14) is inside GT square 1
pred[30:45, 30:45] = 2
assert len(match_by_iou(gt, pred, 0.5)) == 1
r = evaluate_cells(gt, ["", "Cell, Antibody +", "Cell, Antibody +"], pred, ["", "Cell, Antibody +", "Cell, Antibody +"])
assert r["detection"]["tp"] == 1 and r["detection"]["centroid"]["tp"] == 2
def test_nostril_matching_by_distance():
gt = np.zeros((40, 40), np.int32)
gt[10:13, 10:13] = 1
gt[30:33, 30:33] = 2
pred = np.zeros_like(gt)
pred[12:15, 12:15] = 1 # 2 px away -> match
pred[5:8, 30:33] = 2 # 25 px away -> no match
m = match_by_centroid(gt, pred, 6.0)
assert len(m) == 1 and m[0][:2] == (1, 1)
r = evaluate_nostrils(gt, ["", "Nostril in Nucleus", "Nostril External of Nucleus"], pred, ["", "Nostril in Nucleus", "Nostril in Nucleus"])
assert r["detection"]["tp"] == 1 and r["detection"]["fp"] == 1 and r["detection"]["fn"] == 1
assert r["type_accuracy"] == 1.0
def test_count_errors_and_micro_average():
ce = count_errors({"Cell, Antibody +": 10}, {"Cell, Antibody +": 8})
assert ce["Cell, Antibody +"]["abs_err"] == 2 and abs(ce["Cell, Antibody +"]["rel_err"] - 0.2) < 1e-9
per = [{"A": {"tp": 1, "fp": 1, "fn": 0, "gt_count": 1, "pred_count": 2}}, {"A": {"tp": 3, "fp": 0, "fn": 1, "gt_count": 4, "pred_count": 3}}]
m = micro_average(per, ["A"])
assert m["A"]["tp"] == 4 and m["A"]["fp"] == 1 and m["A"]["fn"] == 1 and abs(m["A"]["f1"] - 0.8) < 1e-9