Skip to content

Commit

Permalink
refactoring(data): Refactoring inter-process data passing WIP
Browse files Browse the repository at this point in the history
Add immutable Msg again (still 2-3x slower than main)
  • Loading branch information
DarwinsBuddy committed Oct 28, 2024
1 parent facf30f commit aa05a34
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 70 deletions.
21 changes: 4 additions & 17 deletions foosball/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,24 +116,11 @@ def to_string(self) -> str:
return f'{self.title} {self.value}'


class InfoLog:
def __init__(self, infos=None):
self.infos: [Info] = [] if infos is None else infos
def filter_info(infos: [Info], infoVerbosity: Verbosity = Verbosity.TRACE) -> [Info]:
return [i for i in infos if infoVerbosity is not None and infoVerbosity.value <= i.verbosity.value]

def __iter__(self):
return (i for i in self.infos)

def append(self, info: Info):
self.infos.append(info)

def extend(self, info_log):
self.infos.extend(info_log.infos)

def filter(self, infoVerbosity: Verbosity = Verbosity.TRACE) -> [Info]:
return [i for i in self.infos if infoVerbosity is not None and infoVerbosity.value <= i.verbosity.value]

def to_string(self):
return " - ".join([i.to_string() for i in self.infos])
def infos_to_string(infos: [Info]):
return " - ".join([i.to_string() for i in infos])


@dataclass
Expand Down
29 changes: 7 additions & 22 deletions foosball/pipe/BaseProcess.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,26 @@
from dataclasses import dataclass
from queue import Empty, Full

from foosball.models import InfoLog
from foosball.models import Info
from foosball.pipe.Pipe import clear, SENTINEL


# TODO: check why merging into one Msg is having a huge impact on FPS
@dataclass
class Msg:
data: dict
info: InfoLog
info: [Info]
timestamp: dt.datetime = dt.datetime.now()

def __init__(self, data=None, info=InfoLog(), timestamp=dt.datetime.now()):
def __init__(self, data=None, info:[Info] = None, timestamp=dt.datetime.now(), msg: "Msg" = None):
if data is None:
data = dict()
self.data = data
self.info = info
if info is None:
info = list()
self.data = {**(msg.data if msg is not None else {}), **data}
self.info = (msg.info if msg is not None else []) + info
self.timestamp = timestamp

def __getitem__(self, key):
return self.data[key]

def __setitem__(self, key, value):
self.data[key] = value

def add(self, name: str, data: any, info: InfoLog = None):
self.data[name] = data
info_log = InfoLog() if info is None else info
if self.info is not None:
self.info.extend(info_log)
else:
self.info = InfoLog()

def remove(self, name) -> any:
return self.data.pop(name)


class BaseProcess(multiprocessing.Process):
def __init__(self, send_receive_timeout=0.5, *args, **kwargs):
Expand Down
6 changes: 3 additions & 3 deletions foosball/tracking/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from . import Tracking
from .render import r_text, BLACK
from ..detectors.color import GoalColorConfig, BallColorDetector, BallColorConfig, GoalColorDetector
from ..models import FrameDimensions, Frame, InfoLog, Verbosity
from ..models import FrameDimensions, Frame, Verbosity, Info, filter_info, infos_to_string
from ..sink.opencv import DisplaySink, Key, BallColorCalibration, GoalColorCalibration
from ..source import Source

Expand Down Expand Up @@ -108,7 +108,7 @@ def step_frame():
self.fps.update()
result = msg.data.get('Renderer', None)
frame = result.frame if result is not None else None
info: InfoLog = msg.info
info: [Info] = msg.info
self.fps.stop()
fps = int(self.fps.fps())
if not self.headless:
Expand All @@ -122,7 +122,7 @@ def step_frame():
break
else:
print(
f"{info.filter(self.infoVerbosity).to_string() if self.infoVerbosity is not None else ''} - FPS: {fps} {BLANKS}",
f"{infos_to_string(filter_info(info, self.infoVerbosity)) if self.infoVerbosity is not None else ''} - FPS: {fps} {BLANKS}",
end="\r")
except Empty:
# logger.debug("No new frame")
Expand Down
11 changes: 6 additions & 5 deletions foosball/tracking/analyzer/ScoreAnalyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from . import AbstractAnalyzer
from ...hooks import AudioHook, Webhook
from ...models import Team, Goals, Score, Track, Info, Verbosity, InfoLog
from ...models import Team, Goals, Score, Track, Info, Verbosity, Info
from ...pipe.BaseProcess import Msg
from ...utils import contains

Expand Down Expand Up @@ -52,10 +52,9 @@ def goal_shot(self, goals: Goals, track: Track) -> Optional[Team]:
self.logger.error(f"Error {e}")
return None

def analyze(self, msg: Msg, timestamp: dt.datetime) -> [ScoreAnalyzerResult, InfoLog]:
def analyze(self, msg: Msg, timestamp: dt.datetime) -> [ScoreAnalyzerResult, [Info]]:
goals = msg.data["Tracker"].goals
track = msg.data["Tracker"].ball_track
info = InfoLog()
team_scored = None
try:
self.check_reset_score()
Expand All @@ -81,8 +80,10 @@ def analyze(self, msg: Msg, timestamp: dt.datetime) -> [ScoreAnalyzerResult, Inf
self.logger.error("Error in analyzer ", e)
traceback.print_exc()
self.last_track = track
info.append(Info(verbosity=Verbosity.INFO, title="Score", value=self.score.to_string()))
return [ScoreAnalyzerResult(score=self.score, team_scored=team_scored), info]
return [
ScoreAnalyzerResult(score=self.score, team_scored=team_scored),
[Info(verbosity=Verbosity.INFO, title="Score", value=self.score.to_string())]
]

def check_reset_score(self):
if self.score_reset.is_set():
Expand Down
4 changes: 2 additions & 2 deletions foosball/tracking/analyzer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from abc import ABC, abstractmethod
from datetime import datetime

from foosball.models import InfoLog
from foosball.models import Info
from foosball.pipe.BaseProcess import Msg


Expand All @@ -13,7 +13,7 @@ def __init__(self, name: str = "UnknownAnalyzer", **kwargs):
self.logger = logging.getLogger(name)

@abstractmethod
def analyze(self, msg: Msg, timestamp: datetime) -> [dict, InfoLog]:
def analyze(self, msg: Msg, timestamp: datetime) -> [dict, [Info]]:
pass

@abstractmethod
Expand Down
9 changes: 5 additions & 4 deletions foosball/tracking/analyzer/analyze.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import traceback

from .ScoreAnalyzer import ScoreAnalyzer
from ... import hooks
from ...models import Team
from ...pipe.BaseProcess import BaseProcess, Msg


Expand All @@ -23,11 +21,14 @@ def reset_score(self):
a.reset()

def process(self, msg: Msg) -> Msg:
results = {}
infos = []
for a in self.analyzers:
try:
[result, info] = a.analyze(msg, msg.timestamp)
msg.add(a.name, result, info=info)
results[a.name] = result
infos.extend(info)
except Exception as e:
self.logger.error("Error in Analyzer - analyzers ", e)
traceback.print_exc()
return msg
return Msg(msg=msg, info=infos, data=results)
10 changes: 6 additions & 4 deletions foosball/tracking/preprocess.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import timeit
import traceback
from enum import Enum
from multiprocessing import Queue
Expand All @@ -11,7 +12,7 @@
from ..arUcos.models import Aruco
from ..detectors.color import GoalDetector, GoalColorConfig
from ..models import Frame, PreprocessorResult, Point, Rect, Blob, Goals, FrameDimensions, ScaleDirection, \
InfoLog, Info, Verbosity
Info, Verbosity
from ..pipe.BaseProcess import BaseProcess, Msg
from ..pipe.Pipe import clear
from ..utils import ensure_cpu, generate_processor_switches, relative_change, scale
Expand Down Expand Up @@ -94,7 +95,7 @@ def process(self, msg: Msg) -> Msg:
frame = self.proc(frame)
frame = scale(frame, self.dims, ScaleDirection.DOWN)
preprocessed = frame
info: InfoLog = InfoLog()
info: [Info] = []
try:
if self.goals_calibration:
try:
Expand Down Expand Up @@ -147,8 +148,9 @@ def process(self, msg: Msg) -> Msg:
except Exception as e:
self.logger.error(f"Error in preprocess {e}")
traceback.print_exc()
msg.add("Preprocessor", PreprocessorResult(original=self.iproc(frame), preprocessed=self.iproc(preprocessed), homography_matrix=self.homography_matrix, goals=self.goals), info=info)
return msg
return Msg(msg=msg, info=info, data={
"Preprocessor": PreprocessorResult(original=self.iproc(frame), preprocessed=self.iproc(preprocessed), homography_matrix=self.homography_matrix, goals=self.goals)
})

@staticmethod
def corners2pt(corners) -> [int, int]:
Expand Down
12 changes: 7 additions & 5 deletions foosball/tracking/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import numpy as np

from const import INFO_VERBOSITY
from ..models import Goal, Score, FrameDimensions, Blob, InfoLog, Verbosity, RendererResult
from ..models import Goal, Score, FrameDimensions, Blob, Verbosity, RendererResult, Info, infos_to_string, filter_info
from ..pipe.BaseProcess import Msg, BaseProcess
from ..utils import generate_processor_switches
logger = logging.getLogger(__name__)
Expand All @@ -32,7 +32,7 @@ def text_color(key, value):
return GREEN


def r_info(frame, shape: tuple[int, int, int], info: InfoLog, text_scale=1.0, thickness=1) -> None:
def r_info(frame, shape: tuple[int, int, int], info: [Info], text_scale=1.0, thickness=1) -> None:
[height, width, channels] = shape
# loop over the info tuples and draw them on our frame
x = 0
Expand Down Expand Up @@ -113,7 +113,7 @@ def __init__(self, dims: FrameDimensions, headless=False, useGPU: bool = False,
def process(self, msg: Msg) -> Msg:
score_analyzer = msg.data["ScoreAnalyzer"]
tracker = msg.data["Tracker"]
info: InfoLog = msg.info
info: [Info] = msg.info
try:
if not self.headless:
shape = tracker.frame.shape
Expand All @@ -131,8 +131,10 @@ def process(self, msg: Msg) -> Msg:
r_track(f, track, self.dims.scale)
r_score(f, score, text_scale=1, thickness=4)
if self.infoVerbosity is not None:
r_info(f, shape, info.filter(self.infoVerbosity), text_scale=0.5, thickness=1)
msg.add("Renderer", RendererResult(frame=self.iproc(f)), info=InfoLog())
r_info(f, shape, filter_info(info, self.infoVerbosity), text_scale=0.5, thickness=1)
return Msg(msg=msg, info=None, data={
"Renderer": RendererResult(frame=self.iproc(f))
})
except Exception as e:
logger.error(f"Error in renderer {e}")
traceback.print_exc()
Expand Down
15 changes: 7 additions & 8 deletions foosball/tracking/tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from const import CalibrationMode
from .preprocess import WarpMode, project_blob
from ..detectors.color import BallColorDetector, BallColorConfig
from ..models import TrackerResult, Track, Info, Blob, Goals, InfoLog, Verbosity
from ..models import TrackerResult, Track, Info, Blob, Goals, Verbosity
from ..pipe.BaseProcess import BaseProcess, Msg
from ..pipe.Pipe import clear
from ..utils import generate_processor_switches
Expand Down Expand Up @@ -46,12 +46,12 @@ def update_ball_track(self, detected_ball: Blob) -> Track:
self.ball_track.appendleft(None)
return self.ball_track

def get_info(self, ball_track: Track) -> InfoLog:
info = InfoLog(infos=[
def get_info(self, ball_track: Track) -> [Info]:
info = [
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, ' ')}"),
Info(verbosity=Verbosity.TRACE, title="Calibration", value=f"{self.calibrationMode if self.calibrationMode is not None else 'off'}"),
Info(verbosity=Verbosity.TRACE, title="Tracker", value=f"{'off' if self.off else 'on'}")
])
]
if self.calibration:
[lower, upper] = self.ball_detector.config.bounds
info.append(Info(verbosity=Verbosity.TRACE, title="lower", value=f'({",".join(map(str,lower))})'))
Expand All @@ -74,7 +74,7 @@ def process(self, msg: Msg) -> Msg:
ball = None
goals = data.goals
ball_track = None
tracker_info = InfoLog()
tracker_info = []
try:
if not self.off:
if self.calibration:
Expand Down Expand Up @@ -104,7 +104,6 @@ def process(self, msg: Msg) -> Msg:
traceback.print_exc()
# TODO: splitting into Preprocess and Tracker data maybe renders this obsolete
if not self.verbose:
msg.add("Tracker", TrackerResult(frame=data.original, goals=goals, ball_track=ball_track, ball=ball), info=tracker_info)
return Msg(msg=msg, info=tracker_info, data={"Tracker": TrackerResult(frame=data.original, goals=goals, ball_track=ball_track, ball=ball)})
else:
msg.add("Tracker", TrackerResult(frame=data.preprocessed, goals=goals, ball_track=ball_track, ball=ball), info=tracker_info)
return msg
return Msg(msg=msg, info=tracker_info, data={"Tracker": TrackerResult(frame=data.preprocessed, goals=goals, ball_track=ball_track, ball=ball)})

0 comments on commit aa05a34

Please sign in to comment.