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