Fix: Zaehlen verhungert nach Stunden (unbegrenzte Zustaende)
track_positions/counted_ids wuchsen im 24/7-Betrieb unbegrenzt: -> Speicherleck/Slowdown -> Bildrate bricht ein -> Linienueberquerungen werden nicht mehr erfasst (Einzel-Erkennung lief weiter). - Track-IDs altern jetzt (last-seen-Frame) und werden nach COUNT_FORGET_FRAMES aus track_positions UND counted_ids entfernt - bounded State -> kein Leck; loest auch Unterdrueckung bei spaeterer Track-ID-Wiederverwendung - Langzeit-Simulation (5000 Frames): 100/100 gezaehlt, State-Peak 4 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,9 @@ export COUNT_BAND_PX=45
|
||||
# Entprellung gegen Doppelzaehlung bei Track-ID-Wechseln (Pixel-Radius / Frames).
|
||||
export COUNT_DEDUP_PX=60
|
||||
export COUNT_DEDUP_FRAMES=12
|
||||
# 24/7-Betrieb: Track-IDs nach so vielen Frames ohne Sichtung vergessen
|
||||
# (verhindert Speicherleck / "Zaehlen verhungert nach Stunden").
|
||||
export COUNT_FORGET_FRAMES=150
|
||||
|
||||
# --- MQTT (optional) -------------------------------------------------------
|
||||
# Komplett abschaltbar: "false" -> App laeuft ohne Broker, sendet keine Events.
|
||||
|
||||
19
app.py
19
app.py
@@ -77,6 +77,11 @@ COUNT_BAND_PX = int(os.environ.get("COUNT_BAND_PX", "45"))
|
||||
# letzten COUNT_DEDUP_FRAMES Frames gezaehlten Punkt liegt.
|
||||
COUNT_DEDUP_PX = int(os.environ.get("COUNT_DEDUP_PX", "60"))
|
||||
COUNT_DEDUP_FRAMES = int(os.environ.get("COUNT_DEDUP_FRAMES", "12"))
|
||||
# 24/7-Betrieb: Track-IDs, die so viele Frames nicht mehr gesehen wurden,
|
||||
# werden aus track_positions UND counted_ids entfernt. Verhindert das
|
||||
# unbegrenzte Wachsen der Zustaende (Speicherleck) und falsches Unterdruecken
|
||||
# bei spaeterer Track-ID-Wiederverwendung. Wert > Verweildauer eines Fahrzeugs.
|
||||
COUNT_FORGET_FRAMES = int(os.environ.get("COUNT_FORGET_FRAMES", "150"))
|
||||
|
||||
# --- MQTT: ein Event pro Linienueberquerung (fuer n8n -> NocoDB) -----------
|
||||
# Komplett abschaltbar: MQTT_ENABLED=false -> App laeuft ohne Broker/Events.
|
||||
@@ -341,6 +346,16 @@ def process_frame(frame, det_model, det_names, line_start, line_end, state, sour
|
||||
c for c in recent_counts if frame_idx - c[2] <= COUNT_DEDUP_FRAMES
|
||||
]
|
||||
|
||||
# Garbage Collection: laengst verschwundene Track-IDs vergessen, damit
|
||||
# track_positions/counted_ids im 24/7-Betrieb nicht unbegrenzt wachsen.
|
||||
stale = [
|
||||
tid for tid, pos in track_positions.items()
|
||||
if frame_idx - pos[2] > COUNT_FORGET_FRAMES
|
||||
]
|
||||
for tid in stale:
|
||||
track_positions.pop(tid, None)
|
||||
counted_ids.discard(tid)
|
||||
|
||||
if results and results[0].boxes is not None and results[0].boxes.id is not None:
|
||||
boxes = results[0].boxes.xyxy.int().cpu().tolist()
|
||||
class_ids = results[0].boxes.cls.int().cpu().tolist()
|
||||
@@ -358,7 +373,7 @@ def process_frame(frame, det_model, det_names, line_start, line_end, state, sour
|
||||
|
||||
# (a) Klassischer Segment-Schnitt: Punkt davor UND dahinter.
|
||||
if track_id in track_positions:
|
||||
prev_x, prev_y = track_positions[track_id]
|
||||
prev_x, prev_y, _ = track_positions[track_id]
|
||||
cv2.line(frame, (prev_x, prev_y), (center_x, center_y), (255, 100, 0), 2)
|
||||
if crossed_line((prev_x, prev_y), (center_x, center_y), line_start, line_end):
|
||||
crossed = True
|
||||
@@ -381,7 +396,7 @@ def process_frame(frame, det_model, det_names, line_start, line_end, state, sour
|
||||
publish_crossing(label_name, track_id, source)
|
||||
cv2.circle(frame, (center_x, center_y), 25, (0, 255, 0), 5)
|
||||
|
||||
track_positions[track_id] = (center_x, center_y)
|
||||
track_positions[track_id] = (center_x, center_y, frame_idx)
|
||||
|
||||
box_color = (0, 255, 0) if label_name in VEHICLE_CLASSES else (255, 0, 0)
|
||||
cv2.rectangle(frame, (x1, y1), (x2, y2), box_color, 2)
|
||||
|
||||
Reference in New Issue
Block a user