| from __future__ import annotations |
|
|
| import unittest |
|
|
| from src.localization_quality import ( |
| calculate_bbox_area_ratio, |
| evaluate_localization_boxes, |
| ) |
| from src.schemas.detection import BBox as LocalizationBox |
|
|
|
|
| def make_box(box_2d: list[int], label: str = "finding") -> LocalizationBox: |
| return LocalizationBox(box_2d=box_2d, label=label) |
|
|
|
|
| class TestLocalizationQualityGate(unittest.TestCase): |
| def test_a_small_focal_nodule_box_accepted(self) -> None: |
| box = make_box([388, 553, 403, 575], label="nodule") |
| result = evaluate_localization_boxes("nodule", [box]) |
|
|
| self.assertEqual(len(result.accepted_boxes), 1) |
| self.assertEqual(result.rejection_reasons, []) |
| self.assertAlmostEqual(calculate_bbox_area_ratio(box), 0.0003, places=4) |
|
|
| def test_b_broad_fracture_box_rejected(self) -> None: |
| box = make_box([100, 100, 700, 500], label="fracture") |
| result = evaluate_localization_boxes("fracture", [box]) |
|
|
| self.assertEqual(result.accepted_boxes, []) |
| self.assertTrue( |
| any("bbox_area_ratio=0.2400" in reason for reason in result.rejection_reasons) |
| ) |
|
|
| def test_c_large_diffuse_opacity_box_not_geometry_rejected(self) -> None: |
| box = make_box([380, 250, 750, 750], label="opacity") |
| result = evaluate_localization_boxes("opacity", [box]) |
|
|
| self.assertEqual(len(result.accepted_boxes), 1) |
| self.assertEqual(result.rejection_reasons, []) |
|
|
|
|
| if __name__ == "__main__": |
| unittest.main() |
|
|