Skip to content

Commit 501e458

Browse files
committed
enhancement(zmq): Add zmq hook WIP
Add viewbox to Framestats
1 parent d0ed4cd commit 501e458

File tree

6 files changed

+19
-8
lines changed

6 files changed

+19
-8
lines changed

foosball/tracking/analyzer/ScoreAnalyzer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def analyze(self, msg: Msg, timestamp: dt.datetime) -> [ScoreAnalyzerResult, [In
7272
goals = msg.data["Tracker"].goals
7373
track = msg.data["Tracker"].ball_track
7474
ball = msg.data["Tracker"].ball
75+
viewbox = msg.data["Tracker"].viewbox
7576
team_scored = None
7677
try:
7778
self.check_reset_score()
@@ -103,6 +104,7 @@ def analyze(self, msg: Msg, timestamp: dt.datetime) -> [ScoreAnalyzerResult, [In
103104
score=self.score,
104105
ball=ball,
105106
dims=self.dims,
107+
viewbox=viewbox,
106108
timestamp=timestamp.strftime("%Y-%m-%dT%H:%M:%S")
107109
)
108110
self.frame_hooks.invoke(stats.to_dict())

foosball/tracking/analyzer/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
from foosball.models import Goals, Track, Blob, Score, FrameDimensions
44

5+
56
@dataclass
67
class FrameStats:
78
goals: Goals | None
89
track: Track | None
910
ball: Blob | None
1011
score: Score | None
1112
dims: FrameDimensions | None
13+
viewbox: list | None
1214
timestamp: str | None
1315

1416
def to_dict(self) -> dict:
@@ -18,5 +20,6 @@ def to_dict(self) -> dict:
1820
"ball": self.ball.to_json() if self.ball else None,
1921
"score": self.score.to_json() if self.score else None,
2022
"dims": self.dims.to_json() if self.dims else None,
23+
"viewbox": self.viewbox if self.viewbox else None,
2124
"timestamp": self.timestamp
2225
}

foosball/tracking/preprocess/__init__.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def __init__(self, dims: FrameDimensions, goal_detector: GoalDetector, headless=
6868
self.calibration_out = Queue() if self.goals_calibration else None
6969
self.config_in = Queue() if self.goals_calibration else None
7070
self.goal_detector = goal_detector
71+
self.viewbox = None
7172

7273
def config_input(self, config: GoalColorConfig) -> None:
7374
if self.goals_calibration:
@@ -119,8 +120,10 @@ def process(self, msg: Msg) -> Msg:
119120

120121
self.frames_since_last_marker_detection = (self.frames_since_last_marker_detection + 1) % self.redetect_markers_frame_threshold
121122
if len(self.markers) == 4:
123+
122124
# crop and warp
123-
preprocessed, self.homography_matrix = self.four_point_transform(frame, self.markers)
125+
preprocessed, self.homography_matrix, marker_pts = self.four_point_transform(frame, self.markers)
126+
self.viewbox = [pt.tolist() for pt in marker_pts]
124127
if trigger_marker_detection:
125128
# detect goals anew
126129
goals_detection_result = self.goal_detector.detect(preprocessed)
@@ -150,7 +153,7 @@ def process(self, msg: Msg) -> Msg:
150153
traceback.print_exc()
151154
# Not passing original msg due to performance impact (copying whole frames, etc.)
152155
return Msg(info=info, data={
153-
"Preprocessor": PreprocessorResult(original=self.iproc(frame), preprocessed=self.iproc(preprocessed), homography_matrix=self.homography_matrix, goals=self.goals)
156+
"Preprocessor": PreprocessorResult(original=self.iproc(frame), preprocessed=self.iproc(preprocessed), homography_matrix=self.homography_matrix, goals=self.goals, viewbox=self.viewbox)
154157
})
155158

156159
@staticmethod
@@ -181,7 +184,7 @@ def order_points(pts: np.ndarray) -> np.ndarray:
181184
# return the ordered coordinates
182185
return rect
183186

184-
def four_point_transform(self, frame: Frame, markers: list[Aruco]) -> tuple[Frame, [int, int]]:
187+
def four_point_transform(self, frame: Frame, markers: list[Aruco]) -> tuple[Frame, [int, int], [int, int, int, int]]:
185188
pts = np.array([self.corners2pt(marker.corners) for marker in markers])
186189
# obtain a consistent order of the points and unpack them
187190
# individually
@@ -226,7 +229,7 @@ def four_point_transform(self, frame: Frame, markers: list[Aruco]) -> tuple[Fram
226229
# since we want to draw on the original image (later on), which is still originally not warped,
227230
# we want to have a function set to project from/onto the warped/un-warped version of the frame
228231
# for future reference. so we return the warped image and the used homography matrix
229-
return warped, homography_matrix
232+
return warped, homography_matrix, src_pts
230233

231234

232235
def project_point(pt: Point, homography_matrix: np.array, mode: WarpMode):

foosball/tracking/preprocess/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ class PreprocessorResult:
1212
preprocessed: Optional[Frame]
1313
homography_matrix: Optional[np.ndarray] # 3x3 matrix used to warp the image and project points
1414
goals: Optional[Goals]
15+
viewbox: Optional[list]

foosball/tracking/tracker/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def close(self) -> None:
3838
clear(self.calibration_out)
3939
self.calibration_out.close()
4040

41-
def update_ball_track(self, detected_ball: Blob) -> Track:
41+
def update_ball_track(self, detected_ball: Blob) -> Track | None:
4242
if detected_ball is not None:
4343
center = detected_ball.center
4444
# update the points queue (track history)
@@ -47,7 +47,7 @@ def update_ball_track(self, detected_ball: Blob) -> Track:
4747
self.ball_track.appendleft(None)
4848
return self.ball_track
4949

50-
def get_info(self, ball_track: Track) -> [Info]:
50+
def get_info(self, ball_track: Track | None) -> [Info]:
5151
info = [
5252
Info(verbosity=Verbosity.DEBUG, title="Track length", value=f"{str(sum([1 for p in ball_track or [] if p is not None])).rjust(2, ' ')}"),
5353
Info(verbosity=Verbosity.TRACE, title="Calibration", value=f"{self.calibrationMode if self.calibrationMode is not None else 'off'}"),
@@ -75,6 +75,7 @@ def process(self, msg: Msg) -> Msg:
7575
ball = None
7676
goals = data.goals
7777
ball_track = None
78+
viewbox = data.viewbox
7879
tracker_info = []
7980
try:
8081
if not self.off:
@@ -105,6 +106,6 @@ def process(self, msg: Msg) -> Msg:
105106
traceback.print_exc()
106107
# Not passing original msg due to performance impact (copying whole frames, etc.)
107108
if not self.verbose:
108-
return Msg(info=tracker_info, data={"Tracker": TrackerResult(frame=data.original, goals=goals, ball_track=ball_track, ball=ball)})
109+
return Msg(info=tracker_info, data={"Tracker": TrackerResult(frame=data.original, goals=goals, ball_track=ball_track, ball=ball, viewbox=viewbox)})
109110
else:
110-
return Msg(info=tracker_info, data={"Tracker": TrackerResult(frame=data.preprocessed, goals=goals, ball_track=ball_track, ball=ball)})
111+
return Msg(info=tracker_info, data={"Tracker": TrackerResult(frame=data.preprocessed, goals=goals, ball_track=ball_track, ball=ball, viewbox=viewbox)})

foosball/tracking/tracker/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ class TrackerResult:
99
goals: Goals | None
1010
ball_track: Track | None
1111
ball: Blob | None
12+
viewbox: list | None

0 commit comments

Comments
 (0)