# ============================================================================= # ZenAI KTC — Edge RK3588 sack feeder zone counter + dashboard # Shared config for: counter_live_rknn.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/zenai-ktc-counter # SQLite database path for daily counter records & zone-entry logs DB_PATH=/opt/zenai-ktc-counter/ktc_counter.db # JSON file persisting the current active counting day state STATE_FILE=/opt/zenai-ktc-counter/current_counter.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 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 # NMS IoU threshold (0-1): boxes overlapping the top box by more than this are # suppressed. RAISE it (e.g. 0.6-0.7) if two close/overlapping objects are being # merged into one and their separate boxes get suppressed. Lower = more aggressive # merging. Default 0.45. NMS_IOU=0.45 # --- ByteTrack tracking --- # Detections with score >= this get priority matching in the first association stage TRACK_HIGH_THRESH=0.5 # Detections with score between this and TRACK_HIGH_THRESH are matched in the second stage TRACK_LOW_THRESH=0.1 # IoU threshold for the first-stage association (0–1). Higher = stricter overlap required TRACK_MATCH_THRESH=0.8 # Frames a track survives without a match before being permanently removed TRACK_BUFFER=30 # Minimum consecutive (or total) hits needed before a track is considered confirmed TRACK_MIN_HITS=3 # --- ID-switch counting guards --- # When a track's ID changes right at the counting line, one physical object can be # counted twice (two IDs cross) or missed (neither ID sees the full transition). # These two guards correct for that. # # Dedup guard (prevents double counting): after a zone entry, a second entry in # the SAME feeder within DEDUP_FRAMES frames and DEDUP_PX centroid pixels is # ignored (treated as the same object under a new ID). DEDUP_FRAMES=15 DEDUP_PX=60 # To DISABLE the dedup guard, set DEDUP_PX=-1 (distance check can never match). # # Inheritance guard (prevents missed counting): when a brand-new track appears, it # inherits the last position of a recently-seen nearby track (within INHERIT_SEC # seconds and INHERIT_PX horizontal pixels) so zone entry is still detected # across the ID switch. INHERIT_SEC=1.0 INHERIT_PX=60 # To DISABLE the inheritance guard, set INHERIT_PX=-1 (distance check can never match). # --- Feeder cooldown (seconds) --- # After a sack is counted on a feeder, ignore further counts on that same feeder # for this many seconds. Useful when multiple detections/IDs fire for one sack. # 0 = disabled. ZONE_COOLDOWN_LEFT_SEC=3 ZONE_COOLDOWN_RIGHT_SEC=3 # --- Feeder dwell (seconds) --- # Sack must remain continuously inside the feeder zone for this many seconds # before it is counted and a cross snapshot is saved. Leaving the zone resets # the timer. 0 = count on the first frame inside the zone. ZONE_DWELL_LEFT_SEC=2 ZONE_DWELL_RIGHT_SEC=2 # --- 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=karung # Class name for the counted object (must match model class order) CLASS_OBJECT=karung # Model class ID for the object being counted (default 0) OBJECT_CLASS_ID=0 # Feeder names printed on each count, e.g. # "Total karung di kandang_bawah_feeder_kanan: 5" FEEDER_LEFT_NAME=kandang_bawah_feeder_kiri FEEDER_RIGHT_NAME=kandang_bawah_feeder_kanan # Verbose tracking debug (inherit / dup / cooldown / per-frame dets) DEBUG_TRACKING=false # --- Feeder zones (left / right) --- # Rectangular zones mark the left and right sack feeders. # Count once when a track centroid ENTERS a zone (outside → inside). # Absolute pixel overrides (ZONE_*_X1/Y1/X2/Y2) win over fractions when set. # # Left feeder zone (default: left third of the frame) ZONE_LEFT_X1= ZONE_LEFT_Y1= ZONE_LEFT_X2= ZONE_LEFT_Y2= ZONE_LEFT_X1_FRAC=0.02 ZONE_LEFT_Y1_FRAC=0.10 ZONE_LEFT_X2_FRAC=0.440 ZONE_LEFT_Y2_FRAC=1.00 # # Right feeder zone (full right column) ZONE_RIGHT_X1= ZONE_RIGHT_Y1= ZONE_RIGHT_X2= ZONE_RIGHT_Y2= ZONE_RIGHT_X1_FRAC=0.490 ZONE_RIGHT_Y1_FRAC=0.10 ZONE_RIGHT_X2_FRAC=0.98 ZONE_RIGHT_Y2_FRAC=1.00 # --- Counting day management --- # Daily cutoff time (HH:MM) – a new counting day starts after this time and the # previous day's counter_left / counter_right totals are finalized in the database. # CUTOFF_TIME is an alias used by the dashboard; DAILY_CUTOFF_TIME takes priority in counter_live_rknn.py. DAILY_CUTOFF_TIME=17:00 CUTOFF_TIME=17:00 # --- 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/crossings.csv # --- Crossing snapshots --- # Save an annotated frame image every time an object enters a feeder zone and the # counter increases (true/false, default: false). Written to