From 41c4a558b12bc36b6e7be95ae5ee5912cf808b29 Mon Sep 17 00:00:00 2001 From: Alberto-Audrix Date: Wed, 5 Aug 2026 09:25:04 +0700 Subject: [PATCH] fix counter bug --- counter_live_rknn.py | 19 +++++++++++++------ counter_store.py | 23 ++++++++++++++++++++--- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/counter_live_rknn.py b/counter_live_rknn.py index 013d034..285df8d 100644 --- a/counter_live_rknn.py +++ b/counter_live_rknn.py @@ -1215,8 +1215,9 @@ def run(): frames_since_infer = 0 video_writer = None crossing_times = deque() - counter_in = 0 - counter_out = 0 + # Overlay shows daily store totals (resume-safe, resets on counting-day change). + counter_in = store.current_count_in + counter_out = store.current_count_out last_snapshot_cleanup = 0.0 counting_active = True @@ -1495,13 +1496,17 @@ def run(): recent.append((frame_idx, cx)) st["counted"] = True + _, _, counted = store.record_object_crossing(tid, direction) + counter_in = store.current_count_in + counter_out = store.current_count_out + if not counted: + # Dedup in the store rejected this event; skip overlay/CSV. + object_tracked[tid] = (cx, cy, mono) + continue if direction == "in": - counter_in += 1 count_in_pulse = COUNT_PULSE_FRAMES else: - counter_out += 1 count_out_pulse = COUNT_PULSE_FRAMES - store.record_object_crossing(tid, direction) if cross_logger: cross_logger.write_row( [ @@ -1550,7 +1555,9 @@ def run(): if object_crossed_frame: line_pulse = LINE_PULSE_FRAMES - display_total = store.display_total() + # Keep overlay aligned with daily store (also resets after cutoff). + counter_in = store.current_count_in + counter_out = store.current_count_out while crossing_times and mono - crossing_times[0] > RATE_WINDOW_SEC: crossing_times.popleft() rate = (len(crossing_times) / RATE_WINDOW_SEC * 60) if crossing_times else 0.0 diff --git a/counter_store.py b/counter_store.py index f01f956..965df25 100644 --- a/counter_store.py +++ b/counter_store.py @@ -88,11 +88,23 @@ class CounterStore: state.setdefault('count_in', 0) state.setdefault('count_out', 0) state.setdefault('count', state['count_in'] + state['count_out']) - state.setdefault('counted_event_ids', []) + # Track IDs are process-local and restart from 1 after every process + # start. Persisted dedup keys like "5_in" 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( f"Resumed {current_date} with total={state['count']} " f"(in={state['count_in']} out={state['count_out']})" ) + with open(self.state_file, 'w', encoding='utf-8') as f: + json.dump(state, f, indent=2, ensure_ascii=False) return state except Exception as exc: self.log(f'Failed to load state file: {exc}') @@ -126,7 +138,10 @@ class CounterStore: self.log(f'Started counting day {counting_date} ({self.object_label})') def record_object_crossing(self, track_id, direction): - """Record an object crossing a counting line. direction: 'in' | 'out'.""" + """Record an object crossing a counting line. direction: 'in' | 'out'. + + Returns (total_count, day_started, counted). + """ with self.state_lock: counting_date = self.get_counting_date() day_started = False @@ -134,6 +149,7 @@ class CounterStore: self._start_new_day(counting_date) day_started = True + counted = False event_key = f"{track_id}_{direction}" if event_key not in self.current_state['counted_event_ids']: self.current_state['count'] += 1 @@ -142,6 +158,7 @@ class CounterStore: else: self.current_state['count_out'] += 1 self.current_state['counted_event_ids'].append(event_key) + counted = True self.log( f'Counted {direction} (track {track_id}) | {counting_date} ' f'total: {self.current_state["count"]} ' @@ -151,7 +168,7 @@ class CounterStore: self.current_state['last_detection_time'] = datetime.now().isoformat() self.save_state() - return self.current_state['count'], day_started + return self.current_state['count'], day_started, counted def _persist_day(self): state = self.current_state