AURON: Veraltete Flaschentreffer bei fehlgeschlagener Erkennung verwerfen
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
"""Regressionstests für Erkennungszustand ohne Hardware oder externe Pakete."""
|
||||
import importlib.util
|
||||
import math
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import types
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def load_config():
|
||||
spec = importlib.util.spec_from_file_location("_detection_test_config", ROOT / "config.py")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def load_vision():
|
||||
config = load_config()
|
||||
cv2 = types.ModuleType("cv2")
|
||||
numpy = types.ModuleType("numpy")
|
||||
numpy.sqrt = math.sqrt
|
||||
calibrator_module = types.ModuleType("calibrator")
|
||||
|
||||
class Calibrator:
|
||||
is_calibrated = True
|
||||
|
||||
def pixel_to_robot(self, x, y):
|
||||
return (float(x), float(y))
|
||||
|
||||
calibrator_module.CameraCalibrator = Calibrator
|
||||
ui_module = types.ModuleType("user_interface")
|
||||
ui_module.ModernUI = type("ModernUI", (), {})
|
||||
ultra = types.ModuleType("ultralytics")
|
||||
ultra.YOLO = lambda path: None
|
||||
modules = {
|
||||
"cv2": cv2, "numpy": numpy, "config": config,
|
||||
"calibrator": calibrator_module, "user_interface": ui_module,
|
||||
"ultralytics": ultra,
|
||||
}
|
||||
with patch.dict(sys.modules, modules):
|
||||
spec = importlib.util.spec_from_file_location("_detection_test_vision", ROOT / "vision.py")
|
||||
vision = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(vision)
|
||||
return vision.BeerBotVision
|
||||
|
||||
|
||||
class DetectionStateTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.BeerBotVision = load_vision()
|
||||
self.bot = self.BeerBotVision()
|
||||
|
||||
def seed(self):
|
||||
self.bot.detected_bottles = [{"bbox": (1, 2, 3, 4), "center_pixel": (2, 3),
|
||||
"robot_coords": (2, 3), "confidence": 0.9}]
|
||||
|
||||
def test_missing_model_clears_cache_and_nearest(self):
|
||||
self.seed()
|
||||
self.bot.model = None
|
||||
self.assertEqual(self.bot.detect_objects(), {"bottles": []})
|
||||
self.assertEqual(self.bot.detected_bottles, [])
|
||||
self.assertIsNone(self.bot.get_nearest_bottle())
|
||||
|
||||
def test_missing_capture_does_not_call_model_and_clears_cache(self):
|
||||
self.seed()
|
||||
called = []
|
||||
self.bot.model = lambda *a, **k: called.append(True)
|
||||
self.bot.capture_frame = lambda: None
|
||||
self.assertEqual(self.bot.detect_objects(), {"bottles": []})
|
||||
self.assertEqual(called, [])
|
||||
self.assertEqual(self.bot.detected_bottles, [])
|
||||
self.assertIsNone(self.bot.get_nearest_bottle())
|
||||
|
||||
def test_empty_success_clears_cache(self):
|
||||
self.seed()
|
||||
self.bot.model = lambda frame, **kwargs: [types.SimpleNamespace(boxes=[])]
|
||||
result = self.bot.detect_objects(frame=object())
|
||||
self.assertEqual(result["bottles"], [])
|
||||
self.assertEqual(self.bot.detected_bottles, [])
|
||||
|
||||
def test_fresh_detection_replaces_cache_and_returns_frame(self):
|
||||
self.seed()
|
||||
frame = object()
|
||||
box = types.SimpleNamespace(cls=[39], conf=[0.8], xyxy=[[10.2, 20.8, 30.9, 40.1]])
|
||||
self.bot.model = lambda image, **kwargs: [types.SimpleNamespace(boxes=[box])]
|
||||
result = self.bot.detect_objects(frame=frame)
|
||||
expected = {"bbox": (10, 20, 30, 40), "center_pixel": (20, 30),
|
||||
"robot_coords": (20.0, 30.0), "confidence": 0.8}
|
||||
self.assertIs(result["frame"], frame)
|
||||
self.assertEqual(result["bottles"], [expected])
|
||||
self.assertEqual(self.bot.detected_bottles, [expected])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -55,6 +55,10 @@ class BeerBotVision:
|
||||
return frame if ret else None
|
||||
|
||||
def detect_objects(self, frame=None, visualize=False):
|
||||
# Jeder Aufruf beschreibt einen neuen Erkennungsversuch; alte Treffer
|
||||
# dürfen auch bei fehlendem Modell oder Frame nicht erhalten bleiben.
|
||||
self.detected_bottles = []
|
||||
|
||||
if self.model is None:
|
||||
return {"bottles": []}
|
||||
|
||||
@@ -64,7 +68,6 @@ class BeerBotVision:
|
||||
return {"bottles": []}
|
||||
|
||||
results = self.model(frame, verbose=False)
|
||||
self.detected_bottles = []
|
||||
|
||||
for result in results:
|
||||
for box in result.boxes:
|
||||
|
||||
Reference in New Issue
Block a user