diff --git a/.env b/.env index 43e73a8..2007852 100644 --- a/.env +++ b/.env @@ -1,17 +1,20 @@ # Edge RK3588 production counter — copy to .env on device -# cp .env.example .env && nano .env +# cp config.env.example .env && nano .env -OUTPUT_DIR=/opt/bytetrack-counter-cpp -DB_PATH=/opt/bytetrack-counter-cpp/bytetrack_counter.db +#DEBUG_TRACKING=true +SITE_NAME=Salatiga + +OUTPUT_DIR=/opt/bytetrack-counter +DB_PATH=/opt/bytetrack-counter/bytetrack_counter.db STATE_FILE=/tmp/bytetrack_current_batch.json # Direct LAN camera RTSP (low latency) -#SOURCE=rtsp://frigate:zenai@192.168.192.16:8554/camera_stream_640 -SOURCE=rtsp://192.168.192.53:8554/my_stream +#SOURCE=rtsp://frigate:zenai@127.0.0.1:8554/camera_stream_640 +SOURCE=rtsp://10.38.30.64:8554/my_stream OPENCV_FFMPEG_CAPTURE_OPTIONS=rtsp_transport;tcp|fflags;nobuffer|flags;low_delay -# RKNN model — export'd from YOLO with imgsz=320 -MODEL_PATH=/opt/models/zenai_apc_cicalengka_20260609.rknn +# RKNN model — export'd from YOLO9t with imgsz=320 +MODEL_PATH=/opt/models/zenai_apc_salatiga_20260703.rknn IMGSZ=320 HALF=false CONF=0.3 @@ -21,24 +24,31 @@ CORE_MASK=7 # YOLO decoder params (must match model export) NUM_CLASSES=2 -SCORE_SIGMOID=false +NUM_KEYPOINTS=9 +REG_MAX=16 +STRIDES=8,16,32 -CAMERA_NAME=CC1 +CAMERA_NAME=ZenAi OBJECT_LABEL=ayam-potong CLASS_AYAM=ayam -CLASS_TALENAN=telenan +CLASS_TALENAN=talenan # Line crossing: rtl (default) | ltr | both -CROSS_DIRECTION=ltr +CROSS_DIRECTION=rtl LINE_X= LINE_X_FRAC=0.5 -DAILY_CUTOFF_TIME=17:00 +DAILY_CUTOFF_TIME=20:00 +CUTOFF_TIME=20:00 BATCH_TIMEOUT_SECONDS=300 IGNORE_BATCH_LABEL_TIMEOUT_SECONDS=30 MIN_OBJECT_PER_BATCH=60 MIN_DURATION_PER_BATCH=60 +DASHBOARD_HOST=0.0.0.0 +DASHBOARD_PORT=5001 +SECRET_KEY=change-me-in-production + EXPORT_CSV=true RECORD_VIDEO=false @@ -47,6 +57,14 @@ LIVE_STREAM_FRAME_PATH=/dev/shm/bytetrack-counter/live_frame.jpg LIVE_STREAM_QUALITY=75 LIVE_STREAM_EVERY_N=2 -LOG_LEVEL=info +# Lower high_thresh to match CONF so all valid detections create tracks +TRACK_HIGH_THRESH_0=0.3 +TRACK_HIGH_THRESH_1=0.3 -DASHBOARD_PORT=5001 +# Relax match_thresh for ayam (0.8 is too strict, IoU must be > 0.8 to keep identity) +TRACK_MATCH_THRESH_0=0.5 +TRACK_MATCH_THRESH_1=0.5 + +# Lower low_thresh below CONF so filtering doesn't interfere +TRACK_LOW_THRESH_0=0.1 +TRACK_LOW_THRESH_1=0.1 diff --git a/.gitignore b/.gitignore index e257658..cfde0b4 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,21 @@ *.out *.app +# ---> Build +build/ + +# ---> Environment (contains secrets) +.env + +# ---> Runtime artifacts +*.db +*.csv +current_batch.json + +# ---> IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + diff --git a/CMakeLists.txt b/CMakeLists.txt index 7dc4f13..70eed2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,10 @@ set(CMAKE_CXX_EXTENSIONS OFF) find_package(OpenCV REQUIRED COMPONENTS core imgproc videoio highgui imgcodecs) set(Eigen3_DIR /usr/share/eigen3/cmake) find_package(Eigen3 REQUIRED NO_MODULE) +find_package(nlohmann_json REQUIRED) find_package(SQLite3 REQUIRED) -option(HAS_RKNN "Build with RKNN NPU support" OFF) +option(HAS_RKNN "Build with RKNN NPU support" ON) if(HAS_RKNN) add_definitions(-DHAS_RKNN) @@ -52,4 +53,4 @@ if(HAS_RKNN) endif() endif() -install(TARGETS bytetrack-counter DESTINATION /opt/bytetrack-counter-cpp/bin) +install(TARGETS bytetrack-counter DESTINATION /opt/bytetrack-counter-cpp/build) diff --git a/RUN.md b/RUN.md new file mode 100644 index 0000000..6d99b68 --- /dev/null +++ b/RUN.md @@ -0,0 +1,36 @@ +# ByteTrack Counter C++ — Run Instructions + +## Run from build directory + +```bash +cd /opt/bytetrack-counter-cpp/build +./bytetrack-counter /opt/bytetrack-counter-cpp/.env +``` + +The `.env` path is passed as the first argument. If omitted, it defaults to `.env` in the current working directory: + +```bash +./bytetrack-counter # looks for .env in CWD +./bytetrack-counter .env # same +``` + +You can also set `ENV_FILE` environment variable instead: + +```bash +ENV_FILE=/opt/bytetrack-counter-cpp/.env ./bytetrack-counter +``` + +## Run as systemd service + +```bash +systemctl restart bytetrack-counter +journalctl -u bytetrack-counter -f +``` + +## Build + +```bash +cd /opt/bytetrack-counter-cpp/build +cmake .. -DHAS_RKNN=ON +make -j$(nproc) +``` diff --git a/batch_crossings.csv b/batch_crossings.csv index 455a40c..08835ef 100644 --- a/batch_crossings.csv +++ b/batch_crossings.csv @@ -1648,3 +1648,1488 @@ batch,frame,timestamp,chicken_id 2,2258,2026-07-01 19:28:26,130 2,2273,2026-07-01 19:28:27,131 2,2288,2026-07-01 19:28:28,132 +2,2303,2026-07-01 19:28:28,133 +2,2318,2026-07-01 19:28:29,134 +2,2332,2026-07-01 19:28:29,135 +2,2347,2026-07-01 19:28:30,136 +2,2362,2026-07-01 19:28:31,137 +2,2377,2026-07-01 19:28:31,138 +2,2391,2026-07-01 19:28:32,139 +2,2407,2026-07-01 19:28:32,140 +2,2422,2026-07-01 19:28:33,141 +2,2436,2026-07-01 19:28:34,142 +2,2451,2026-07-01 19:28:34,143 +2,2465,2026-07-01 19:28:35,144 +2,2481,2026-07-01 19:28:36,145 +2,2496,2026-07-01 19:28:36,146 +2,2511,2026-07-01 19:28:37,147 +2,2526,2026-07-01 19:28:37,148 +2,2540,2026-07-01 19:28:38,149 +2,2555,2026-07-01 19:28:38,150 +2,2570,2026-07-01 19:28:39,151 +2,2585,2026-07-01 19:28:40,152 +2,2599,2026-07-01 19:28:40,153 +2,2614,2026-07-01 19:28:41,154 +2,2629,2026-07-01 19:28:42,155 +2,2645,2026-07-01 19:28:42,156 +2,2659,2026-07-01 19:28:43,157 +2,2674,2026-07-01 19:28:43,158 +2,2689,2026-07-01 19:28:44,159 +2,2703,2026-07-01 19:28:44,160 +2,2718,2026-07-01 19:28:45,161 +2,2733,2026-07-01 19:28:45,162 +2,2749,2026-07-01 19:28:46,163 +2,2763,2026-07-01 19:28:47,164 +2,2779,2026-07-01 19:28:47,165 +2,2793,2026-07-01 19:28:48,166 +2,2808,2026-07-01 19:28:49,167 +2,2822,2026-07-01 19:28:49,168 +2,2837,2026-07-01 19:28:50,169 +2,2852,2026-07-01 19:28:50,170 +2,2868,2026-07-01 19:28:51,171 +2,2883,2026-07-01 19:28:51,172 +2,2898,2026-07-01 19:28:52,173 +2,2912,2026-07-01 19:28:53,174 +2,2927,2026-07-01 19:28:53,175 +2,2942,2026-07-01 19:28:54,176 +2,2957,2026-07-01 19:28:54,177 +2,2972,2026-07-01 19:28:55,178 +2,2987,2026-07-01 19:28:56,179 +2,3002,2026-07-01 19:28:56,180 +2,3017,2026-07-01 19:28:57,181 +2,3032,2026-07-01 19:28:57,182 +2,3046,2026-07-01 19:28:58,183 +2,3062,2026-07-01 19:28:59,184 +2,3076,2026-07-01 19:28:59,185 +2,3091,2026-07-01 19:29:00,186 +2,3106,2026-07-01 19:29:00,187 +2,3121,2026-07-01 19:29:01,188 +2,3136,2026-07-01 19:29:02,189 +2,3151,2026-07-01 19:29:02,190 +2,3166,2026-07-01 19:29:03,191 +2,3181,2026-07-01 19:29:03,192 +2,3196,2026-07-01 19:29:04,193 +2,3211,2026-07-01 19:29:05,194 +2,3226,2026-07-01 19:29:05,195 +2,3240,2026-07-01 19:29:06,196 +2,3255,2026-07-01 19:29:06,197 +2,3270,2026-07-01 19:29:07,198 +2,3285,2026-07-01 19:29:08,199 +2,3300,2026-07-01 19:29:08,200 +2,3316,2026-07-01 19:29:09,201 +2,3330,2026-07-01 19:29:09,202 +2,3345,2026-07-01 19:29:10,203 +2,3360,2026-07-01 19:29:11,204 +2,3375,2026-07-01 19:29:11,205 +2,3390,2026-07-01 19:29:12,206 +2,3404,2026-07-01 19:29:12,207 +2,3419,2026-07-01 19:29:13,208 +2,3434,2026-07-01 19:29:13,209 +2,3449,2026-07-01 19:29:14,210 +2,3464,2026-07-01 19:29:15,211 +2,3479,2026-07-01 19:29:15,212 +2,3493,2026-07-01 19:29:16,213 +2,3508,2026-07-01 19:29:16,214 +2,3522,2026-07-01 19:29:17,215 +2,3538,2026-07-01 19:29:18,216 +2,3553,2026-07-01 19:29:18,217 +2,3569,2026-07-01 19:29:19,218 +2,3583,2026-07-01 19:29:20,219 +2,3598,2026-07-01 19:29:20,220 +2,3613,2026-07-01 19:29:21,221 +2,3628,2026-07-01 19:29:21,222 +2,3643,2026-07-01 19:29:22,223 +2,3658,2026-07-01 19:29:22,224 +2,3673,2026-07-01 19:29:23,225 +2,3688,2026-07-01 19:29:24,226 +2,3703,2026-07-01 19:29:24,227 +2,3718,2026-07-01 19:29:25,228 +2,3732,2026-07-01 19:29:26,229 +2,3747,2026-07-01 19:29:26,230 +2,3762,2026-07-01 19:29:27,231 +2,3777,2026-07-01 19:29:27,232 +2,3792,2026-07-01 19:29:28,233 +2,3807,2026-07-01 19:29:28,234 +2,3822,2026-07-01 19:29:29,235 +2,3837,2026-07-01 19:29:30,236 +2,3852,2026-07-01 19:29:30,237 +2,3867,2026-07-01 19:29:31,238 +2,3882,2026-07-01 19:29:31,239 +2,3896,2026-07-01 19:29:32,240 +2,3913,2026-07-01 19:29:33,241 +2,3926,2026-07-01 19:29:33,245 +2,3942,2026-07-01 19:29:34,251 +2,3956,2026-07-01 19:29:34,247 +2,3971,2026-07-01 19:29:35,252 +2,3986,2026-07-01 19:29:36,253 +2,4001,2026-07-01 19:29:36,254 +2,4016,2026-07-01 19:29:37,255 +2,4031,2026-07-01 19:29:37,256 +2,4046,2026-07-01 19:29:38,257 +2,4062,2026-07-01 19:29:39,258 +2,4075,2026-07-01 19:29:39,259 +2,4090,2026-07-01 19:29:40,260 +2,4105,2026-07-01 19:29:40,261 +2,4121,2026-07-01 19:29:41,262 +2,4136,2026-07-01 19:29:42,263 +2,4150,2026-07-01 19:29:42,264 +2,4165,2026-07-01 19:29:43,265 +2,4180,2026-07-01 19:29:43,266 +2,4195,2026-07-01 19:29:44,267 +2,4210,2026-07-01 19:29:45,268 +2,4224,2026-07-01 19:29:45,269 +2,4240,2026-07-01 19:29:46,271 +2,4254,2026-07-01 19:29:46,270 +2,4269,2026-07-01 19:29:47,272 +2,4285,2026-07-01 19:29:48,273 +2,4299,2026-07-01 19:29:48,274 +2,4315,2026-07-01 19:29:49,275 +2,4329,2026-07-01 19:29:49,276 +2,4344,2026-07-01 19:29:50,277 +2,4359,2026-07-01 19:29:50,278 +2,4374,2026-07-01 19:29:51,279 +2,4388,2026-07-01 19:29:52,280 +2,4404,2026-07-01 19:29:52,281 +2,4418,2026-07-01 19:29:53,282 +2,4433,2026-07-01 19:29:54,283 +2,4447,2026-07-01 19:29:54,284 +2,4463,2026-07-01 19:29:55,285 +2,4478,2026-07-01 19:29:55,286 +2,4493,2026-07-01 19:29:56,287 +2,4508,2026-07-01 19:29:56,288 +2,4523,2026-07-01 19:29:57,289 +2,4538,2026-07-01 19:29:58,290 +2,4553,2026-07-01 19:29:58,291 +2,4568,2026-07-01 19:29:59,292 +2,4583,2026-07-01 19:29:59,293 +2,4597,2026-07-01 19:30:00,294 +2,4612,2026-07-01 19:30:01,295 +2,4627,2026-07-01 19:30:01,296 +2,4642,2026-07-01 19:30:02,297 +2,4657,2026-07-01 19:30:02,298 +2,4671,2026-07-01 19:30:03,299 +2,4687,2026-07-01 19:30:04,300 +2,4702,2026-07-01 19:30:04,301 +2,4716,2026-07-01 19:30:05,302 +2,4731,2026-07-01 19:30:05,303 +2,4746,2026-07-01 19:30:06,304 +2,4761,2026-07-01 19:30:07,305 +2,4777,2026-07-01 19:30:07,306 +2,4791,2026-07-01 19:30:08,307 +2,4806,2026-07-01 19:30:08,308 +2,4821,2026-07-01 19:30:09,309 +2,4836,2026-07-01 19:30:10,310 +2,4851,2026-07-01 19:30:10,311 +2,4866,2026-07-01 19:30:11,313 +2,4881,2026-07-01 19:30:11,312 +2,4895,2026-07-01 19:30:12,314 +2,4910,2026-07-01 19:30:13,315 +2,4925,2026-07-01 19:30:13,316 +2,4940,2026-07-01 19:30:14,317 +2,4955,2026-07-01 19:30:14,318 +2,4970,2026-07-01 19:30:15,319 +2,4985,2026-07-01 19:30:16,320 +2,4999,2026-07-01 19:30:16,321 +2,5014,2026-07-01 19:30:17,322 +2,5030,2026-07-01 19:30:17,323 +2,5045,2026-07-01 19:30:18,324 +2,5058,2026-07-01 19:30:18,325 +2,5073,2026-07-01 19:30:19,326 +2,5089,2026-07-01 19:30:20,327 +2,5103,2026-07-01 19:30:20,328 +2,5119,2026-07-01 19:30:21,329 +2,5133,2026-07-01 19:30:21,330 +2,5148,2026-07-01 19:30:22,331 +2,5164,2026-07-01 19:30:23,332 +2,5179,2026-07-01 19:30:23,333 +2,5194,2026-07-01 19:30:24,334 +2,5209,2026-07-01 19:30:24,335 +2,5224,2026-07-01 19:30:25,336 +2,5239,2026-07-01 19:30:26,337 +2,5253,2026-07-01 19:30:26,338 +2,5269,2026-07-01 19:30:27,339 +2,5283,2026-07-01 19:30:28,340 +2,5298,2026-07-01 19:30:28,341 +2,5313,2026-07-01 19:30:29,342 +2,5328,2026-07-01 19:30:29,343 +2,5342,2026-07-01 19:30:30,344 +2,5358,2026-07-01 19:30:30,345 +2,5372,2026-07-01 19:30:31,346 +2,5387,2026-07-01 19:30:32,347 +2,5403,2026-07-01 19:30:32,348 +2,5418,2026-07-01 19:30:33,349 +2,5432,2026-07-01 19:30:33,350 +2,5448,2026-07-01 19:30:34,351 +2,5463,2026-07-01 19:30:35,352 +2,5477,2026-07-01 19:30:35,353 +2,5492,2026-07-01 19:30:36,354 +2,5507,2026-07-01 19:30:37,355 +2,5522,2026-07-01 19:30:37,356 +2,5536,2026-07-01 19:30:38,357 +2,5552,2026-07-01 19:30:38,358 +2,5567,2026-07-01 19:30:39,359 +2,5581,2026-07-01 19:30:39,360 +2,5596,2026-07-01 19:30:40,361 +2,5611,2026-07-01 19:30:41,362 +2,5626,2026-07-01 19:30:41,363 +2,5642,2026-07-01 19:30:42,364 +2,5656,2026-07-01 19:30:42,365 +2,5671,2026-07-01 19:30:43,366 +2,5686,2026-07-01 19:30:44,367 +2,5701,2026-07-01 19:30:44,368 +2,5715,2026-07-01 19:30:45,370 +2,5730,2026-07-01 19:30:45,369 +2,5745,2026-07-01 19:30:46,371 +2,5759,2026-07-01 19:30:47,372 +2,5775,2026-07-01 19:30:47,373 +2,5790,2026-07-01 19:30:48,374 +2,5804,2026-07-01 19:30:48,375 +2,5820,2026-07-01 19:30:49,376 +2,5835,2026-07-01 19:30:50,377 +2,5850,2026-07-01 19:30:50,378 +2,5865,2026-07-01 19:30:51,379 +2,5880,2026-07-01 19:30:51,380 +2,5894,2026-07-01 19:30:52,381 +2,5912,2026-07-01 19:30:53,382 +2,5925,2026-07-01 19:30:53,391 +2,5939,2026-07-01 19:30:54,387 +2,5954,2026-07-01 19:30:54,389 +2,5970,2026-07-01 19:30:55,393 +2,5985,2026-07-01 19:30:56,394 +2,6000,2026-07-01 19:30:56,395 +2,6014,2026-07-01 19:30:57,396 +2,6029,2026-07-01 19:30:57,397 +2,6044,2026-07-01 19:30:58,398 +2,6059,2026-07-01 19:30:58,399 +2,6073,2026-07-01 19:30:59,400 +2,6089,2026-07-01 19:31:00,401 +2,6103,2026-07-01 19:31:00,402 +2,6118,2026-07-01 19:31:01,403 +2,6133,2026-07-01 19:31:01,404 +2,6148,2026-07-01 19:31:02,405 +2,6164,2026-07-01 19:31:03,406 +2,6178,2026-07-01 19:31:03,407 +2,6193,2026-07-01 19:31:04,408 +2,6208,2026-07-01 19:31:04,409 +2,6223,2026-07-01 19:31:05,410 +2,6238,2026-07-01 19:31:06,411 +2,6253,2026-07-01 19:31:06,412 +2,6267,2026-07-01 19:31:07,413 +2,6282,2026-07-01 19:31:07,414 +2,6296,2026-07-01 19:31:08,415 +2,6311,2026-07-01 19:31:09,416 +2,6327,2026-07-01 19:31:09,417 +2,6342,2026-07-01 19:31:10,418 +2,6357,2026-07-01 19:31:10,419 +2,6373,2026-07-01 19:31:11,420 +2,6387,2026-07-01 19:31:12,421 +2,6402,2026-07-01 19:31:12,422 +2,6417,2026-07-01 19:31:13,423 +2,6432,2026-07-01 19:31:13,424 +2,6447,2026-07-01 19:31:14,425 +2,6462,2026-07-01 19:31:15,426 +2,6477,2026-07-01 19:31:15,427 +2,6491,2026-07-01 19:31:16,428 +2,6507,2026-07-01 19:31:17,429 +2,6521,2026-07-01 19:31:17,430 +2,6536,2026-07-01 19:31:18,431 +2,6551,2026-07-01 19:31:18,432 +2,6565,2026-07-01 19:31:19,433 +2,6581,2026-07-01 19:31:19,434 +2,6596,2026-07-01 19:31:20,435 +2,6610,2026-07-01 19:31:20,436 +2,6625,2026-07-01 19:31:21,437 +2,6640,2026-07-01 19:31:22,438 +2,6655,2026-07-01 19:31:22,439 +2,6670,2026-07-01 19:31:23,440 +2,6685,2026-07-01 19:31:24,441 +2,6700,2026-07-01 19:31:24,442 +2,6715,2026-07-01 19:31:25,443 +2,6730,2026-07-01 19:31:25,444 +2,6745,2026-07-01 19:31:26,445 +2,6760,2026-07-01 19:31:27,446 +2,6775,2026-07-01 19:31:27,447 +2,6789,2026-07-01 19:31:28,448 +2,6805,2026-07-01 19:31:28,449 +2,6820,2026-07-01 19:31:29,450 +2,6834,2026-07-01 19:31:29,451 +2,6849,2026-07-01 19:31:30,452 +2,6863,2026-07-01 19:31:31,453 +2,6879,2026-07-01 19:31:31,454 +2,6894,2026-07-01 19:31:32,455 +2,6909,2026-07-01 19:31:33,456 +2,6923,2026-07-01 19:31:33,457 +2,6939,2026-07-01 19:31:34,458 +2,6953,2026-07-01 19:31:34,459 +2,6968,2026-07-01 19:31:35,460 +2,6983,2026-07-01 19:31:36,461 +2,6998,2026-07-01 19:31:36,462 +2,7013,2026-07-01 19:31:37,463 +2,7028,2026-07-01 19:31:37,464 +2,7042,2026-07-01 19:31:38,465 +2,7058,2026-07-01 19:31:39,466 +2,7073,2026-07-01 19:31:39,467 +2,7087,2026-07-01 19:31:40,468 +2,7102,2026-07-01 19:31:40,469 +2,7117,2026-07-01 19:31:41,470 +2,7132,2026-07-01 19:31:41,471 +2,7146,2026-07-01 19:31:42,472 +2,7161,2026-07-01 19:31:43,473 +2,7176,2026-07-01 19:31:43,474 +2,7192,2026-07-01 19:31:44,475 +2,7207,2026-07-01 19:31:44,476 +2,7221,2026-07-01 19:31:45,477 +2,7236,2026-07-01 19:31:46,478 +2,7251,2026-07-01 19:31:46,479 +2,7266,2026-07-01 19:31:47,480 +2,7280,2026-07-01 19:31:47,481 +2,7296,2026-07-01 19:31:48,482 +2,7312,2026-07-01 19:31:49,483 +2,7326,2026-07-01 19:31:49,484 +2,7340,2026-07-01 19:31:50,485 +2,7356,2026-07-01 19:31:50,486 +2,7371,2026-07-01 19:31:51,487 +2,7385,2026-07-01 19:31:52,488 +2,7399,2026-07-01 19:31:52,489 +2,7415,2026-07-01 19:31:53,491 +2,7429,2026-07-01 19:31:53,490 +2,7445,2026-07-01 19:31:54,492 +2,7460,2026-07-01 19:31:55,493 +2,7474,2026-07-01 19:31:55,494 +2,7490,2026-07-01 19:31:56,495 +2,7505,2026-07-01 19:31:56,496 +2,7519,2026-07-01 19:31:57,497 +2,7534,2026-07-01 19:31:58,498 +2,7549,2026-07-01 19:31:58,499 +2,7564,2026-07-01 19:31:59,500 +2,7579,2026-07-01 19:31:59,501 +2,7594,2026-07-01 19:32:00,502 +2,7609,2026-07-01 19:32:00,503 +2,7624,2026-07-01 19:32:01,504 +2,7638,2026-07-01 19:32:02,505 +2,7654,2026-07-01 19:32:02,506 +2,7669,2026-07-01 19:32:03,507 +2,7683,2026-07-01 19:32:03,508 +2,7699,2026-07-01 19:32:04,509 +2,7714,2026-07-01 19:32:05,510 +2,7728,2026-07-01 19:32:05,511 +2,7743,2026-07-01 19:32:06,512 +2,7758,2026-07-01 19:32:07,513 +2,7773,2026-07-01 19:32:07,514 +2,7788,2026-07-01 19:32:08,515 +2,7803,2026-07-01 19:32:08,516 +2,7818,2026-07-01 19:32:09,517 +2,7833,2026-07-01 19:32:10,518 +2,7848,2026-07-01 19:32:10,519 +2,7864,2026-07-01 19:32:11,520 +2,7877,2026-07-01 19:32:11,521 +2,7892,2026-07-01 19:32:12,522 +2,7907,2026-07-01 19:32:12,523 +2,7922,2026-07-01 19:32:13,524 +2,7938,2026-07-01 19:32:14,525 +2,7952,2026-07-01 19:32:14,526 +2,7968,2026-07-01 19:32:15,527 +2,7982,2026-07-01 19:32:15,528 +2,7997,2026-07-01 19:32:16,529 +2,8012,2026-07-01 19:32:17,530 +2,8026,2026-07-01 19:32:17,531 +2,8041,2026-07-01 19:32:18,532 +2,8056,2026-07-01 19:32:18,533 +2,8071,2026-07-01 19:32:19,534 +2,8086,2026-07-01 19:32:20,535 +2,8101,2026-07-01 19:32:20,536 +2,8116,2026-07-01 19:32:21,537 +2,8131,2026-07-01 19:32:21,538 +2,8146,2026-07-01 19:32:22,539 +2,8162,2026-07-01 19:32:23,540 +2,8176,2026-07-01 19:32:23,541 +2,8191,2026-07-01 19:32:24,542 +2,8206,2026-07-01 19:32:24,543 +2,8220,2026-07-01 19:32:25,544 +2,8235,2026-07-01 19:32:26,545 +2,8250,2026-07-01 19:32:26,546 +2,8265,2026-07-01 19:32:27,547 +3,8280,2026-07-01 19:32:27,548 +3,8295,2026-07-01 19:32:28,549 +3,8311,2026-07-01 19:32:29,550 +3,8325,2026-07-01 19:32:29,551 +3,8339,2026-07-01 19:32:30,552 +3,8354,2026-07-01 19:32:30,553 +3,8370,2026-07-01 19:32:31,554 +3,8385,2026-07-01 19:32:32,555 +3,8399,2026-07-01 19:32:32,556 +3,8414,2026-07-01 19:32:33,557 +3,8429,2026-07-01 19:32:33,558 +3,8459,2026-07-01 19:32:34,563 +3,8474,2026-07-01 19:32:35,567 +3,8489,2026-07-01 19:32:36,564 +3,8503,2026-07-01 19:32:36,570 +3,8518,2026-07-01 19:32:37,571 +3,8533,2026-07-01 19:32:37,572 +3,8549,2026-07-01 19:32:38,573 +3,8566,2026-07-01 19:32:39,574 +3,8578,2026-07-01 19:32:39,575 +3,8593,2026-07-01 19:32:40,576 +3,8608,2026-07-01 19:32:40,577 +3,8623,2026-07-01 19:32:41,585 +3,8637,2026-07-01 19:32:42,584 +3,8652,2026-07-01 19:32:42,583 +3,8667,2026-07-01 19:32:43,588 +3,8683,2026-07-01 19:32:44,589 +3,8697,2026-07-01 19:32:44,590 +3,8713,2026-07-01 19:32:45,591 +3,8727,2026-07-01 19:32:45,592 +3,8742,2026-07-01 19:32:46,593 +3,8757,2026-07-01 19:32:46,594 +3,8771,2026-07-01 19:32:47,595 +3,8787,2026-07-01 19:32:48,596 +3,8802,2026-07-01 19:32:48,597 +3,8818,2026-07-01 19:32:49,598 +3,8832,2026-07-01 19:32:49,599 +3,8847,2026-07-01 19:32:50,600 +3,8862,2026-07-01 19:32:51,601 +3,8877,2026-07-01 19:32:51,602 +3,8892,2026-07-01 19:32:52,603 +3,8907,2026-07-01 19:32:52,604 +3,8921,2026-07-01 19:32:53,605 +3,8936,2026-07-01 19:32:54,606 +3,8952,2026-07-01 19:32:54,607 +3,8967,2026-07-01 19:32:55,608 +3,8982,2026-07-01 19:32:55,609 +3,8997,2026-07-01 19:32:56,610 +3,9012,2026-07-01 19:32:57,611 +3,9027,2026-07-01 19:32:57,612 +3,9042,2026-07-01 19:32:58,613 +3,9057,2026-07-01 19:32:59,614 +3,9071,2026-07-01 19:32:59,615 +3,9087,2026-07-01 19:33:00,616 +3,9102,2026-07-01 19:33:00,617 +3,9116,2026-07-01 19:33:01,618 +3,9131,2026-07-01 19:33:02,619 +3,9146,2026-07-01 19:33:02,620 +3,9162,2026-07-01 19:33:03,621 +3,9176,2026-07-01 19:33:03,622 +3,9194,2026-07-01 19:33:04,623 +3,9206,2026-07-01 19:33:04,624 +3,9221,2026-07-01 19:33:05,625 +3,9236,2026-07-01 19:33:06,626 +3,9251,2026-07-01 19:33:06,629 +3,9267,2026-07-01 19:33:07,630 +3,9282,2026-07-01 19:33:07,631 +3,9296,2026-07-01 19:33:08,632 +3,9311,2026-07-01 19:33:09,633 +3,9326,2026-07-01 19:33:09,634 +3,9342,2026-07-01 19:33:10,635 +3,9356,2026-07-01 19:33:10,636 +3,9371,2026-07-01 19:33:11,638 +3,9386,2026-07-01 19:33:12,637 +3,9401,2026-07-01 19:33:12,639 +3,9416,2026-07-01 19:33:13,640 +3,9431,2026-07-01 19:33:14,641 +3,9446,2026-07-01 19:33:14,642 +3,9462,2026-07-01 19:33:15,643 +3,9476,2026-07-01 19:33:15,644 +3,9490,2026-07-01 19:33:16,645 +3,9506,2026-07-01 19:33:16,646 +3,9521,2026-07-01 19:33:17,647 +3,9536,2026-07-01 19:33:18,648 +3,9551,2026-07-01 19:33:18,649 +3,9567,2026-07-01 19:33:19,650 +3,9580,2026-07-01 19:33:19,651 +3,9594,2026-07-01 19:33:20,652 +3,9610,2026-07-01 19:33:20,653 +3,9625,2026-07-01 19:33:21,654 +3,9640,2026-07-01 19:33:22,655 +3,9655,2026-07-01 19:33:22,656 +3,9670,2026-07-01 19:33:23,657 +3,9685,2026-07-01 19:33:24,658 +3,9699,2026-07-01 19:33:24,659 +3,9730,2026-07-01 19:33:25,668 +3,9744,2026-07-01 19:33:26,670 +3,9759,2026-07-01 19:33:26,669 +3,9774,2026-07-01 19:33:27,663 +3,9789,2026-07-01 19:33:28,673 +3,9805,2026-07-01 19:33:28,674 +3,9818,2026-07-01 19:33:29,675 +3,9834,2026-07-01 19:33:30,676 +3,9849,2026-07-01 19:33:30,677 +3,9864,2026-07-01 19:33:31,678 +3,9879,2026-07-01 19:33:31,679 +3,9893,2026-07-01 19:33:32,680 +3,9908,2026-07-01 19:33:33,681 +3,9924,2026-07-01 19:33:33,683 +3,9938,2026-07-01 19:33:34,684 +3,9952,2026-07-01 19:33:34,685 +3,9968,2026-07-01 19:33:35,686 +3,9983,2026-07-01 19:33:35,687 +3,9998,2026-07-01 19:33:36,691 +3,10014,2026-07-01 19:33:37,690 +3,10028,2026-07-01 19:33:37,688 +3,10043,2026-07-01 19:33:38,693 +3,10058,2026-07-01 19:33:38,694 +3,10072,2026-07-01 19:33:39,695 +3,10087,2026-07-01 19:33:40,696 +3,10102,2026-07-01 19:33:40,697 +3,10117,2026-07-01 19:33:41,698 +3,10132,2026-07-01 19:33:41,699 +3,10147,2026-07-01 19:33:42,700 +3,10163,2026-07-01 19:33:43,701 +3,10177,2026-07-01 19:33:43,703 +3,10191,2026-07-01 19:33:44,704 +3,10206,2026-07-01 19:33:44,705 +3,10222,2026-07-01 19:33:45,706 +3,10236,2026-07-01 19:33:46,707 +3,10251,2026-07-01 19:33:46,708 +3,10266,2026-07-01 19:33:47,710 +3,10281,2026-07-01 19:33:47,709 +3,10296,2026-07-01 19:33:48,711 +3,10311,2026-07-01 19:33:49,712 +3,10326,2026-07-01 19:33:49,713 +3,10341,2026-07-01 19:33:50,714 +3,10356,2026-07-01 19:33:50,715 +3,10370,2026-07-01 19:33:51,716 +3,10385,2026-07-01 19:33:52,717 +3,10400,2026-07-01 19:33:52,718 +3,10415,2026-07-01 19:33:53,719 +3,10430,2026-07-01 19:33:53,720 +3,10446,2026-07-01 19:33:54,721 +3,10460,2026-07-01 19:33:55,722 +3,10475,2026-07-01 19:33:55,723 +3,10490,2026-07-01 19:33:56,724 +3,10505,2026-07-01 19:33:56,725 +3,10520,2026-07-01 19:33:57,726 +3,10535,2026-07-01 19:33:58,727 +3,10550,2026-07-01 19:33:58,728 +3,10564,2026-07-01 19:33:59,729 +3,10580,2026-07-01 19:33:59,730 +3,10594,2026-07-01 19:34:00,731 +3,10609,2026-07-01 19:34:00,732 +3,10624,2026-07-01 19:34:01,733 +3,10639,2026-07-01 19:34:02,734 +3,10654,2026-07-01 19:34:02,735 +3,10670,2026-07-01 19:34:03,736 +3,10684,2026-07-01 19:34:03,737 +3,10699,2026-07-01 19:34:04,738 +3,10714,2026-07-01 19:34:05,739 +3,10729,2026-07-01 19:34:05,740 +3,10744,2026-07-01 19:34:06,741 +3,10759,2026-07-01 19:34:07,742 +3,10774,2026-07-01 19:34:07,743 +3,10789,2026-07-01 19:34:08,744 +3,10803,2026-07-01 19:34:08,745 +3,10822,2026-07-01 19:34:09,746 +3,10834,2026-07-01 19:34:09,758 +3,10849,2026-07-01 19:34:10,760 +3,10863,2026-07-01 19:34:11,753 +3,10878,2026-07-01 19:34:11,762 +3,10893,2026-07-01 19:34:12,763 +3,10908,2026-07-01 19:34:12,764 +3,10923,2026-07-01 19:34:13,765 +3,10939,2026-07-01 19:34:14,766 +3,10953,2026-07-01 19:34:14,767 +3,10968,2026-07-01 19:34:15,768 +3,10983,2026-07-01 19:34:16,769 +3,10999,2026-07-01 19:34:16,770 +3,11014,2026-07-01 19:34:17,771 +3,11029,2026-07-01 19:34:17,772 +3,11043,2026-07-01 19:34:18,773 +3,11058,2026-07-01 19:34:18,774 +3,11074,2026-07-01 19:34:19,775 +3,11089,2026-07-01 19:34:20,776 +3,11104,2026-07-01 19:34:20,777 +3,11118,2026-07-01 19:34:21,778 +3,11134,2026-07-01 19:34:22,779 +3,11149,2026-07-01 19:34:22,780 +3,11163,2026-07-01 19:34:23,781 +3,11178,2026-07-01 19:34:23,782 +3,11193,2026-07-01 19:34:24,783 +3,11208,2026-07-01 19:34:24,784 +3,11223,2026-07-01 19:34:25,785 +3,11238,2026-07-01 19:34:26,786 +3,11253,2026-07-01 19:34:27,787 +3,11268,2026-07-01 19:34:27,788 +3,11283,2026-07-01 19:34:27,789 +3,11298,2026-07-01 19:34:28,790 +3,11315,2026-07-01 19:34:29,791 +3,11327,2026-07-01 19:34:29,792 +3,11343,2026-07-01 19:34:30,793 +3,11357,2026-07-01 19:34:30,794 +3,11372,2026-07-01 19:34:31,795 +3,11387,2026-07-01 19:34:32,796 +3,11402,2026-07-01 19:34:32,797 +3,11417,2026-07-01 19:34:33,798 +3,11432,2026-07-01 19:34:33,799 +3,11449,2026-07-01 19:34:34,800 +3,11462,2026-07-01 19:34:35,801 +3,11477,2026-07-01 19:34:35,802 +3,11492,2026-07-01 19:34:36,803 +3,11507,2026-07-01 19:34:37,804 +3,11522,2026-07-01 19:34:37,805 +3,11536,2026-07-01 19:34:38,806 +3,11551,2026-07-01 19:34:38,807 +3,11567,2026-07-01 19:34:39,808 +3,11582,2026-07-01 19:34:39,809 +3,11596,2026-07-01 19:34:40,810 +3,11613,2026-07-01 19:34:41,811 +3,11626,2026-07-01 19:34:41,813 +3,11641,2026-07-01 19:34:42,812 +3,11657,2026-07-01 19:34:42,814 +3,11671,2026-07-01 19:34:43,815 +3,11686,2026-07-01 19:34:44,816 +3,11701,2026-07-01 19:34:44,817 +3,11717,2026-07-01 19:34:45,819 +3,11733,2026-07-01 19:34:46,820 +3,11748,2026-07-01 19:34:46,818 +3,11764,2026-07-01 19:34:47,821 +3,11779,2026-07-01 19:34:47,822 +3,11795,2026-07-01 19:34:48,823 +3,11811,2026-07-01 19:34:49,824 +3,11826,2026-07-01 19:34:49,825 +3,11842,2026-07-01 19:34:50,826 +3,11857,2026-07-01 19:34:50,827 +3,11873,2026-07-01 19:34:51,828 +3,11889,2026-07-01 19:34:52,829 +3,11904,2026-07-01 19:34:52,830 +3,11920,2026-07-01 19:34:53,831 +3,11935,2026-07-01 19:34:54,832 +3,11951,2026-07-01 19:34:54,833 +3,11967,2026-07-01 19:34:55,834 +3,11983,2026-07-01 19:34:55,835 +3,11998,2026-07-01 19:34:56,836 +3,12013,2026-07-01 19:34:57,837 +3,12029,2026-07-01 19:34:57,838 +3,12044,2026-07-01 19:34:58,839 +3,12061,2026-07-01 19:34:59,840 +3,12076,2026-07-01 19:34:59,841 +3,12092,2026-07-01 19:35:00,842 +3,12107,2026-07-01 19:35:00,843 +3,12123,2026-07-01 19:35:01,844 +3,12139,2026-07-01 19:35:02,845 +3,12155,2026-07-01 19:35:02,846 +3,12170,2026-07-01 19:35:03,847 +3,12186,2026-07-01 19:35:04,848 +3,12202,2026-07-01 19:35:04,849 +3,12217,2026-07-01 19:35:05,850 +3,12233,2026-07-01 19:35:05,851 +3,12249,2026-07-01 19:35:06,852 +3,12264,2026-07-01 19:35:07,853 +3,12280,2026-07-01 19:35:07,855 +3,12296,2026-07-01 19:35:08,856 +3,12311,2026-07-01 19:35:09,857 +3,12326,2026-07-01 19:35:09,858 +3,12342,2026-07-01 19:35:10,859 +3,12358,2026-07-01 19:35:10,860 +3,12373,2026-07-01 19:35:11,861 +3,12389,2026-07-01 19:35:12,862 +3,12405,2026-07-01 19:35:12,863 +3,12421,2026-07-01 19:35:13,864 +3,12436,2026-07-01 19:35:14,865 +3,12451,2026-07-01 19:35:14,866 +3,12467,2026-07-01 19:35:15,867 +3,12483,2026-07-01 19:35:15,868 +3,12499,2026-07-01 19:35:16,869 +3,12514,2026-07-01 19:35:17,870 +3,12529,2026-07-01 19:35:17,871 +3,12544,2026-07-01 19:35:18,872 +3,12558,2026-07-01 19:35:18,873 +3,12574,2026-07-01 19:35:19,874 +3,12590,2026-07-01 19:35:20,875 +3,12604,2026-07-01 19:35:20,876 +3,12619,2026-07-01 19:35:21,877 +3,12633,2026-07-01 19:35:22,878 +3,12648,2026-07-01 19:35:22,879 +3,12663,2026-07-01 19:35:23,880 +3,12678,2026-07-01 19:35:23,881 +3,12693,2026-07-01 19:35:24,882 +3,12708,2026-07-01 19:35:24,883 +3,12723,2026-07-01 19:35:25,884 +3,12738,2026-07-01 19:35:26,885 +3,12753,2026-07-01 19:35:27,886 +3,12768,2026-07-01 19:35:27,887 +3,12783,2026-07-01 19:35:27,888 +3,12797,2026-07-01 19:35:28,889 +3,12812,2026-07-01 19:35:29,890 +3,12828,2026-07-01 19:35:29,891 +3,12843,2026-07-01 19:35:30,892 +3,12858,2026-07-01 19:35:30,893 +3,12873,2026-07-01 19:35:31,894 +3,12887,2026-07-01 19:35:32,895 +3,12903,2026-07-01 19:35:32,896 +3,12917,2026-07-01 19:35:33,897 +3,12932,2026-07-01 19:35:33,898 +3,12947,2026-07-01 19:35:34,899 +3,12962,2026-07-01 19:35:35,900 +3,12977,2026-07-01 19:35:35,901 +3,12992,2026-07-01 19:35:36,902 +3,13007,2026-07-01 19:35:37,903 +3,13022,2026-07-01 19:35:37,904 +3,13037,2026-07-01 19:35:38,905 +3,13052,2026-07-01 19:35:38,906 +3,13067,2026-07-01 19:35:39,907 +3,13081,2026-07-01 19:35:39,908 +3,13097,2026-07-01 19:35:40,909 +3,13112,2026-07-01 19:35:41,910 +3,13127,2026-07-01 19:35:41,911 +3,13142,2026-07-01 19:35:42,912 +3,13157,2026-07-01 19:35:42,913 +3,13172,2026-07-01 19:35:43,914 +3,13187,2026-07-01 19:35:44,915 +3,13201,2026-07-01 19:35:44,916 +3,13217,2026-07-01 19:35:45,917 +3,13232,2026-07-01 19:35:45,918 +3,13246,2026-07-01 19:35:46,919 +3,13262,2026-07-01 19:35:47,920 +3,13277,2026-07-01 19:35:47,921 +3,13291,2026-07-01 19:35:48,922 +3,13307,2026-07-01 19:35:48,923 +3,13321,2026-07-01 19:35:49,924 +3,13336,2026-07-01 19:35:50,925 +3,13351,2026-07-01 19:35:50,926 +3,13365,2026-07-01 19:35:51,927 +3,13381,2026-07-01 19:35:52,928 +3,13396,2026-07-01 19:35:52,929 +3,13411,2026-07-01 19:35:53,930 +3,13426,2026-07-01 19:35:53,931 +3,13440,2026-07-01 19:35:54,932 +3,13456,2026-07-01 19:35:54,933 +3,13471,2026-07-01 19:35:55,934 +3,13486,2026-07-01 19:35:56,935 +3,13500,2026-07-01 19:35:56,936 +3,13516,2026-07-01 19:35:57,937 +3,13530,2026-07-01 19:35:57,938 +3,13546,2026-07-01 19:35:58,939 +3,13560,2026-07-01 19:35:59,940 +3,13576,2026-07-01 19:35:59,941 +3,13590,2026-07-01 19:36:00,942 +3,13605,2026-07-01 19:36:00,943 +3,13620,2026-07-01 19:36:01,944 +3,13635,2026-07-01 19:36:02,945 +3,13650,2026-07-01 19:36:02,946 +3,13665,2026-07-01 19:36:03,947 +3,13679,2026-07-01 19:36:03,948 +3,13695,2026-07-01 19:36:04,949 +3,13709,2026-07-01 19:36:04,950 +3,13725,2026-07-01 19:36:05,951 +3,13739,2026-07-01 19:36:06,952 +3,13754,2026-07-01 19:36:07,953 +3,13769,2026-07-01 19:36:07,954 +3,13785,2026-07-01 19:36:08,955 +3,13799,2026-07-01 19:36:08,956 +3,13814,2026-07-01 19:36:09,957 +3,13828,2026-07-01 19:36:09,958 +3,13843,2026-07-01 19:36:10,959 +3,13858,2026-07-01 19:36:10,960 +3,13873,2026-07-01 19:36:11,961 +3,13888,2026-07-01 19:36:12,962 +3,13902,2026-07-01 19:36:12,963 +3,13917,2026-07-01 19:36:13,964 +3,13932,2026-07-01 19:36:14,965 +3,13947,2026-07-01 19:36:14,966 +3,13961,2026-07-01 19:36:15,967 +3,13976,2026-07-01 19:36:15,968 +3,13990,2026-07-01 19:36:16,969 +3,14004,2026-07-01 19:36:16,970 +3,14020,2026-07-01 19:36:17,971 +3,14034,2026-07-01 19:36:17,972 +3,14047,2026-07-01 19:36:18,973 +3,14062,2026-07-01 19:36:19,974 +3,14076,2026-07-01 19:36:19,975 +3,14090,2026-07-01 19:36:20,976 +3,14105,2026-07-01 19:36:20,977 +3,14119,2026-07-01 19:36:21,978 +3,14134,2026-07-01 19:36:22,979 +3,14147,2026-07-01 19:36:22,980 +3,14161,2026-07-01 19:36:23,981 +3,14176,2026-07-01 19:36:23,982 +3,14190,2026-07-01 19:36:24,983 +3,14206,2026-07-01 19:36:24,984 +3,14219,2026-07-01 19:36:25,985 +3,14234,2026-07-01 19:36:26,986 +3,14247,2026-07-01 19:36:26,987 +3,14262,2026-07-01 19:36:27,989 +3,14276,2026-07-01 19:36:27,988 +3,14291,2026-07-01 19:36:28,990 +3,14305,2026-07-01 19:36:28,991 +3,14319,2026-07-01 19:36:29,992 +3,14334,2026-07-01 19:36:30,993 +3,14348,2026-07-01 19:36:30,994 +3,14362,2026-07-01 19:36:31,995 +3,14377,2026-07-01 19:36:31,996 +3,14391,2026-07-01 19:36:32,997 +3,14405,2026-07-01 19:36:32,998 +3,14420,2026-07-01 19:36:33,999 +3,14434,2026-07-01 19:36:33,1000 +3,14448,2026-07-01 19:36:34,1001 +3,14463,2026-07-01 19:36:35,1002 +3,14477,2026-07-01 19:36:35,1003 +3,14491,2026-07-01 19:36:36,1004 +3,14505,2026-07-01 19:36:37,1005 +3,14520,2026-07-01 19:36:37,1006 +3,14534,2026-07-01 19:36:37,1007 +3,14548,2026-07-01 19:36:38,1008 +3,14562,2026-07-01 19:36:39,1010 +3,14576,2026-07-01 19:36:39,1009 +3,14590,2026-07-01 19:36:40,1011 +3,14605,2026-07-01 19:36:40,1012 +3,14620,2026-07-01 19:36:41,1013 +3,14634,2026-07-01 19:36:42,1014 +3,14648,2026-07-01 19:36:42,1015 +3,14662,2026-07-01 19:36:43,1016 +3,14677,2026-07-01 19:36:43,1017 +3,14691,2026-07-01 19:36:44,1018 +3,14705,2026-07-01 19:36:44,1019 +3,14719,2026-07-01 19:36:45,1020 +3,14734,2026-07-01 19:36:45,1021 +3,14749,2026-07-01 19:36:46,1022 +3,14763,2026-07-01 19:36:47,1023 +3,14778,2026-07-01 19:36:47,1024 +3,14793,2026-07-01 19:36:48,1025 +3,14808,2026-07-01 19:36:48,1026 +3,14824,2026-07-01 19:36:49,1027 +3,14838,2026-07-01 19:36:50,1028 +3,14853,2026-07-01 19:36:50,1029 +3,14867,2026-07-01 19:36:51,1030 +3,14882,2026-07-01 19:36:51,1031 +4,5,2026-07-01 19:36:58,3 +4,20,2026-07-01 19:36:59,8 +4,34,2026-07-01 19:36:59,6 +4,51,2026-07-01 19:37:00,5 +4,65,2026-07-01 19:37:00,9 +4,80,2026-07-01 19:37:01,10 +4,95,2026-07-01 19:37:02,11 +4,110,2026-07-01 19:37:02,12 +4,125,2026-07-01 19:37:03,13 +4,140,2026-07-01 19:37:03,14 +4,155,2026-07-01 19:37:04,15 +4,170,2026-07-01 19:37:05,16 +4,184,2026-07-01 19:37:05,17 +4,200,2026-07-01 19:37:06,18 +4,214,2026-07-01 19:37:06,19 +4,229,2026-07-01 19:37:07,20 +4,245,2026-07-01 19:37:08,21 +4,259,2026-07-01 19:37:08,22 +4,274,2026-07-01 19:37:09,23 +4,289,2026-07-01 19:37:09,24 +4,304,2026-07-01 19:37:10,29 +4,319,2026-07-01 19:37:11,32 +4,334,2026-07-01 19:37:11,30 +4,349,2026-07-01 19:37:12,35 +4,364,2026-07-01 19:37:12,39 +4,378,2026-07-01 19:37:13,49 +4,394,2026-07-01 19:37:13,43 +4,408,2026-07-01 19:37:14,47 +4,424,2026-07-01 19:37:15,53 +4,438,2026-07-01 19:37:15,42 +4,453,2026-07-01 19:37:16,58 +4,468,2026-07-01 19:37:17,57 +4,483,2026-07-01 19:37:17,60 +4,498,2026-07-01 19:37:18,61 +4,514,2026-07-01 19:37:18,62 +4,528,2026-07-01 19:37:19,63 +4,543,2026-07-01 19:37:19,64 +4,558,2026-07-01 19:37:20,65 +4,574,2026-07-01 19:37:21,66 +4,588,2026-07-01 19:37:21,67 +4,603,2026-07-01 19:37:22,68 +4,618,2026-07-01 19:37:23,69 +4,633,2026-07-01 19:37:23,70 +4,648,2026-07-01 19:37:24,71 +4,663,2026-07-01 19:37:24,72 +4,678,2026-07-01 19:37:25,73 +4,693,2026-07-01 19:37:25,74 +4,707,2026-07-01 19:37:26,75 +4,723,2026-07-01 19:37:27,76 +4,738,2026-07-01 19:37:27,77 +4,753,2026-07-01 19:37:28,78 +4,767,2026-07-01 19:37:28,79 +4,783,2026-07-01 19:37:29,80 +4,798,2026-07-01 19:37:30,81 +4,813,2026-07-01 19:37:30,82 +4,828,2026-07-01 19:37:31,83 +4,843,2026-07-01 19:37:31,84 +4,858,2026-07-01 19:37:32,85 +4,872,2026-07-01 19:37:33,86 +4,887,2026-07-01 19:37:33,87 +4,902,2026-07-01 19:37:34,88 +4,917,2026-07-01 19:37:35,89 +4,931,2026-07-01 19:37:35,90 +4,947,2026-07-01 19:37:36,91 +4,962,2026-07-01 19:37:36,92 +4,977,2026-07-01 19:37:37,93 +4,992,2026-07-01 19:37:37,94 +4,1007,2026-07-01 19:37:38,95 +4,1022,2026-07-01 19:37:39,96 +4,1037,2026-07-01 19:37:39,97 +4,1051,2026-07-01 19:37:40,98 +4,1067,2026-07-01 19:37:41,99 +4,1082,2026-07-01 19:37:41,100 +4,1097,2026-07-01 19:37:42,102 +4,1111,2026-07-01 19:37:42,101 +4,1126,2026-07-01 19:37:43,103 +4,1142,2026-07-01 19:37:44,104 +4,11,2026-07-01 19:37:48,4 +4,26,2026-07-01 19:37:49,5 +4,41,2026-07-01 19:37:49,2 +4,55,2026-07-01 19:37:50,8 +4,72,2026-07-01 19:37:51,9 +4,85,2026-07-01 19:37:51,10 +4,99,2026-07-01 19:37:52,11 +4,115,2026-07-01 19:37:52,12 +4,130,2026-07-01 19:37:53,13 +4,145,2026-07-01 19:37:54,14 +4,159,2026-07-01 19:37:54,15 +4,175,2026-07-01 19:37:55,16 +4,189,2026-07-01 19:37:55,17 +4,203,2026-07-01 19:37:56,18 +4,220,2026-07-01 19:37:57,19 +4,233,2026-07-01 19:37:58,20 +4,248,2026-07-01 19:37:58,21 +4,263,2026-07-01 19:37:58,22 +4,278,2026-07-01 19:37:59,23 +4,294,2026-07-01 19:38:00,24 +4,308,2026-07-01 19:38:00,25 +4,324,2026-07-01 19:38:01,26 +4,338,2026-07-01 19:38:01,27 +4,352,2026-07-01 19:38:02,29 +4,368,2026-07-01 19:38:03,28 +4,382,2026-07-01 19:38:03,30 +4,397,2026-07-01 19:38:04,31 +4,412,2026-07-01 19:38:04,32 +4,426,2026-07-01 19:38:05,38 +4,441,2026-07-01 19:38:05,39 +4,456,2026-07-01 19:38:06,41 +4,471,2026-07-01 19:38:07,40 +4,486,2026-07-01 19:38:07,45 +4,502,2026-07-01 19:38:08,46 +4,516,2026-07-01 19:38:08,47 +4,530,2026-07-01 19:38:09,48 +4,4,2026-07-01 19:38:18,7 +4,19,2026-07-01 19:38:18,2 +4,34,2026-07-01 19:38:19,6 +4,49,2026-07-01 19:38:20,5 +4,64,2026-07-01 19:38:20,9 +4,78,2026-07-01 19:38:21,10 +4,94,2026-07-01 19:38:22,11 +4,109,2026-07-01 19:38:22,12 +4,124,2026-07-01 19:38:23,13 +4,138,2026-07-01 19:38:23,14 +4,153,2026-07-01 19:38:24,15 +4,168,2026-07-01 19:38:24,16 +4,182,2026-07-01 19:38:25,17 +4,197,2026-07-01 19:38:26,18 +4,213,2026-07-01 19:38:26,19 +4,227,2026-07-01 19:38:27,20 +4,242,2026-07-01 19:38:27,21 +4,257,2026-07-01 19:38:28,22 +4,272,2026-07-01 19:38:29,23 +4,287,2026-07-01 19:38:29,24 +4,302,2026-07-01 19:38:30,25 +4,317,2026-07-01 19:38:30,26 +4,332,2026-07-01 19:38:31,27 +4,347,2026-07-01 19:38:32,28 +4,361,2026-07-01 19:38:32,29 +4,376,2026-07-01 19:38:33,30 +4,391,2026-07-01 19:38:34,31 +4,405,2026-07-01 19:38:34,32 +4,420,2026-07-01 19:38:35,33 +4,435,2026-07-01 19:38:35,34 +4,451,2026-07-01 19:38:36,35 +4,465,2026-07-01 19:38:36,36 +4,480,2026-07-01 19:38:37,37 +4,496,2026-07-01 19:38:38,38 +4,511,2026-07-01 19:38:38,39 +4,526,2026-07-01 19:38:39,40 +4,539,2026-07-01 19:38:39,41 +4,554,2026-07-01 19:38:40,42 +4,570,2026-07-01 19:38:41,43 +4,585,2026-07-01 19:38:41,44 +4,599,2026-07-01 19:38:42,45 +4,614,2026-07-01 19:38:42,46 +4,629,2026-07-01 19:38:43,47 +4,644,2026-07-01 19:38:44,48 +4,659,2026-07-01 19:38:44,49 +4,673,2026-07-01 19:38:45,50 +4,689,2026-07-01 19:38:45,51 +4,704,2026-07-01 19:38:46,52 +4,718,2026-07-01 19:38:46,53 +4,733,2026-07-01 19:38:47,54 +4,748,2026-07-01 19:38:48,55 +4,762,2026-07-01 19:38:48,56 +4,778,2026-07-01 19:38:49,57 +4,792,2026-07-01 19:38:49,58 +4,807,2026-07-01 19:38:50,59 +4,823,2026-07-01 19:38:51,60 +4,837,2026-07-01 19:38:51,61 +4,852,2026-07-01 19:38:52,62 +4,867,2026-07-01 19:38:52,63 +4,882,2026-07-01 19:38:53,64 +4,896,2026-07-01 19:38:54,65 +4,911,2026-07-01 19:38:54,66 +4,926,2026-07-01 19:38:55,67 +4,941,2026-07-01 19:38:55,68 +4,956,2026-07-01 19:38:56,69 +4,971,2026-07-01 19:38:57,70 +4,985,2026-07-01 19:38:57,71 +4,1000,2026-07-01 19:38:58,72 +4,1015,2026-07-01 19:38:58,73 +4,1030,2026-07-01 19:38:59,74 +4,1045,2026-07-01 19:39:00,75 +4,1060,2026-07-01 19:39:00,76 +4,1075,2026-07-01 19:39:01,77 +4,1090,2026-07-01 19:39:01,78 +4,1104,2026-07-01 19:39:02,79 +4,1120,2026-07-01 19:39:03,80 +4,1135,2026-07-01 19:39:03,81 +4,1149,2026-07-01 19:39:04,82 +4,1164,2026-07-01 19:39:04,83 +4,1179,2026-07-01 19:39:05,84 +4,7,2026-07-01 19:39:18,1 +4,37,2026-07-01 19:39:19,13 +4,67,2026-07-01 19:39:20,49 +4,82,2026-07-01 19:39:21,47 +4,97,2026-07-01 19:39:22,51 +4,111,2026-07-01 19:39:22,45 +4,128,2026-07-01 19:39:23,40 +4,142,2026-07-01 19:39:24,35 +4,156,2026-07-01 19:39:24,53 +4,172,2026-07-01 19:39:25,54 +4,186,2026-07-01 19:39:25,55 +4,202,2026-07-01 19:39:26,56 +4,216,2026-07-01 19:39:26,57 +4,231,2026-07-01 19:39:27,59 +4,246,2026-07-01 19:39:28,60 +4,261,2026-07-01 19:39:28,61 +4,276,2026-07-01 19:39:29,62 +4,291,2026-07-01 19:39:29,63 +4,306,2026-07-01 19:39:30,64 +4,320,2026-07-01 19:39:31,65 +4,335,2026-07-01 19:39:31,66 +4,350,2026-07-01 19:39:32,67 +4,365,2026-07-01 19:39:32,68 +4,380,2026-07-01 19:39:33,69 +4,395,2026-07-01 19:39:34,70 +4,410,2026-07-01 19:39:34,71 +4,426,2026-07-01 19:39:35,72 +4,440,2026-07-01 19:39:35,73 +4,455,2026-07-01 19:39:36,74 +4,469,2026-07-01 19:39:37,75 +4,3,2026-07-01 19:39:48,5 +4,18,2026-07-01 19:39:49,4 +4,33,2026-07-01 19:39:49,2 +4,48,2026-07-01 19:39:50,3 +4,62,2026-07-01 19:39:50,9 +4,77,2026-07-01 19:39:51,10 +4,92,2026-07-01 19:39:51,11 +4,107,2026-07-01 19:39:52,12 +4,122,2026-07-01 19:39:53,13 +4,138,2026-07-01 19:39:53,14 +4,152,2026-07-01 19:39:54,15 +4,167,2026-07-01 19:39:54,16 +4,182,2026-07-01 19:39:55,17 +4,197,2026-07-01 19:39:56,23 +4,212,2026-07-01 19:39:56,24 +4,227,2026-07-01 19:39:57,22 +4,241,2026-07-01 19:39:57,28 +4,256,2026-07-01 19:39:58,29 +4,271,2026-07-01 19:39:59,30 +4,286,2026-07-01 19:39:59,31 +4,302,2026-07-01 19:40:00,32 +4,316,2026-07-01 19:40:00,33 +4,331,2026-07-01 19:40:01,34 +4,347,2026-07-01 19:40:02,35 +4,361,2026-07-01 19:40:02,36 +4,376,2026-07-01 19:40:03,37 +4,390,2026-07-01 19:40:03,38 +4,406,2026-07-01 19:40:04,39 +4,420,2026-07-01 19:40:05,40 +4,436,2026-07-01 19:40:05,41 +4,451,2026-07-01 19:40:06,42 +4,465,2026-07-01 19:40:06,43 +4,480,2026-07-01 19:40:07,44 +4,496,2026-07-01 19:40:08,45 +4,510,2026-07-01 19:40:08,46 +4,525,2026-07-01 19:40:09,47 +4,540,2026-07-01 19:40:09,48 +4,554,2026-07-01 19:40:10,49 +4,570,2026-07-01 19:40:11,50 +4,585,2026-07-01 19:40:11,51 +4,600,2026-07-01 19:40:12,52 +4,615,2026-07-01 19:40:12,53 +4,629,2026-07-01 19:40:13,54 +4,645,2026-07-01 19:40:14,55 +4,659,2026-07-01 19:40:14,56 +4,674,2026-07-01 19:40:15,57 +4,689,2026-07-01 19:40:15,58 +4,704,2026-07-01 19:40:16,59 +4,719,2026-07-01 19:40:17,60 +4,734,2026-07-01 19:40:17,61 +4,748,2026-07-01 19:40:18,62 +4,763,2026-07-01 19:40:18,63 +4,778,2026-07-01 19:40:19,64 +4,793,2026-07-01 19:40:20,65 +4,808,2026-07-01 19:40:20,66 +4,823,2026-07-01 19:40:21,67 +4,838,2026-07-01 19:40:21,68 +4,853,2026-07-01 19:40:22,69 +4,868,2026-07-01 19:40:23,70 +4,883,2026-07-01 19:40:23,71 +4,898,2026-07-01 19:40:24,72 +4,913,2026-07-01 19:40:24,73 +4,928,2026-07-01 19:40:25,74 +4,943,2026-07-01 19:40:25,75 +4,958,2026-07-01 19:40:26,76 +4,972,2026-07-01 19:40:27,77 +4,987,2026-07-01 19:40:28,78 +4,1002,2026-07-01 19:40:28,79 +4,1017,2026-07-01 19:40:28,80 +4,1032,2026-07-01 19:40:29,81 +4,1047,2026-07-01 19:40:30,82 +4,1062,2026-07-01 19:40:30,83 +4,1077,2026-07-01 19:40:31,84 +4,1092,2026-07-01 19:40:31,85 +4,1106,2026-07-01 19:40:32,86 +4,1121,2026-07-01 19:40:33,87 +4,1136,2026-07-01 19:40:33,88 +4,1151,2026-07-01 19:40:34,89 +4,1167,2026-07-01 19:40:34,90 +4,1181,2026-07-01 19:40:35,91 +4,1195,2026-07-01 19:40:36,92 +4,1211,2026-07-01 19:40:36,93 +4,1226,2026-07-01 19:40:37,94 +4,1241,2026-07-01 19:40:38,95 +4,1256,2026-07-01 19:40:38,96 +4,1270,2026-07-01 19:40:39,97 +4,1285,2026-07-01 19:40:40,98 +4,1300,2026-07-01 19:40:40,99 +4,1315,2026-07-01 19:40:40,100 +4,1331,2026-07-01 19:40:41,101 +4,1345,2026-07-01 19:40:42,102 +4,1360,2026-07-01 19:40:42,103 +4,1375,2026-07-01 19:40:43,104 +4,1390,2026-07-01 19:40:44,105 +4,1405,2026-07-01 19:40:44,106 +4,1419,2026-07-01 19:40:45,107 +4,1434,2026-07-01 19:40:45,108 +4,1450,2026-07-01 19:40:46,109 +4,1464,2026-07-01 19:40:46,110 +4,1479,2026-07-01 19:40:47,111 +4,1495,2026-07-01 19:40:48,112 +4,1509,2026-07-01 19:40:48,113 +4,1524,2026-07-01 19:40:49,114 +4,1539,2026-07-01 19:40:49,115 +4,1554,2026-07-01 19:40:50,116 +4,1568,2026-07-01 19:40:50,117 +4,1584,2026-07-01 19:40:51,118 +4,1599,2026-07-01 19:40:52,119 +4,1613,2026-07-01 19:40:52,120 +4,1629,2026-07-01 19:40:53,121 +4,1644,2026-07-01 19:40:54,122 +4,1658,2026-07-01 19:40:54,123 +4,1673,2026-07-01 19:40:55,124 +4,1687,2026-07-01 19:40:55,125 +4,1703,2026-07-01 19:40:56,126 +4,1718,2026-07-01 19:40:56,127 +4,1733,2026-07-01 19:40:57,128 +4,1748,2026-07-01 19:40:58,129 +4,1763,2026-07-01 19:40:58,130 +4,1777,2026-07-01 19:40:59,131 +4,1792,2026-07-01 19:40:59,132 +4,1808,2026-07-01 19:41:00,133 +4,1822,2026-07-01 19:41:01,134 +4,1837,2026-07-01 19:41:01,135 +4,1852,2026-07-01 19:41:02,136 +4,1868,2026-07-01 19:41:03,137 +4,1882,2026-07-01 19:41:03,138 +4,1897,2026-07-01 19:41:04,139 +4,1912,2026-07-01 19:41:04,140 +4,1927,2026-07-01 19:41:05,141 +4,1942,2026-07-01 19:41:06,142 +4,1956,2026-07-01 19:41:06,143 +4,1972,2026-07-01 19:41:07,144 +4,1986,2026-07-01 19:41:07,145 +4,2001,2026-07-01 19:41:08,146 +4,2016,2026-07-01 19:41:09,147 +4,2031,2026-07-01 19:41:09,148 +4,2046,2026-07-01 19:41:10,149 +4,2061,2026-07-01 19:41:10,150 +4,2076,2026-07-01 19:41:11,151 +4,2091,2026-07-01 19:41:11,152 +4,2106,2026-07-01 19:41:12,153 +4,2121,2026-07-01 19:41:13,154 +4,2136,2026-07-01 19:41:13,155 +4,2150,2026-07-01 19:41:14,156 +4,2165,2026-07-01 19:41:14,157 +4,2180,2026-07-01 19:41:15,158 +4,2195,2026-07-01 19:41:16,159 +4,2210,2026-07-01 19:41:16,160 +4,2225,2026-07-01 19:41:17,161 +4,2240,2026-07-01 19:41:17,162 +4,2255,2026-07-01 19:41:18,163 +4,2270,2026-07-01 19:41:19,164 +4,2285,2026-07-01 19:41:19,165 +4,2299,2026-07-01 19:41:20,166 +4,2315,2026-07-01 19:41:20,167 +4,2330,2026-07-01 19:41:21,168 +4,2345,2026-07-01 19:41:22,169 +4,2359,2026-07-01 19:41:22,170 +4,2374,2026-07-01 19:41:23,171 +4,2389,2026-07-01 19:41:23,172 +4,2405,2026-07-01 19:41:24,173 +4,2419,2026-07-01 19:41:25,174 +4,2434,2026-07-01 19:41:25,175 +4,2449,2026-07-01 19:41:26,176 +4,2463,2026-07-01 19:41:26,177 +4,2478,2026-07-01 19:41:27,178 +4,2493,2026-07-01 19:41:28,179 +4,2509,2026-07-01 19:41:28,180 +4,2523,2026-07-01 19:41:29,181 +4,2538,2026-07-01 19:41:29,182 +4,2552,2026-07-01 19:41:30,183 +4,2568,2026-07-01 19:41:30,184 +4,2583,2026-07-01 19:41:31,185 +4,2597,2026-07-01 19:41:32,186 +4,2613,2026-07-01 19:41:32,187 +4,2628,2026-07-01 19:41:33,188 +4,2642,2026-07-01 19:41:33,189 +4,2657,2026-07-01 19:41:34,190 +4,2672,2026-07-01 19:41:35,191 +4,2687,2026-07-01 19:41:35,192 +4,2702,2026-07-01 19:41:36,193 +4,2717,2026-07-01 19:41:37,194 +4,2732,2026-07-01 19:41:37,196 +4,2746,2026-07-01 19:41:38,195 +4,2762,2026-07-01 19:41:38,197 +4,2776,2026-07-01 19:41:39,198 +4,2792,2026-07-01 19:41:39,199 +4,2806,2026-07-01 19:41:40,200 +4,2821,2026-07-01 19:41:41,201 +4,2836,2026-07-01 19:41:41,202 +4,2851,2026-07-01 19:41:42,203 +4,2866,2026-07-01 19:41:42,204 +4,2881,2026-07-01 19:41:43,205 +4,2896,2026-07-01 19:41:44,206 +4,2911,2026-07-01 19:41:44,207 +4,2926,2026-07-01 19:41:45,208 +4,2942,2026-07-01 19:41:45,209 +4,2960,2026-07-01 19:41:46,218 +4,2972,2026-07-01 19:41:47,212 +4,2984,2026-07-01 19:41:47,211 +4,3000,2026-07-01 19:41:48,215 +4,3015,2026-07-01 19:41:48,220 +4,3030,2026-07-01 19:41:49,222 +4,3044,2026-07-01 19:41:49,224 +4,3060,2026-07-01 19:41:50,225 +4,3074,2026-07-01 19:41:51,228 +4,3089,2026-07-01 19:41:51,229 +4,3104,2026-07-01 19:41:52,230 +4,3119,2026-07-01 19:41:53,231 +4,3134,2026-07-01 19:41:53,232 +4,3149,2026-07-01 19:41:54,233 +4,3164,2026-07-01 19:41:54,234 +4,3178,2026-07-01 19:41:55,235 +4,3194,2026-07-01 19:41:56,236 +4,3208,2026-07-01 19:41:56,237 +4,3224,2026-07-01 19:41:57,238 +4,3237,2026-07-01 19:41:57,239 +4,3253,2026-07-01 19:41:58,240 +4,3268,2026-07-01 19:41:58,241 +4,3283,2026-07-01 19:41:59,242 +4,3298,2026-07-01 19:42:00,243 +4,3312,2026-07-01 19:42:00,244 +4,3327,2026-07-01 19:42:01,245 +4,3342,2026-07-01 19:42:01,246 +4,3358,2026-07-01 19:42:02,247 +4,3373,2026-07-01 19:42:03,249 +4,3386,2026-07-01 19:42:03,250 +4,3401,2026-07-01 19:42:04,251 +4,3417,2026-07-01 19:42:04,252 +4,3431,2026-07-01 19:42:05,253 +4,3447,2026-07-01 19:42:06,254 +4,3462,2026-07-01 19:42:06,256 +4,3476,2026-07-01 19:42:07,257 +4,3491,2026-07-01 19:42:07,258 +4,3506,2026-07-01 19:42:08,259 +4,3520,2026-07-01 19:42:09,260 +4,3536,2026-07-01 19:42:09,261 +4,3551,2026-07-01 19:42:10,262 +4,3566,2026-07-01 19:42:10,263 +4,3580,2026-07-01 19:42:11,264 +4,3595,2026-07-01 19:42:12,265 +4,3611,2026-07-01 19:42:12,266 +4,3626,2026-07-01 19:42:13,267 +4,3640,2026-07-01 19:42:13,268 +4,3655,2026-07-01 19:42:14,269 +4,3670,2026-07-01 19:42:15,270 +4,3685,2026-07-01 19:42:15,271 +4,3700,2026-07-01 19:42:16,272 +4,3715,2026-07-01 19:42:16,273 +4,3729,2026-07-01 19:42:17,274 +4,3745,2026-07-01 19:42:18,275 +4,3759,2026-07-01 19:42:18,276 +4,3774,2026-07-01 19:42:19,277 +4,3789,2026-07-01 19:42:19,278 +4,3807,2026-07-01 19:42:20,279 +4,3819,2026-07-01 19:42:21,293 +4,3834,2026-07-01 19:42:21,287 +4,3849,2026-07-01 19:42:22,290 +4,3864,2026-07-01 19:42:22,295 +4,3878,2026-07-01 19:42:23,296 +4,3893,2026-07-01 19:42:24,297 +4,3908,2026-07-01 19:42:24,298 +4,3923,2026-07-01 19:42:25,299 +4,3938,2026-07-01 19:42:25,300 +4,3953,2026-07-01 19:42:26,301 +4,3968,2026-07-01 19:42:26,302 +4,3983,2026-07-01 19:42:27,303 +4,3997,2026-07-01 19:42:28,304 +4,4013,2026-07-01 19:42:28,305 +4,4028,2026-07-01 19:42:29,306 +4,4043,2026-07-01 19:42:29,307 +4,4057,2026-07-01 19:42:30,308 +4,4073,2026-07-01 19:42:31,309 +4,4088,2026-07-01 19:42:31,310 +4,4102,2026-07-01 19:42:32,311 +4,4117,2026-07-01 19:42:33,312 +4,4132,2026-07-01 19:42:33,313 +4,4147,2026-07-01 19:42:34,314 +4,4162,2026-07-01 19:42:34,315 +4,4176,2026-07-01 19:42:35,316 +4,4192,2026-07-01 19:42:36,317 +4,4207,2026-07-01 19:42:36,318 +4,4221,2026-07-01 19:42:37,319 +4,4236,2026-07-01 19:42:37,321 +4,4250,2026-07-01 19:42:38,320 +4,4266,2026-07-01 19:42:38,322 +4,4281,2026-07-01 19:42:39,323 +4,4296,2026-07-01 19:42:40,324 +4,4311,2026-07-01 19:42:40,330 +4,4326,2026-07-01 19:42:41,335 +4,4341,2026-07-01 19:42:41,337 +4,4355,2026-07-01 19:42:42,328 +4,4370,2026-07-01 19:42:43,340 +4,4386,2026-07-01 19:42:43,341 +4,4400,2026-07-01 19:42:44,342 +4,4414,2026-07-01 19:42:44,343 +4,4430,2026-07-01 19:42:45,344 +4,4445,2026-07-01 19:42:46,345 +4,4460,2026-07-01 19:42:46,346 +4,4474,2026-07-01 19:42:47,347 +4,4489,2026-07-01 19:42:47,348 +4,4505,2026-07-01 19:42:48,349 +4,4519,2026-07-01 19:42:49,350 +4,4534,2026-07-01 19:42:49,351 +4,4549,2026-07-01 19:42:50,352 +4,4564,2026-07-01 19:42:50,353 +4,4579,2026-07-01 19:42:51,354 +4,4594,2026-07-01 19:42:52,355 +4,4609,2026-07-01 19:42:52,356 +4,4624,2026-07-01 19:42:53,357 +4,4639,2026-07-01 19:42:53,358 +4,4653,2026-07-01 19:42:54,359 +4,4668,2026-07-01 19:42:55,360 +4,4683,2026-07-01 19:42:55,361 +4,4698,2026-07-01 19:42:56,362 +4,4714,2026-07-01 19:42:56,363 +4,4727,2026-07-01 19:42:57,372 +4,4743,2026-07-01 19:42:57,369 +4,4757,2026-07-01 19:42:58,373 +4,4773,2026-07-01 19:42:59,370 +4,4787,2026-07-01 19:42:59,374 +4,4802,2026-07-01 19:43:00,375 +4,4817,2026-07-01 19:43:00,376 +4,4833,2026-07-01 19:43:01,377 +4,4847,2026-07-01 19:43:02,378 +4,4862,2026-07-01 19:43:02,379 +4,4877,2026-07-01 19:43:03,380 +4,4892,2026-07-01 19:43:03,381 +4,4907,2026-07-01 19:43:04,382 +4,4922,2026-07-01 19:43:05,383 +4,4937,2026-07-01 19:43:05,384 +4,4952,2026-07-01 19:43:06,385 +4,4967,2026-07-01 19:43:06,386 +4,4982,2026-07-01 19:43:07,387 +4,4997,2026-07-01 19:43:08,388 +4,5012,2026-07-01 19:43:08,389 +4,5027,2026-07-01 19:43:09,390 +4,5042,2026-07-01 19:43:10,391 +4,5071,2026-07-01 19:43:11,396 +4,5087,2026-07-01 19:43:11,400 +4,5102,2026-07-01 19:43:12,395 +4,5116,2026-07-01 19:43:12,402 +4,5132,2026-07-01 19:43:13,403 +4,5146,2026-07-01 19:43:14,404 +4,5161,2026-07-01 19:43:14,405 +4,5177,2026-07-01 19:43:15,406 +4,5191,2026-07-01 19:43:15,407 +4,5207,2026-07-01 19:43:16,408 +4,5221,2026-07-01 19:43:17,409 +4,5236,2026-07-01 19:43:17,410 +4,5251,2026-07-01 19:43:18,411 +4,5267,2026-07-01 19:43:19,412 +4,5281,2026-07-01 19:43:19,413 +4,5296,2026-07-01 19:43:20,414 +4,5312,2026-07-01 19:43:20,415 +4,5326,2026-07-01 19:43:21,416 +4,5341,2026-07-01 19:43:21,417 +4,5357,2026-07-01 19:43:22,418 +4,5371,2026-07-01 19:43:23,419 +4,5386,2026-07-01 19:43:24,420 +4,5401,2026-07-01 19:43:24,421 +4,5416,2026-07-01 19:43:24,422 +4,5433,2026-07-01 19:43:25,423 +4,5445,2026-07-01 19:43:26,428 +4,5461,2026-07-01 19:43:26,432 +4,5476,2026-07-01 19:43:27,431 +4,5490,2026-07-01 19:43:27,433 +4,5506,2026-07-01 19:43:28,434 +4,5522,2026-07-01 19:43:29,435 +4,5535,2026-07-01 19:43:29,436 +4,5551,2026-07-01 19:43:30,437 +4,5566,2026-07-01 19:43:30,438 +4,5581,2026-07-01 19:43:31,447 +4,5596,2026-07-01 19:43:32,443 +4,5610,2026-07-01 19:43:32,450 +4,5625,2026-07-01 19:43:33,448 +4,5640,2026-07-01 19:43:33,442 +4,5655,2026-07-01 19:43:34,451 +4,5671,2026-07-01 19:43:35,452 +4,5701,2026-07-01 19:43:36,454 +4,5715,2026-07-01 19:43:36,462 +4,5730,2026-07-01 19:43:37,459 +4,5745,2026-07-01 19:43:38,464 +4,5760,2026-07-01 19:43:38,465 +4,5775,2026-07-01 19:43:39,468 +4,5789,2026-07-01 19:43:39,469 +4,5804,2026-07-01 19:43:40,470 +4,5821,2026-07-01 19:43:41,471 +4,5834,2026-07-01 19:43:41,472 +4,5849,2026-07-01 19:43:42,473 +4,5864,2026-07-01 19:43:42,474 +4,5879,2026-07-01 19:43:43,475 +4,5894,2026-07-01 19:43:43,476 +4,5908,2026-07-01 19:43:44,477 +4,5924,2026-07-01 19:43:45,479 +4,5939,2026-07-01 19:43:45,480 +4,5954,2026-07-01 19:43:46,481 +4,5969,2026-07-01 19:43:47,482 +4,5984,2026-07-01 19:43:47,484 +4,5998,2026-07-01 19:43:48,485 +4,6014,2026-07-01 19:43:48,486 +4,6029,2026-07-01 19:43:49,487 +4,6116,2026-07-01 19:43:52,488 +4,6132,2026-07-01 19:43:53,489 +4,6149,2026-07-01 19:43:54,490 +4,6280,2026-07-01 19:43:59,491 +4,6297,2026-07-01 19:44:00,492 +4,6313,2026-07-01 19:44:00,493 +4,6342,2026-07-01 19:44:02,494 +4,6488,2026-07-01 19:44:07,495 +4,6505,2026-07-01 19:44:08,496 +4,6521,2026-07-01 19:44:09,497 +4,6535,2026-07-01 19:44:09,498 +4,6549,2026-07-01 19:44:10,499 +4,6566,2026-07-01 19:44:10,500 +4,6700,2026-07-01 19:44:16,505 +4,6714,2026-07-01 19:44:16,506 +4,6729,2026-07-01 19:44:17,507 +4,6746,2026-07-01 19:44:18,509 diff --git a/build/CMakeCache.txt b/build/CMakeCache.txt index 61a48d1..bd4177d 100644 --- a/build/CMakeCache.txt +++ b/build/CMakeCache.txt @@ -213,6 +213,9 @@ bytetrack-counter_IS_TOP_LEVEL:STATIC=ON //Value Computed by CMake bytetrack-counter_SOURCE_DIR:STATIC=/opt/bytetrack-counter-cpp +//The directory containing a CMake configuration file for nlohmann_json. +nlohmann_json_DIR:PATH=/usr/share/cmake/nlohmann_json + ######################## # INTERNAL cache entries @@ -351,6 +354,8 @@ CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 FIND_PACKAGE_MESSAGE_DETAILS_OpenCV:INTERNAL=[/usr][cfound components: core imgproc videoio highgui imgcodecs ][v4.6.0()] //Details about finding SQLite3 FIND_PACKAGE_MESSAGE_DETAILS_SQLite3:INTERNAL=[/usr/include][/usr/lib/aarch64-linux-gnu/libsqlite3.so][v3.45.1()] +//Details about finding nlohmann_json +FIND_PACKAGE_MESSAGE_DETAILS_nlohmann_json:INTERNAL=[/usr/share/cmake/nlohmann_json/nlohmann_jsonConfig.cmake][v3.11.3()] //ADVANCED property for variable: SQLite3_INCLUDE_DIR SQLite3_INCLUDE_DIR-ADVANCED:INTERNAL=1 //ADVANCED property for variable: SQLite3_LIBRARY diff --git a/build/CMakeFiles/Makefile.cmake b/build/CMakeFiles/Makefile.cmake index 9f96cc8..0b9328a 100644 --- a/build/CMakeFiles/Makefile.cmake +++ b/build/CMakeFiles/Makefile.cmake @@ -32,6 +32,9 @@ set(CMAKE_MAKEFILE_DEPENDS "/usr/share/cmake-3.28/Modules/Platform/Linux-Initialize.cmake" "/usr/share/cmake-3.28/Modules/Platform/Linux.cmake" "/usr/share/cmake-3.28/Modules/Platform/UnixPaths.cmake" + "/usr/share/cmake/nlohmann_json/nlohmann_jsonConfig.cmake" + "/usr/share/cmake/nlohmann_json/nlohmann_jsonConfigVersion.cmake" + "/usr/share/cmake/nlohmann_json/nlohmann_jsonTargets.cmake" "/usr/share/eigen3/cmake/Eigen3Config.cmake" "/usr/share/eigen3/cmake/Eigen3ConfigVersion.cmake" "/usr/share/eigen3/cmake/Eigen3Targets.cmake" diff --git a/build/bytetrack-counter b/build/bytetrack-counter index 97a369e..224c3a0 100755 Binary files a/build/bytetrack-counter and b/build/bytetrack-counter differ diff --git a/build/cmake_install.cmake b/build/cmake_install.cmake index b1fea9d..edbbbc7 100644 --- a/build/cmake_install.cmake +++ b/build/cmake_install.cmake @@ -43,25 +43,25 @@ if(NOT DEFINED CMAKE_OBJDUMP) endif() if(CMAKE_INSTALL_COMPONENT STREQUAL "Unspecified" OR NOT CMAKE_INSTALL_COMPONENT) - if(EXISTS "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/bin/bytetrack-counter" AND - NOT IS_SYMLINK "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/bin/bytetrack-counter") + if(EXISTS "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/build/bytetrack-counter" AND + NOT IS_SYMLINK "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/build/bytetrack-counter") file(RPATH_CHECK - FILE "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/bin/bytetrack-counter" + FILE "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/build/bytetrack-counter" RPATH "") endif() list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES - "/opt/bytetrack-counter-cpp/bin/bytetrack-counter") + "/opt/bytetrack-counter-cpp/build/bytetrack-counter") if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION) message(WARNING "ABSOLUTE path INSTALL DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}") endif() if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION) message(FATAL_ERROR "ABSOLUTE path INSTALL DESTINATION forbidden (by caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}") endif() - file(INSTALL DESTINATION "/opt/bytetrack-counter-cpp/bin" TYPE EXECUTABLE FILES "/opt/bytetrack-counter-cpp/build/bytetrack-counter") - if(EXISTS "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/bin/bytetrack-counter" AND - NOT IS_SYMLINK "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/bin/bytetrack-counter") + file(INSTALL DESTINATION "/opt/bytetrack-counter-cpp/build" TYPE EXECUTABLE FILES "/opt/bytetrack-counter-cpp/build/bytetrack-counter") + if(EXISTS "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/build/bytetrack-counter" AND + NOT IS_SYMLINK "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/build/bytetrack-counter") if(CMAKE_INSTALL_DO_STRIP) - execute_process(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/bin/bytetrack-counter") + execute_process(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}/opt/bytetrack-counter-cpp/build/bytetrack-counter") endif() endif() endif() diff --git a/bytetrack_counter.db b/bytetrack_counter.db index faa5a93..df789d5 100644 Binary files a/bytetrack_counter.db and b/bytetrack_counter.db differ diff --git a/config.env.example b/config.env.example new file mode 100644 index 0000000..91e0b63 --- /dev/null +++ b/config.env.example @@ -0,0 +1,152 @@ +# ============================================================================= +# Edge RK3588 production counter + dashboard +# Shared config for: counter_live_rknn_bytetrack.py + counter_dashboard.py +# Copy to .env on device: cp config.env.example .env && nano .env +# ============================================================================= + +# --- Core paths --- +# Root output directory (logs, DB, video, CSV) +OUTPUT_DIR=/opt/bytetrack-counter +# SQLite database path for batch entries & crossing logs +DB_PATH=/opt/bytetrack-counter/bytetrack_counter.db +# JSON file persisting the current active batch state +STATE_FILE=/tmp/bytetrack_current_batch.json + +# --- Input source --- +# RTSP / HTTP live stream, or a local video file path +SOURCE=rtsp://user:pass@192.168.0.100:554/stream1 +# FFmpeg capture options passed to cv2.VideoCapture (RTSP low-latency flags) +OPENCV_FFMPEG_CAPTURE_OPTIONS=rtsp_transport;tcp|fflags;nobuffer|flags;low_delay + +# --- RKNN model --- +# Path to exported .rknn model (YOLO format, e.g. yolo11n.rknn) +MODEL_PATH=/opt/models/yolo9t.rknn +# Input image size for the model (square, e.g. 320 → 320×320) +IMGSZ=320 +# Use FP16 inference on NPU (true/false); currently unused in ByteTrack variant +HALF=false +# NPU core mask: 1=core0, 2=core1, 3=core0+core1, 7=all three +CORE_MASK=7 +# Compute device index (reserved; not used at runtime) +DEVICE=0 + +# --- YOLO decoder --- +# Number of object classes the model outputs (e.g. 2 = ayam + talenan) +NUM_CLASSES=2 +# Apply sigmoid to raw class scores (true/false); set true if model head uses BCE logits +SCORE_SIGMOID=false + +# --- Detection --- +# Confidence threshold – detections below this are discarded before NMS +CONF=0.3 + +# --- ByteTrack tracking --- +# General for ayam, index 0 +# Detections with score ≥ this get priority matching in the first association stage +TRACK_HIGH_THRESH_0=0.5 +# Detections with score between this and TRACK_HIGH_THRESH are matched in the second stage +TRACK_LOW_THRESH_0=0.1 +# IoU threshold for the first-stage association (0–1). Higher = stricter overlap required +TRACK_MATCH_THRESH_0=0.8 +# Frames a track survives without a match before being permanently removed +TRACK_BUFFER_0=30 +# Minimum consecutive (or total) hits needed before a track is considered confirmed +TRACK_MIN_HITS_0=3 + +# For talenan, index 1 +# Detections with score ≥ this get priority matching in the first association stage +TRACK_HIGH_THRESH_1=0.5 +# Detections with score between this and TRACK_HIGH_THRESH are matched in the second stage +TRACK_LOW_THRESH_1=0.1 +# IoU threshold for the first-stage association (0–1). Higher = stricter overlap required +TRACK_MATCH_THRESH_1=0.6 +# Frames a track survives without a match before being permanently removed +TRACK_BUFFER_1=30 +# Minimum consecutive (or total) hits needed before a track is considered confirmed +TRACK_MIN_HITS_1=3 + +# --- Display --- +# Site name shown on the dashboard header (top-right) +SITE_NAME=ZenAi + +# --- Object class names --- +# Camera / location identifier shown in HUD and stored in DB +CAMERA_NAME=ZenAi +# Label used for batch grouping in the database +OBJECT_LABEL=ayam-potong +# Class name for the counted object (must match NUM_CLASSES order, index 0) +CLASS_AYAM=ayam +# Class name for the batch-closing trigger object (must match NUM_CLASSES order, index 1) +CLASS_TALENAN=talenan + +# --- Line crossing --- +# Direction for counting: rtl (right-to-left, default) | ltr (left-to-right) | both +CROSS_DIRECTION=rtl +# Fixed x-coordinate for the counting line (overrides LINE_X_FRAC if set) +LINE_X= +# Fraction of frame width where the counting line is drawn (default 0.5 = centre) +LINE_X_FRAC=0.5 + +# --- Batch management --- +# Daily cutoff time (HH:MM) – a new day's batch numbering starts after this time. +# 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 +# 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 +IGNORE_BATCH_LABEL_TIMEOUT_SECONDS=30 +# Minimum number of objects required for a batch to be saved as valid +MIN_OBJECT_PER_BATCH=60 +# Minimum duration in seconds a batch must be open to be saved as valid +MIN_DURATION_PER_BATCH=60 + +# --- CSV export --- +# Write per-crossing events to a CSV file (true/false) +EXPORT_CSV=true +# Path where the crossing CSV is written +CROSS_CSV=/opt/batch-counter/batch_crossings.csv + +# --- Rate / performance --- +# Sliding window in seconds for computing the crossing rate (objects/minute) +RATE_WINDOW_SEC=60 +# Number of frames to discard at startup to let the stream buffer stabilise +WARMUP_FRAMES=30 +# Delay in seconds between stream reconnection attempts +RECONNECT_DELAY_SEC=3 +# Maximum reconnection attempts (0 = infinite) +MAX_RECONNECT_ATTEMPTS=0 +# Print status log every N processed frames +FLUSH_EVERY_N_FRAMES=100 +# Seconds after which a tracked but unseen object is pruned from the active set +TRACKED_PRUNE_SEC=300 + +# --- Video recording --- +# Save annotated frames to segmented MP4 files (true/false) +RECORD_VIDEO=false +# Duration in seconds of each video segment file +VIDEO_SEGMENT_SEC=3600 +# Output video FPS (fallback if source FPS is unknown or ≤ 1) +OUTPUT_FPS=15 + +# --- Live stream snapshot --- +# Periodically write the latest annotated frame as JPEG for an external web server +LIVE_STREAM_ENABLED=false +# Path to the shared-memory snapshot file (served by nginx / lighttpd) +LIVE_STREAM_FRAME_PATH=/dev/shm/byetrack-counter/live_frame.jpg +# JPEG quality (1–100) +LIVE_STREAM_QUALITY=75 +# Write the snapshot every N frames (lower = more frequent updates) +LIVE_STREAM_EVERY_N=2 + +# --- Dashboard (counter_dashboard.py) --- +# Flask secret key for session/cookie signing — change in production! +SECRET_KEY=change-me-in-production +# Bind address for the Flask web server +DASHBOARD_HOST=0.0.0.0 +# Listen port for the dashboard web UI +DASHBOARD_PORT=5000 +# Enable Flask debug mode (true/false) — auto-reloads on code changes; disable in production +FLASK_DEBUG=false +# Fallback name for the active-batch JSON state file used by the dashboard +CURRENT_BATCH_PATH=/tmp/bytetrack_current_batch.json diff --git a/counter_live_rknn_bytetrack.py b/counter_live_rknn_bytetrack.py index 1ad5e62..b012255 100644 --- a/counter_live_rknn_bytetrack.py +++ b/counter_live_rknn_bytetrack.py @@ -10,6 +10,7 @@ import csv import os import signal import time +from collections import deque from datetime import datetime from pathlib import Path @@ -48,11 +49,18 @@ NUM_CLASSES = int(os.getenv("NUM_CLASSES", "2")) SCORE_SIGMOID = os.getenv("SCORE_SIGMOID", "false").lower() == "true" # ByteTrack settings -TRACK_HIGH_THRESH = float(os.getenv("TRACK_HIGH_THRESH", "0.5")) -TRACK_LOW_THRESH = float(os.getenv("TRACK_LOW_THRESH", "0.1")) -TRACK_MATCH_THRESH = float(os.getenv("TRACK_MATCH_THRESH", "0.8")) -TRACK_BUFFER = int(os.getenv("TRACK_BUFFER", "30")) -TRACK_MIN_HITS = int(os.getenv("TRACK_MIN_HITS", "3")) +# Ayam index 0 +TRACK_HIGH_THRESH_0 = float(os.getenv("TRACK_HIGH_THRESH_0", "0.5")) +TRACK_LOW_THRESH_0 = float(os.getenv("TRACK_LOW_THRESH_0", "0.1")) +TRACK_MATCH_THRESH_0 = float(os.getenv("TRACK_MATCH_THRESH_0", "0.8")) +TRACK_BUFFER_0 = int(os.getenv("TRACK_BUFFER_0", "30")) +TRACK_MIN_HITS_0 = int(os.getenv("TRACK_MIN_HITS_0", "3")) +# Talenan index 1 +TRACK_HIGH_THRESH_1 = float(os.getenv("TRACK_HIGH_THRESH_1", "0.5")) +TRACK_LOW_THRESH_1 = float(os.getenv("TRACK_LOW_THRESH_1", "0.1")) +TRACK_MATCH_THRESH_1 = float(os.getenv("TRACK_MATCH_THRESH_1", "0.6")) +TRACK_BUFFER_1 = int(os.getenv("TRACK_BUFFER_1", "30")) +TRACK_MIN_HITS_1 = int(os.getenv("TRACK_MIN_HITS_1", "3")) DAILY_CUTOFF_TIME = os.getenv("DAILY_CUTOFF_TIME", "20:00") BATCH_TIMEOUT_SECONDS = float(os.getenv("BATCH_TIMEOUT_SECONDS", "300")) @@ -65,6 +73,7 @@ MIN_DURATION_PER_BATCH = int(os.getenv("MIN_DURATION_PER_BATCH", "60")) EXPORT_CSV = os.getenv("EXPORT_CSV", "true").lower() == "true" CROSS_CSV = os.getenv("CROSS_CSV", f"{OUTPUT_DIR}/batch_crossings.csv") +RATE_WINDOW_SEC = int(os.getenv("RATE_WINDOW_SEC", "60")) WARMUP_FRAMES = int(os.getenv("WARMUP_FRAMES", "30")) RECONNECT_DELAY_SEC = int(os.getenv("RECONNECT_DELAY_SEC", "3")) MAX_RECONNECT_ATTEMPTS = int(os.getenv("MAX_RECONNECT_ATTEMPTS", "0")) @@ -345,11 +354,13 @@ class ByteTracker: # --- separate detections by score --- if len(boxes_xyxy) > 0: remain = scores > self.low_thresh + remain_orig_idx = np.where(remain)[0] dets = boxes_xyxy[remain] det_scores = scores[remain] is_high = det_scores > self.high_thresh is_low = ~is_high else: + remain_orig_idx = np.zeros(0, dtype=np.int64) dets = np.zeros((0, 4), dtype=np.float32) det_scores = np.zeros(0, dtype=np.float32) is_high = np.zeros(0, dtype=bool) @@ -389,10 +400,11 @@ class ByteTracker: for di, ti in matches: det_global = int(high_idx[di]) + orig_idx = int(remain_orig_idx[det_global]) track_pool[ti].update(dets[det_global]) track_pool[ti].hit_streak = max(1, track_pool[ti].hit_streak) matched_track_idx.add(ti) - det_to_track[det_global] = track_pool[ti].track_id + det_to_track[orig_idx] = track_pool[ti].track_id tracked_map[track_pool[ti].track_id] = track_pool[ti].get_cx() match_pairs_high.append((det_global, ti)) @@ -408,17 +420,20 @@ class ByteTracker: unmatched_boxes = track_boxes[unmatched_tracks] iou_mat = _ious_xyxy(low_dets, unmatched_boxes) cost_mat = 1.0 - iou_mat - matches2 = _greedy_match(cost_mat, threshold=0.5) + matches2 = _greedy_match( + cost_mat, threshold=1.0 - self.match_thresh + ) for di, uti in matches2: det_global = int(low_idx[di]) pool_idx = unmatched_tracks[uti] + orig_idx = int(remain_orig_idx[det_global]) track_pool[pool_idx].update(dets[det_global]) track_pool[pool_idx].hit_streak = max( 1, track_pool[pool_idx].hit_streak ) matched_track_idx.add(pool_idx) - det_to_track[det_global] = track_pool[pool_idx].track_id + det_to_track[orig_idx] = track_pool[pool_idx].track_id tracked_map[track_pool[pool_idx].track_id] = track_pool[ pool_idx ].get_cx() @@ -454,10 +469,11 @@ class ByteTracker: high_all = np.where(is_high)[0] matched_det_ids = set(det_to_track.keys()) for dg in high_all: - if int(dg) not in matched_det_ids: - trk = KalmanBoxTracker(dets[dg]) + orig_idx = int(remain_orig_idx[int(dg)]) + if orig_idx not in matched_det_ids: + trk = KalmanBoxTracker(dets[int(dg)]) self.tracked_tracks.append(trk) - det_to_track[int(dg)] = trk.track_id + det_to_track[orig_idx] = trk.track_id tracked_map[trk.track_id] = trk.get_cx() return tracked_map, det_to_track, lost_map @@ -749,61 +765,59 @@ def draw_hero_count(img, line_x, h, count, pulse_remaining=0): text = str(count) font = cv2.FONT_HERSHEY_SIMPLEX boost = 0.35 * (pulse_remaining / max(COUNT_PULSE_FRAMES, 1)) - font_scale, thickness = 1.6 + boost, 3 + font_scale, thickness = 1.4 + boost, 3 (tw, th), _ = cv2.getTextSize(text, font, font_scale, thickness) pad = 14 - tx, ty = line_x - tw // 2, h // 2 + th // 2 + tx, ty = line_x - tw // 2, h // 3 + th // 2 overlay_rect( - img, tx - pad, ty - th - pad, tx + tw + pad, ty + pad // 2, C_PANEL, alpha=0.78 + img, tx - pad, ty - th - pad, tx + tw + pad, ty + pad, C_PANEL, alpha=0.78 ) cv2.rectangle( - img, (tx - pad, ty - th - pad), (tx + tw + pad, ty + pad // 2), C_LINE_CORE, 2 + img, (tx - pad, ty - th - pad), (tx + tw + pad, ty + pad), C_LINE_CORE, 2 ) cv2.putText(img, text, (tx, ty), font, font_scale, C_GREEN, thickness, cv2.LINE_AA) -def draw_hud( - img, w, batch_num, batch_count, total_ayam, elapsed_sec, rate, camera_id, clock -): - bar_h = 52 +def draw_hud(img, w, batch_num, batch_count, total_ayam, elapsed_sec, rate): + bar_h = 40 overlay_rect(img, 0, 0, w, bar_h, C_PANEL, alpha=0.72) cv2.line(img, (0, bar_h), (w, bar_h), C_BORDER, 1) cv2.putText( - img, "BATCH", (16, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.45, C_MUTED, 1, cv2.LINE_AA + img, "BATCH", (14, 14), cv2.FONT_HERSHEY_SIMPLEX, 0.32, C_MUTED, 1, cv2.LINE_AA ) - batch_label = str(batch_num) if batch_num else "\u2014" + batch_label = str(batch_num) if batch_num else "--" cv2.putText( img, batch_label, - (16, 44), + (14, 32), cv2.FONT_HERSHEY_SIMPLEX, - 0.9, + 0.55, C_ACCENT, - 2, + 1, cv2.LINE_AA, ) cv2.putText( - img, "COUNT", (100, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.45, C_MUTED, 1, cv2.LINE_AA + img, "COUNT", (90, 14), cv2.FONT_HERSHEY_SIMPLEX, 0.32, C_MUTED, 1, cv2.LINE_AA ) cv2.putText( img, str(batch_count), - (100, 44), + (90, 32), cv2.FONT_HERSHEY_SIMPLEX, - 0.9, + 0.55, C_GREEN, - 2, + 1, cv2.LINE_AA, ) cv2.putText( - img, "TOTAL", (190, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.45, C_MUTED, 1, cv2.LINE_AA + img, "TOTAL", (170, 14), cv2.FONT_HERSHEY_SIMPLEX, 0.32, C_MUTED, 1, cv2.LINE_AA ) cv2.putText( img, str(total_ayam), - (190, 44), + (170, 32), cv2.FONT_HERSHEY_SIMPLEX, - 0.7, + 0.45, C_TEXT, 1, cv2.LINE_AA, @@ -811,9 +825,9 @@ def draw_hud( cv2.putText( img, "UPTIME", - (280, 20), + (250, 14), cv2.FONT_HERSHEY_SIMPLEX, - 0.45, + 0.32, C_MUTED, 1, cv2.LINE_AA, @@ -821,45 +835,34 @@ def draw_hud( cv2.putText( img, f"{elapsed_sec / 3600:.1f}h", - (280, 44), + (250, 32), cv2.FONT_HERSHEY_SIMPLEX, - 0.7, + 0.45, C_TEXT, 1, cv2.LINE_AA, ) cv2.putText( - img, "RATE", (380, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.45, C_MUTED, 1, cv2.LINE_AA + img, "RATE", (340, 14), cv2.FONT_HERSHEY_SIMPLEX, 0.32, C_MUTED, 1, cv2.LINE_AA ) cv2.putText( img, f"{rate:.1f}/min", - (380, 44), + (340, 32), cv2.FONT_HERSHEY_SIMPLEX, - 0.7, + 0.45, C_ACCENT, 1, cv2.LINE_AA, ) - # cv2.putText(img, clock, (w - 180, 36), cv2.FONT_HERSHEY_SIMPLEX, 0.55, C_TEXT, 1, cv2.LINE_AA) - cv2.putText( - img, - f"CAM {camera_id}", - (w - 180, 20), - cv2.FONT_HERSHEY_SIMPLEX, - 0.45, - C_MUTED, - 1, - cv2.LINE_AA, - ) -def draw_footer(img, w, h, frame_idx, live_tag): +def draw_footer(img, w, h, frame_idx, live_tag, inf_ms=0.0, model_name=""): bar_h = 28 overlay_rect(img, 0, h - bar_h, w, h, C_PANEL, alpha=0.55) cv2.putText( img, - f"{live_tag} | Frame {frame_idx}", + f"{live_tag} | {model_name} | Frame {frame_idx} | Inf {inf_ms:.1f}ms", (12, h - 9), cv2.FONT_HERSHEY_SIMPLEX, 0.45, @@ -982,26 +985,22 @@ def run(): score_sigmoid=SCORE_SIGMOID, ) - CLASS_IDS = { - os.getenv("CLASS_AYAM", "ayam"): 0, - os.getenv("CLASS_TALENAN", "talenan"): 1, - } - ayam_cls = CLASS_IDS[CLASS_AYAM] - talenan_cls = CLASS_IDS[CLASS_TALENAN] + ayam_cls = int(os.getenv("AYAM_CLASS_ID", "0")) + talenan_cls = int(os.getenv("TALENAN_CLASS_ID", "1")) ayam_tracker = ByteTracker( - track_high_thresh=TRACK_HIGH_THRESH, - track_low_thresh=TRACK_LOW_THRESH, - match_thresh=TRACK_MATCH_THRESH, - track_buffer=TRACK_BUFFER, - min_hits=TRACK_MIN_HITS, + track_high_thresh=TRACK_HIGH_THRESH_0, + track_low_thresh=TRACK_LOW_THRESH_0, + match_thresh=TRACK_MATCH_THRESH_0, + track_buffer=TRACK_BUFFER_0, + min_hits=TRACK_MIN_HITS_0, ) talenan_tracker = ByteTracker( - track_high_thresh=TRACK_HIGH_THRESH, - track_low_thresh=TRACK_LOW_THRESH, - match_thresh=TRACK_MATCH_THRESH, - track_buffer=TRACK_BUFFER, - min_hits=TRACK_MIN_HITS, + track_high_thresh=TRACK_HIGH_THRESH_1, + track_low_thresh=TRACK_LOW_THRESH_1, + match_thresh=TRACK_MATCH_THRESH_1, + track_buffer=TRACK_BUFFER_1, + min_hits=TRACK_MIN_HITS_1, ) ayam_line_crossed = set() @@ -1014,7 +1013,9 @@ def run(): session_start = time.time() frame_idx = 0 + inf_ms = 0.0 video_writer = None + crossing_times = deque() cap, w, h, fps = connect_stream(SOURCE) if cap is None: @@ -1028,8 +1029,12 @@ def run(): ) print(f"Model: {MODEL_PATH} | imgsz={IMGSZ} | core_mask={CORE_MASK}") print( - f"ByteTrack: high_thresh={TRACK_HIGH_THRESH} low_thresh={TRACK_LOW_THRESH} " - f"match_thresh={TRACK_MATCH_THRESH} buffer={TRACK_BUFFER}" + f"ByteTrack Index 0: high_thresh={TRACK_HIGH_THRESH_0} low_thresh={TRACK_LOW_THRESH_0} " + f"match_thresh={TRACK_MATCH_THRESH_0} buffer={TRACK_BUFFER_0}" + ) + print( + f"ByteTrack Index 1: high_thresh={TRACK_HIGH_THRESH_1} low_thresh={TRACK_LOW_THRESH_1} " + f"match_thresh={TRACK_MATCH_THRESH_1} buffer={TRACK_BUFFER_1}" ) print(f"DB: {DB_PATH}") print(f"State: {STATE_FILE}") @@ -1061,7 +1066,9 @@ def run(): mono = time.monotonic() ayam_crossed_frame = batch_closed_frame = batch_started_frame = False + inf_start = time.time() detections = model(frame) + inf_ms = inf_ms * 0.9 + (time.time() - inf_start) * 1000 * 0.1 if detections: ayam_boxes_xyxy = [] @@ -1104,6 +1111,56 @@ def run(): talenan_tracker.update(talenan_boxes_xyxy, talenan_scores) ) + if os.getenv("DEBUG_TRACKING", "").lower() == "true": + if len(ayam_boxes_xyxy) > 0 or len(talenan_boxes_xyxy) > 0: + ayam_scores_str = ( + f" ayam scores: {ayam_scores.round(3).tolist()}" + if len(ayam_scores) > 0 + else "" + ) + talenan_scores_str = ( + f" talenan scores: {talenan_scores.round(3).tolist()}" + if len(talenan_scores) > 0 + else "" + ) + ayam_tracks_str = ( + f" ayam det→track: {dict(ayam_det_to_track)}" + if ayam_det_to_track + else "" + ) + talenan_tracks_str = ( + f" talenan det→track: {dict(talenan_det_to_track)}" + if talenan_det_to_track + else "" + ) + crossing_str = ( + f" ayam_line_crossed: {sorted(ayam_line_crossed)}" + if ayam_line_crossed + else "" + ) + # Show cx values for one tracked object to check movement + cx_sample = "" + if len(ayam_cx_list) > 0 and ayam_det_to_track: + sample_tid = list(ayam_det_to_track.values())[0] + sample_cx = ayam_cx_list[ + list(ayam_det_to_track.keys())[0] + ] + prev = ( + ayam_tracked.get(sample_tid, (None,))[0] + if ayam_tracked.get(sample_tid) + else None + ) + cx_sample = ( + f" sample tid={sample_tid} prev_cx={prev} cx={sample_cx:.1f}" + ) + print( + f"[DEBUG F{frame_idx}] ayam_dets={len(ayam_boxes_xyxy)} " + f"talenan_dets={len(talenan_boxes_xyxy)} " + f"line_x={line_x}{ayam_scores_str}{talenan_scores_str}" + f"{ayam_tracks_str}{talenan_tracks_str}{crossing_str}" + f"{cx_sample}" + ) + # Process talenan crossings for di in range(len(talenan_boxes_xyxy)): tid = talenan_det_to_track.get(di) @@ -1145,6 +1202,11 @@ def run(): crossed_line(prev_cx, cx, line_x) and tid not in ayam_line_crossed ): + if os.getenv("DEBUG_TRACKING", "").lower() == "true": + print( + f"[DEBUG F{frame_idx}] CROSS DETECTED: tid={tid} " + f"prev_cx={prev_cx:.1f} → cx={cx:.1f} line_x={line_x}" + ) ayam_line_crossed.add(tid) _, started_new = store.record_ayam_crossing(tid) if cross_logger: @@ -1159,6 +1221,7 @@ def run(): ayam_crossed_frame = True if started_new: batch_started_frame = True + crossing_times.append(mono) ayam_cross_flash[tid] = CROSS_FLASH_FRAMES popups.append( { @@ -1216,7 +1279,9 @@ def run(): batch_num = store.current_batch_number or 0 batch_count = store.current_batch_count display_total = store.display_total() - rate = (display_total / elapsed * 60) if elapsed > 0 else 0.0 + 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 draw_elegant_counting_line(frame, line_x, h, line_pulse) draw_hero_count(frame, line_x, h, batch_count, count_pulse) @@ -1228,12 +1293,16 @@ def run(): display_total, elapsed, rate, - CAMERA_NAME, - now_str(), ) draw_batch_banner(frame, w, batch_num, batch_pulse) draw_footer( - frame, w, h, frame_idx, "LIVE-RKNN-BT" if IS_LIVE else "FILE-RKNN-BT" + frame, + w, + h, + frame_idx, + "LIVE" if IS_LIVE else "FILE", + inf_ms, + Path(MODEL_PATH).name, ) popups = draw_popups(frame, popups, frame_idx) diff --git a/src/bytetrack.cpp b/src/bytetrack.cpp index 0e073a2..7ebe9dc 100644 --- a/src/bytetrack.cpp +++ b/src/bytetrack.cpp @@ -134,7 +134,7 @@ TrackResult ByteTracker::update(const Eigen::MatrixXf& boxes_xyxy, const Eigen:: auto iou_mat = ious_xyxy(low_mat, unmatched_boxes); auto cost_mat = Eigen::MatrixXf::Constant(n_low, n_unmatched, 1.0f) - iou_mat; - auto matches2 = greedy_match(cost_mat, 0.5f); + auto matches2 = greedy_match(cost_mat, 1.0f - match_thresh_); for (auto [di, uti] : matches2) { int det_global = low_indices[di]; diff --git a/src/config.cpp b/src/config.cpp index b457db6..1ddda04 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -74,18 +74,32 @@ void AppConfig::load_from_env(const char* env_path) { auto ss_s = get_env("SCORE_SIGMOID"); score_sigmoid = (ss_s == "true"); - auto th_s = get_env("TRACK_HIGH_THRESH"); - if (!th_s.empty()) track_high_thresh = std::stof(th_s); - auto tl_s = get_env("TRACK_LOW_THRESH"); - if (!tl_s.empty()) track_low_thresh = std::stof(tl_s); - auto tm_s = get_env("TRACK_MATCH_THRESH"); - if (!tm_s.empty()) track_match_thresh = std::stof(tm_s); - auto tb_s = get_env("TRACK_BUFFER"); - if (!tb_s.empty()) track_buffer = std::stoi(tb_s); - auto tmh_s = get_env("TRACK_MIN_HITS"); - if (!tmh_s.empty()) track_min_hits = std::stoi(tmh_s); + auto th0_s = get_env("TRACK_HIGH_THRESH_0"); + if (!th0_s.empty()) track_high_thresh_0 = std::stof(th0_s); + auto tl0_s = get_env("TRACK_LOW_THRESH_0"); + if (!tl0_s.empty()) track_low_thresh_0 = std::stof(tl0_s); + auto tm0_s = get_env("TRACK_MATCH_THRESH_0"); + if (!tm0_s.empty()) track_match_thresh_0 = std::stof(tm0_s); + auto tb0_s = get_env("TRACK_BUFFER_0"); + if (!tb0_s.empty()) track_buffer_0 = std::stoi(tb0_s); + auto tmh0_s = get_env("TRACK_MIN_HITS_0"); + if (!tmh0_s.empty()) track_min_hits_0 = std::stoi(tmh0_s); - daily_cutoff_time = get_env("DAILY_CUTOFF_TIME", daily_cutoff_time); + auto th1_s = get_env("TRACK_HIGH_THRESH_1"); + if (!th1_s.empty()) track_high_thresh_1 = std::stof(th1_s); + auto tl1_s = get_env("TRACK_LOW_THRESH_1"); + if (!tl1_s.empty()) track_low_thresh_1 = std::stof(tl1_s); + auto tm1_s = get_env("TRACK_MATCH_THRESH_1"); + if (!tm1_s.empty()) track_match_thresh_1 = std::stof(tm1_s); + auto tb1_s = get_env("TRACK_BUFFER_1"); + if (!tb1_s.empty()) track_buffer_1 = std::stoi(tb1_s); + auto tmh1_s = get_env("TRACK_MIN_HITS_1"); + if (!tmh1_s.empty()) track_min_hits_1 = std::stoi(tmh1_s); + + auto rw_s = get_env("RATE_WINDOW_SEC"); + if (!rw_s.empty()) rate_window_sec = std::stoi(rw_s); + + daily_cutoff_time = get_env("DAILY_CUTOFF_TIME", get_env("CUTOFF_TIME", daily_cutoff_time)); 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"); @@ -125,4 +139,15 @@ void AppConfig::load_from_env(const char* env_path) { if (!lsn_s.empty()) live_stream_every_n = std::stoi(lsn_s); rtsp_ffmpeg_options = get_env("OPENCV_FFMPEG_CAPTURE_OPTIONS", rtsp_ffmpeg_options); + + auto cff_s = get_env("CROSS_FLASH_FRAMES"); + if (!cff_s.empty()) cross_flash_frames = std::stoi(cff_s); + auto pl_s = get_env("POPUP_LIFETIME"); + if (!pl_s.empty()) popup_lifetime = std::stoi(pl_s); + auto lpf_s = get_env("LINE_PULSE_FRAMES"); + if (!lpf_s.empty()) line_pulse_frames = std::stoi(lpf_s); + auto cpf_s = get_env("COUNT_PULSE_FRAMES"); + if (!cpf_s.empty()) count_pulse_frames = std::stoi(cpf_s); + auto bpf_s = get_env("BATCH_PULSE_FRAMES"); + if (!bpf_s.empty()) batch_pulse_frames = std::stoi(bpf_s); } diff --git a/src/config.hpp b/src/config.hpp index e334e5f..2188e00 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -25,11 +25,19 @@ struct AppConfig { int num_classes = 2; bool score_sigmoid = false; - float track_high_thresh = 0.5f; - float track_low_thresh = 0.1f; - float track_match_thresh = 0.8f; - int track_buffer = 30; - int track_min_hits = 3; + float track_high_thresh_0 = 0.5f; + float track_low_thresh_0 = 0.1f; + float track_match_thresh_0 = 0.8f; + int track_buffer_0 = 30; + int track_min_hits_0 = 3; + + float track_high_thresh_1 = 0.5f; + float track_low_thresh_1 = 0.1f; + float track_match_thresh_1 = 0.6f; + int track_buffer_1 = 30; + int track_min_hits_1 = 3; + + int rate_window_sec = 60; std::string daily_cutoff_time = "20:00"; float batch_timeout_seconds = 300.0f; diff --git a/src/main.cpp b/src/main.cpp index 8653939..00cdd1e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,12 +105,12 @@ int main(int argc, char* argv[]) { g_config.imgsz, g_config.conf, 0.45f, g_config.num_classes, 0, g_config.score_sigmoid); - ByteTracker ayam_tracker(g_config.track_high_thresh, g_config.track_low_thresh, - g_config.track_match_thresh, g_config.track_buffer, - g_config.track_min_hits); - ByteTracker talenan_tracker(g_config.track_high_thresh, g_config.track_low_thresh, - g_config.track_match_thresh, g_config.track_buffer, - g_config.track_min_hits); + ByteTracker ayam_tracker(g_config.track_high_thresh_0, g_config.track_low_thresh_0, + g_config.track_match_thresh_0, g_config.track_buffer_0, + g_config.track_min_hits_0); + ByteTracker talenan_tracker(g_config.track_high_thresh_1, g_config.track_low_thresh_1, + g_config.track_match_thresh_1, g_config.track_buffer_1, + g_config.track_min_hits_1); std::unordered_set ayam_line_crossed; std::unordered_set talenan_line_crossed; @@ -122,6 +122,7 @@ int main(int argc, char* argv[]) { auto session_start = std::chrono::steady_clock::now(); int frame_idx = 0; + std::deque crossing_times; cv::VideoCapture cap = open_capture(g_config.source); bool is_live = g_config.source.substr(0, 7) == "rtsp://" || @@ -317,6 +318,7 @@ int main(int argc, char* argv[]) { } ayam_crossed_frame = true; if (started_new) batch_started_frame = true; + crossing_times.push_back(mono); ayam_cross_flash[tid] = g_config.cross_flash_frames; popups.push_back({ static_cast(cx) - 12, @@ -380,7 +382,13 @@ int main(int argc, char* argv[]) { int batch_count = store.current_batch_count(); int display_total = store.display_total(); double elapsed = static_cast(elapsed_sec); - double rate = elapsed > 0 ? (display_total / elapsed * 60.0) : 0.0; + while (!crossing_times.empty() && + std::chrono::duration_cast( + mono - crossing_times.front()).count() > g_config.rate_window_sec) { + crossing_times.pop_front(); + } + double rate = crossing_times.empty() ? 0.0 + : (static_cast(crossing_times.size()) / g_config.rate_window_sec * 60.0); draw_elegant_counting_line(frame, line_x, h, line_pulse); draw_hero_count(frame, line_x, h, batch_count, count_pulse);