diff --git a/.env.example b/.env.example index 41ac89c..7ec6981 100644 --- a/.env.example +++ b/.env.example @@ -34,6 +34,7 @@ LINE_X= LINE_X_FRAC=0.5 DAILY_CUTOFF_TIME=17:00 +RESET_COUNTERS_AT_CUTOFF=true BATCH_TIMEOUT_SECONDS=300 IGNORE_BATCH_LABEL_TIMEOUT_SECONDS=30 MIN_OBJECT_PER_BATCH=60 diff --git a/build/bytetrack-counter b/build/bytetrack-counter index e9b43a2..813b6da 100755 Binary files a/build/bytetrack-counter and b/build/bytetrack-counter differ diff --git a/build/version.hpp b/build/version.hpp index 576cf18..de98d19 100644 --- a/build/version.hpp +++ b/build/version.hpp @@ -4,11 +4,11 @@ namespace version { -const std::string GIT_COMMIT = "d66af69c"; +const std::string GIT_COMMIT = "e6dc2739"; const std::string GIT_BRANCH = "main"; const std::string GIT_TAG = ""; const std::string BUILD_DATE = "2026-07-06"; -const std::string BUILD_TIME = "10:23:30"; +const std::string BUILD_TIME = "11:31:15"; const int BUILD_YEAR = 2026; const bool BUILD_RKNN = 1; diff --git a/config.env.example b/config.env.example index 91e0b63..dcba75e 100644 --- a/config.env.example +++ b/config.env.example @@ -92,6 +92,8 @@ LINE_X_FRAC=0.5 # CUTOFF_TIME is an alias used by the dashboard; DAILY_CUTOFF_TIME takes priority in counter_live_rknn_bytetrack.py. DAILY_CUTOFF_TIME=20:00 CUTOFF_TIME=20:00 +# Reset frame counter and ByteTrack track-ID counter back to 0 when the daily cutoff is reached (true/false, default: true) +RESET_COUNTERS_AT_CUTOFF=true # Seconds of inactivity after which the current batch is auto-closed BATCH_TIMEOUT_SECONDS=300 # Seconds a newly-opened batch ignores the talenan label before accepting a close trigger diff --git a/src/batch_store.cpp b/src/batch_store.cpp index 3c2f733..75d8af9 100644 --- a/src/batch_store.cpp +++ b/src/batch_store.cpp @@ -250,6 +250,7 @@ std::pair BatchStore::record_ayam_crossing(int track_id) { end_batch_locked("cutoff"); start_new_batch(counting_date); started_new = true; + cutoff_triggered_ = true; } std::string event_key = std::to_string(track_id); @@ -380,6 +381,10 @@ int BatchStore::display_total() { return get_closed_total_for_day(get_counting_date()) + current_batch_count(); } +bool BatchStore::check_cutoff_reset() { + return cutoff_triggered_.exchange(false); +} + int BatchStore::current_batch_number() const { if (current_state_.is_null()) return 0; return current_state_.value("batch_number", 0); @@ -398,6 +403,7 @@ void BatchStore::cutoff_watcher_loop() { if (current_state_["counting_date"].get() != get_counting_date()) { logger_("Daily cutoff reached - finalizing batch"); end_batch_locked("cutoff"); + cutoff_triggered_ = true; } } } diff --git a/src/batch_store.hpp b/src/batch_store.hpp index d0cd719..e907c3c 100644 --- a/src/batch_store.hpp +++ b/src/batch_store.hpp @@ -31,6 +31,8 @@ public: int current_batch_count() const; int display_total(); + bool check_cutoff_reset(); + std::pair record_ayam_crossing(int track_id); bool record_talenan_crossing(int track_id); void end_batch(const std::string& closed_by = "manual"); @@ -75,6 +77,7 @@ private: std::atomic ignore_label_active_{false}; std::atomic shutdown_flag_{false}; std::atomic ignore_batch_label_{false}; + std::atomic cutoff_triggered_{false}; json current_state_; json previous_state_; diff --git a/src/bytetrack.cpp b/src/bytetrack.cpp index 0e073a2..bde2d2a 100644 --- a/src/bytetrack.cpp +++ b/src/bytetrack.cpp @@ -55,6 +55,13 @@ ByteTracker::ByteTracker(float track_high_thresh, float track_low_thresh, : high_thresh_(track_high_thresh), low_thresh_(track_low_thresh), match_thresh_(match_thresh), track_buffer_(track_buffer), min_hits_(min_hits) {} +void ByteTracker::reset() { + tracked_tracks_.clear(); + lost_tracks_.clear(); + removed_tracks_.clear(); + frame_id_ = 0; +} + TrackResult ByteTracker::update(const Eigen::MatrixXf& boxes_xyxy, const Eigen::VectorXf& scores) { frame_id_++; diff --git a/src/bytetrack.hpp b/src/bytetrack.hpp index 18d4c7b..91247bd 100644 --- a/src/bytetrack.hpp +++ b/src/bytetrack.hpp @@ -41,6 +41,7 @@ public: int min_hits = 3); TrackResult update(const Eigen::MatrixXf& boxes_xyxy, const Eigen::VectorXf& scores); + void reset(); private: float high_thresh_; diff --git a/src/config.cpp b/src/config.cpp index 479c32a..882618e 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -104,6 +104,8 @@ void AppConfig::load_from_env(const char* env_path) { if (!rw_s.empty()) rate_window_sec = std::stoi(rw_s); daily_cutoff_time = get_env("DAILY_CUTOFF_TIME", daily_cutoff_time); + auto rcc_s = get_env("RESET_COUNTERS_AT_CUTOFF"); + if (!rcc_s.empty()) reset_counters_at_cutoff = (rcc_s == "true"); auto bto_s = get_env("BATCH_TIMEOUT_SECONDS"); if (!bto_s.empty()) batch_timeout_seconds = std::stof(bto_s); auto ibl_s = get_env("IGNORE_BATCH_LABEL_TIMEOUT_SECONDS"); diff --git a/src/config.hpp b/src/config.hpp index 85f66fb..cbc280d 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -42,6 +42,7 @@ struct AppConfig { int rate_window_sec = 60; std::string daily_cutoff_time = "20:00"; + bool reset_counters_at_cutoff = true; float batch_timeout_seconds = 300.0f; float ignore_batch_label_timeout = 30.0f; int min_object_per_batch = 60; diff --git a/src/main.cpp b/src/main.cpp index 559254a..3a1c499 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -232,6 +232,24 @@ int main(int argc, char* argv[]) { std::chrono::steady_clock::now() - session_start).count(); auto mono = std::chrono::steady_clock::now(); + if (g_config.reset_counters_at_cutoff && store.check_cutoff_reset()) { + std::cout << "[" << now_str() << "] Cutoff reset — resetting frame + tracker counters" << std::endl; + frame_idx = 0; + KalmanBoxTracker::count = 0; + ayam_tracker.reset(); + talenan_tracker.reset(); + ayam_tracked.clear(); + talenan_tracked.clear(); + ayam_line_crossed.clear(); + talenan_line_crossed.clear(); + ayam_cross_flash.clear(); + talenan_cross_flash.clear(); + crossing_times.clear(); + line_pulse = 0; + count_pulse = 0; + batch_pulse = 0; + } + bool ayam_crossed_frame = false, batch_closed_frame = false, batch_started_frame = false; auto inf_start = std::chrono::steady_clock::now();