feat: add capture strategy interface and manual button strategy
This commit is contained in:
parent
f93d51d500
commit
b707aef137
3 changed files with 62 additions and 0 deletions
15
bookmark/capture_strategies/base.py
Normal file
15
bookmark/capture_strategies/base.py
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
class CaptureStrategy(ABC):
|
||||||
|
"""Watches a stream of frames and decides when to fire a capture."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def reset(self) -> None:
|
||||||
|
"""Clear any internal state, e.g. after a capture fires."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def observe(self, frame: np.ndarray) -> bool:
|
||||||
|
"""Feed the latest frame. Returns True exactly once per capture."""
|
||||||
22
bookmark/capture_strategies/manual_button.py
Normal file
22
bookmark/capture_strategies/manual_button.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from .base import CaptureStrategy
|
||||||
|
|
||||||
|
|
||||||
|
class ManualButtonStrategy(CaptureStrategy):
|
||||||
|
"""Fires only when trigger() has been called since the last observe()."""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._armed = False
|
||||||
|
|
||||||
|
def trigger(self) -> None:
|
||||||
|
self._armed = True
|
||||||
|
|
||||||
|
def reset(self) -> None:
|
||||||
|
self._armed = False
|
||||||
|
|
||||||
|
def observe(self, frame: np.ndarray) -> bool:
|
||||||
|
if self._armed:
|
||||||
|
self._armed = False
|
||||||
|
return True
|
||||||
|
return False
|
||||||
25
tests/test_manual_button_strategy.py
Normal file
25
tests/test_manual_button_strategy.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from bookmark.capture_strategies.manual_button import ManualButtonStrategy
|
||||||
|
|
||||||
|
|
||||||
|
def test_does_not_fire_without_trigger():
|
||||||
|
strategy = ManualButtonStrategy()
|
||||||
|
frame = np.zeros((10, 10, 3), dtype=np.uint8)
|
||||||
|
assert strategy.observe(frame) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_fires_once_after_trigger():
|
||||||
|
strategy = ManualButtonStrategy()
|
||||||
|
frame = np.zeros((10, 10, 3), dtype=np.uint8)
|
||||||
|
strategy.trigger()
|
||||||
|
assert strategy.observe(frame) is True
|
||||||
|
assert strategy.observe(frame) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_reset_clears_armed_state():
|
||||||
|
strategy = ManualButtonStrategy()
|
||||||
|
frame = np.zeros((10, 10, 3), dtype=np.uint8)
|
||||||
|
strategy.trigger()
|
||||||
|
strategy.reset()
|
||||||
|
assert strategy.observe(frame) is False
|
||||||
Loading…
Reference in a new issue