fix: ignore global lighting shifts in occupancy
This commit is contained in:
@@ -158,6 +158,66 @@ class VisionTests(unittest.TestCase):
|
||||
self.assertEqual(first_empty_counts, {"1": 1})
|
||||
self.assertEqual(second_empty_counts, {"1": 0})
|
||||
|
||||
def test_detector_ignores_global_lighting_dimming_across_many_zones(self) -> None:
|
||||
regions = [
|
||||
Region(str(index + 1), ((index / 7, 0.0), ((index + 1) / 7, 0.0), ((index + 1) / 7, 1.0), (index / 7, 1.0)))
|
||||
for index in range(7)
|
||||
]
|
||||
detector = ZoneOccupancyDetector(
|
||||
regions,
|
||||
trash_region=None,
|
||||
settings=RuntimeVisionSettings(
|
||||
baseline_frames=1,
|
||||
sample_stride_pixels=2,
|
||||
occupancy_mean_delta=55,
|
||||
occupancy_texture_delta=18,
|
||||
occupancy_confirm_frames=2,
|
||||
empty_confirm_frames=2,
|
||||
),
|
||||
)
|
||||
now = datetime(2026, 6, 1, 4, 55, tzinfo=timezone.utc)
|
||||
|
||||
detector.observe(solid_frame(70, 20, 180), now)
|
||||
first_counts, _, first_diagnostics = detector.observe(solid_frame(70, 20, 100), now + timedelta(seconds=5))
|
||||
second_counts, _, second_diagnostics = detector.observe(solid_frame(70, 20, 100), now + timedelta(seconds=10))
|
||||
|
||||
self.assertEqual(first_counts, {str(index): 0 for index in range(1, 8)})
|
||||
self.assertEqual(second_counts, {str(index): 0 for index in range(1, 8)})
|
||||
self.assertTrue(first_diagnostics["lighting_shift"]["active"])
|
||||
self.assertTrue(second_diagnostics["lighting_shift"]["active"])
|
||||
self.assertTrue(all(not zone["raw_occupied"] for zone in second_diagnostics["zones"].values()))
|
||||
|
||||
def test_detector_allows_single_zone_object_while_lighting_guard_is_available(self) -> None:
|
||||
regions = [
|
||||
Region(str(index + 1), ((index / 7, 0.0), ((index + 1) / 7, 0.0), ((index + 1) / 7, 1.0), (index / 7, 1.0)))
|
||||
for index in range(7)
|
||||
]
|
||||
detector = ZoneOccupancyDetector(
|
||||
regions,
|
||||
trash_region=None,
|
||||
settings=RuntimeVisionSettings(
|
||||
baseline_frames=1,
|
||||
sample_stride_pixels=2,
|
||||
occupancy_mean_delta=55,
|
||||
occupancy_texture_delta=100,
|
||||
occupancy_dark_luma_threshold=80,
|
||||
occupancy_dark_fraction=0.06,
|
||||
occupancy_confirm_frames=2,
|
||||
empty_confirm_frames=2,
|
||||
),
|
||||
)
|
||||
now = datetime(2026, 6, 1, 10, 0, tzinfo=timezone.utc)
|
||||
|
||||
detector.observe(solid_frame(70, 20, 180), now)
|
||||
object_frame = patched_frame(70, 20, 180, (0, 0, 10, 20, 20))
|
||||
detector.observe(object_frame, now + timedelta(seconds=5))
|
||||
counts, _, diagnostics = detector.observe(object_frame, now + timedelta(seconds=10))
|
||||
|
||||
self.assertEqual(counts["1"], 1)
|
||||
self.assertEqual(sum(counts.values()), 1)
|
||||
self.assertFalse(diagnostics["lighting_shift"]["active"])
|
||||
self.assertTrue(diagnostics["zones"]["1"]["raw_occupied"])
|
||||
|
||||
def test_runtime_vision_defaults_raise_brightness_reflection_threshold(self) -> None:
|
||||
settings = load_runtime_vision_settings({})
|
||||
|
||||
@@ -169,6 +229,10 @@ class VisionTests(unittest.TestCase):
|
||||
self.assertEqual(settings.trash_sustained_motion_delta, 8.0)
|
||||
self.assertEqual(settings.trash_sustained_motion_frames, 2)
|
||||
self.assertEqual(settings.trash_motion_cooldown_seconds, 3)
|
||||
self.assertTrue(settings.lighting_shift_guard_enabled)
|
||||
self.assertEqual(settings.lighting_shift_min_regions, 3)
|
||||
self.assertAlmostEqual(settings.lighting_shift_region_fraction, 0.6)
|
||||
self.assertEqual(settings.lighting_shift_mean_delta, 45.0)
|
||||
|
||||
def test_detector_can_seed_previous_baseline_and_occupancy(self) -> None:
|
||||
detector = ZoneOccupancyDetector(
|
||||
@@ -596,6 +660,10 @@ class VisionTests(unittest.TestCase):
|
||||
"yolo_enabled": True,
|
||||
"yolo_model_path": "models/yolo.onnx",
|
||||
"yolo_min_confidence": 0.7,
|
||||
"lighting_shift_guard_enabled": False,
|
||||
"lighting_shift_min_regions": 4,
|
||||
"lighting_shift_region_fraction": 0.75,
|
||||
"lighting_shift_mean_delta": 60.0,
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -613,6 +681,10 @@ class VisionTests(unittest.TestCase):
|
||||
self.assertTrue(settings.yolo_enabled)
|
||||
self.assertEqual(settings.yolo_model_path, "models/yolo.onnx")
|
||||
self.assertEqual(settings.yolo_min_confidence, 0.7)
|
||||
self.assertFalse(settings.lighting_shift_guard_enabled)
|
||||
self.assertEqual(settings.lighting_shift_min_regions, 4)
|
||||
self.assertAlmostEqual(settings.lighting_shift_region_fraction, 0.75)
|
||||
self.assertEqual(settings.lighting_shift_mean_delta, 60.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user