fix counter bug
This commit is contained in:
1 parent
a4f7d4d794
commit
e9ab06e823
2 files changed
+33
-8
No files matched your search
+13
-6
@@ -1309,8 +1309,9 @@ def run():
|
|||||||
frames_since_infer = 0
|
frames_since_infer = 0
|
||||||
video_writer = None
|
video_writer = None
|
||||||
crossing_times = deque()
|
crossing_times = deque()
|
||||||
counter_left = 0
|
# Overlay shows daily store totals (resume-safe, resets on counting-day change).
|
||||||
counter_right = 0
|
counter_left = store.current_count_left
|
||||||
|
counter_right = store.current_count_right
|
||||||
last_snapshot_cleanup = 0.0
|
last_snapshot_cleanup = 0.0
|
||||||
|
|
||||||
counting_active = True
|
counting_active = True
|
||||||
@@ -1595,12 +1596,17 @@ def run():
|
|||||||
st["counted"] = True
|
st["counted"] = True
|
||||||
st["side"] = feeder
|
st["side"] = feeder
|
||||||
last_count_mono[feeder] = mono
|
last_count_mono[feeder] = mono
|
||||||
|
_, _, counted = store.record_zone_entry(tid, feeder)
|
||||||
|
counter_left = store.current_count_left
|
||||||
|
counter_right = store.current_count_right
|
||||||
|
if not counted:
|
||||||
|
# Dedup in the store rejected this event; skip overlay/CSV.
|
||||||
|
object_tracked[tid] = (cx, cy, mono)
|
||||||
|
continue
|
||||||
if feeder == "left":
|
if feeder == "left":
|
||||||
counter_left += 1
|
|
||||||
count_left_pulse = COUNT_PULSE_FRAMES
|
count_left_pulse = COUNT_PULSE_FRAMES
|
||||||
feeder_total = counter_left
|
feeder_total = counter_left
|
||||||
else:
|
else:
|
||||||
counter_right += 1
|
|
||||||
count_right_pulse = COUNT_PULSE_FRAMES
|
count_right_pulse = COUNT_PULSE_FRAMES
|
||||||
feeder_total = counter_right
|
feeder_total = counter_right
|
||||||
# Frigate-style count log, e.g.
|
# Frigate-style count log, e.g.
|
||||||
@@ -1609,7 +1615,6 @@ def run():
|
|||||||
f"Total {OBJECT_LABEL} di {feeder_display_name(feeder)}: {feeder_total}",
|
f"Total {OBJECT_LABEL} di {feeder_display_name(feeder)}: {feeder_total}",
|
||||||
flush=True,
|
flush=True,
|
||||||
)
|
)
|
||||||
store.record_zone_entry(tid, feeder)
|
|
||||||
if cross_logger:
|
if cross_logger:
|
||||||
cross_logger.write_row(
|
cross_logger.write_row(
|
||||||
[
|
[
|
||||||
@@ -1654,7 +1659,9 @@ def run():
|
|||||||
if object_crossed_frame:
|
if object_crossed_frame:
|
||||||
zone_pulse = ZONE_PULSE_FRAMES
|
zone_pulse = ZONE_PULSE_FRAMES
|
||||||
|
|
||||||
display_total = store.display_total()
|
# Keep overlay aligned with daily store (also resets after cutoff).
|
||||||
|
counter_left = store.current_count_left
|
||||||
|
counter_right = store.current_count_right
|
||||||
while crossing_times and mono - crossing_times[0] > RATE_WINDOW_SEC:
|
while crossing_times and mono - crossing_times[0] > RATE_WINDOW_SEC:
|
||||||
crossing_times.popleft()
|
crossing_times.popleft()
|
||||||
rate = (len(crossing_times) / RATE_WINDOW_SEC * 60) if crossing_times else 0.0
|
rate = (len(crossing_times) / RATE_WINDOW_SEC * 60) if crossing_times else 0.0
|
||||||
|
|||||||
+20
-2
@@ -97,10 +97,23 @@ class CounterStore:
|
|||||||
self.state_file.unlink(missing_ok=True)
|
self.state_file.unlink(missing_ok=True)
|
||||||
return None
|
return None
|
||||||
state = self._normalize_state(state)
|
state = self._normalize_state(state)
|
||||||
|
# Track IDs are process-local and restart from 1 after every process
|
||||||
|
# start. Persisted dedup keys like "5_left" would silently block new
|
||||||
|
# counts that reuse those IDs, so clear them on resume while keeping
|
||||||
|
# the day's totals.
|
||||||
|
stale_ids = state.get('counted_event_ids') or []
|
||||||
|
if stale_ids:
|
||||||
|
self.log(
|
||||||
|
f"Cleared {len(stale_ids)} persisted track dedup keys "
|
||||||
|
f"(track IDs reset on restart)"
|
||||||
|
)
|
||||||
|
state['counted_event_ids'] = []
|
||||||
self.log(
|
self.log(
|
||||||
f"Resumed {current_date} with total={state['count']} "
|
f"Resumed {current_date} with total={state['count']} "
|
||||||
f"(left={state['count_left']} right={state['count_right']})"
|
f"(left={state['count_left']} right={state['count_right']})"
|
||||||
)
|
)
|
||||||
|
with open(self.state_file, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(state, f, indent=2, ensure_ascii=False)
|
||||||
return state
|
return state
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self.log(f'Failed to load state file: {exc}')
|
self.log(f'Failed to load state file: {exc}')
|
||||||
@@ -134,7 +147,10 @@ class CounterStore:
|
|||||||
self.log(f'Started counting day {counting_date} ({self.object_label})')
|
self.log(f'Started counting day {counting_date} ({self.object_label})')
|
||||||
|
|
||||||
def record_zone_entry(self, track_id, feeder):
|
def record_zone_entry(self, track_id, feeder):
|
||||||
"""Record a sack entering a feeder zone. feeder: 'left' | 'right'."""
|
"""Record a sack entering a feeder zone. feeder: 'left' | 'right'.
|
||||||
|
|
||||||
|
Returns (total_count, day_started, counted).
|
||||||
|
"""
|
||||||
if feeder not in ('left', 'right'):
|
if feeder not in ('left', 'right'):
|
||||||
raise ValueError(f"feeder must be 'left' or 'right', got {feeder!r}")
|
raise ValueError(f"feeder must be 'left' or 'right', got {feeder!r}")
|
||||||
with self.state_lock:
|
with self.state_lock:
|
||||||
@@ -144,6 +160,7 @@ class CounterStore:
|
|||||||
self._start_new_day(counting_date)
|
self._start_new_day(counting_date)
|
||||||
day_started = True
|
day_started = True
|
||||||
|
|
||||||
|
counted = False
|
||||||
event_key = f"{track_id}_{feeder}"
|
event_key = f"{track_id}_{feeder}"
|
||||||
if event_key not in self.current_state['counted_event_ids']:
|
if event_key not in self.current_state['counted_event_ids']:
|
||||||
self.current_state['count'] += 1
|
self.current_state['count'] += 1
|
||||||
@@ -152,6 +169,7 @@ class CounterStore:
|
|||||||
else:
|
else:
|
||||||
self.current_state['count_right'] += 1
|
self.current_state['count_right'] += 1
|
||||||
self.current_state['counted_event_ids'].append(event_key)
|
self.current_state['counted_event_ids'].append(event_key)
|
||||||
|
counted = True
|
||||||
self.log(
|
self.log(
|
||||||
f'Counted {feeder} feeder (track {track_id}) | {counting_date} '
|
f'Counted {feeder} feeder (track {track_id}) | {counting_date} '
|
||||||
f'total: {self.current_state["count"]} '
|
f'total: {self.current_state["count"]} '
|
||||||
@@ -162,7 +180,7 @@ class CounterStore:
|
|||||||
|
|
||||||
self.current_state['last_detection_time'] = datetime.now().isoformat()
|
self.current_state['last_detection_time'] = datetime.now().isoformat()
|
||||||
self.save_state()
|
self.save_state()
|
||||||
return self.current_state['count'], day_started
|
return self.current_state['count'], day_started, counted
|
||||||
|
|
||||||
def _persist_day(self):
|
def _persist_day(self):
|
||||||
state = self.current_state
|
state = self.current_state
|
||||||
|
|||||||
Reference in new issue
Block a user