mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
114 lines
3.4 KiB
Python
114 lines
3.4 KiB
Python
import numpy as np
|
|
|
|
from compressors.object_score import (
|
|
MaskScoringConfig,
|
|
compute_mask_features,
|
|
rank_masks,
|
|
score_mask,
|
|
select_best_mask,
|
|
)
|
|
|
|
|
|
def _rect_mask(height: int, width: int, x: int, y: int, w: int, h: int) -> np.ndarray:
|
|
mask = np.zeros((height, width), dtype=bool)
|
|
mask[y : y + h, x : x + w] = True
|
|
return mask
|
|
|
|
|
|
def test_compute_mask_features_core_metrics() -> None:
|
|
mask = _rect_mask(height=20, width=20, x=5, y=4, w=6, h=5)
|
|
mask_dict = {
|
|
"segment": mask,
|
|
"area": int(mask.sum()),
|
|
"bbox": [5, 4, 6, 5],
|
|
"predicted_iou": 0.8,
|
|
"stability_score": 0.9,
|
|
}
|
|
|
|
features = compute_mask_features(mask_dict, image_shape=(20, 20))
|
|
|
|
assert features.area_ratio == 30 / 400
|
|
assert features.fill_ratio == 1.0
|
|
assert features.aspect_ratio == 6 / 5
|
|
assert features.touch_top is False
|
|
assert features.touch_left is False
|
|
assert features.num_components == 1
|
|
assert features.largest_component_ratio == 1.0
|
|
assert features.num_holes == 0
|
|
|
|
|
|
def test_rank_masks_rejects_extreme_small_and_fragmented_masks() -> None:
|
|
cfg = MaskScoringConfig(min_area_ratio=0.02)
|
|
good_mask = _rect_mask(height=30, width=30, x=6, y=6, w=10, h=10)
|
|
|
|
fragmented = np.zeros((30, 30), dtype=bool)
|
|
fragmented[2, 2] = True
|
|
fragmented[4, 7] = True
|
|
fragmented[8, 12] = True
|
|
fragmented[12, 16] = True
|
|
fragmented[16, 20] = True
|
|
fragmented[20, 24] = True
|
|
fragmented[24, 26] = True
|
|
|
|
masks = [
|
|
{"segment": np.zeros((30, 30), dtype=bool), "area": 1, "bbox": [0, 0, 1, 1]},
|
|
{
|
|
"segment": fragmented,
|
|
"area": int(fragmented.sum()),
|
|
"bbox": [2, 2, 25, 25],
|
|
},
|
|
{
|
|
"segment": good_mask,
|
|
"area": int(good_mask.sum()),
|
|
"bbox": [6, 6, 10, 10],
|
|
"predicted_iou": 0.9,
|
|
"stability_score": 0.9,
|
|
},
|
|
]
|
|
|
|
ranked = rank_masks(masks=masks, image_shape=(30, 30), config=cfg, max_masks=3)
|
|
|
|
assert len(ranked) == 1
|
|
assert ranked[0]["area"] == int(good_mask.sum())
|
|
assert "mask_score" in ranked[0]
|
|
|
|
|
|
def test_score_mask_prefers_stable_reasonable_object() -> None:
|
|
cfg = MaskScoringConfig()
|
|
|
|
candidate = {
|
|
"segment": _rect_mask(height=100, width=100, x=30, y=20, w=24, h=25),
|
|
"area": 24 * 25,
|
|
"bbox": [30, 20, 24, 25],
|
|
"predicted_iou": 0.92,
|
|
"stability_score": 0.91,
|
|
}
|
|
weak = {
|
|
"segment": _rect_mask(height=100, width=100, x=0, y=0, w=4, h=60),
|
|
"area": 4 * 60,
|
|
"bbox": [0, 0, 4, 60],
|
|
"predicted_iou": 0.4,
|
|
"stability_score": 0.3,
|
|
}
|
|
|
|
score_candidate = score_mask(candidate, image_shape=(100, 100), config=cfg)
|
|
score_weak = score_mask(weak, image_shape=(100, 100), config=cfg)
|
|
|
|
assert score_candidate > score_weak
|
|
|
|
|
|
def test_select_best_mask_falls_back_to_largest_area_when_all_rejected() -> None:
|
|
cfg = MaskScoringConfig(min_area_ratio=0.2)
|
|
tiny = _rect_mask(height=20, width=20, x=1, y=1, w=2, h=2)
|
|
larger = _rect_mask(height=20, width=20, x=5, y=5, w=4, h=4)
|
|
|
|
masks = [
|
|
{"segment": tiny, "area": int(tiny.sum()), "bbox": [1, 1, 2, 2]},
|
|
{"segment": larger, "area": int(larger.sum()), "bbox": [5, 5, 4, 4]},
|
|
]
|
|
|
|
best = select_best_mask(masks=masks, image_shape=(20, 20), config=cfg)
|
|
|
|
assert best is not None
|
|
assert best["area"] == int(larger.sum())
|