feat: implement config inheritance via 'extends' and place lightweight floor configs in configs/floor_config/

This commit is contained in:
proitlab committed 2026-08-19 11:44:46 +07:00
1 parent 5ad4a5f796
commit f9c38e5126
25 files changed
+218 -1526

No files matched your search

+3 -2
View File
@@ -24,10 +24,11 @@ visual.
```text
configs/
K1-L1.yaml .. K5-L2.yaml ← Standard floor configurations (K1-L1 to K5-L2)
floor_config/ ← Lightweight floor configs (K1-L1 to K5-L2)
K1-L1.yaml .. K5-L2.yaml ← Extends cycle7_batch_optimized.yaml
cameras/example_camera.yaml
cycle7_batch.yaml
cycle7_batch_optimized.yaml
cycle7_batch_optimized.yaml ← Base batch processing config
mortality_config.yaml
trackers/botsort_chicken.yaml
src/chicken_counter/
+4 -3
View File
@@ -34,8 +34,9 @@ venv/bin/pip install -r requirements.txt
```text
chicken-counting-sukawarna-det/
├── configs/
│ ├── K1-L1.yaml .. K5-L2.yaml ← Standard floor configurations (K1-L1 to K5-L2)
│ ├── cycle7_batch_optimized.yaml ← Main batch processing config
│ ├── floor_config/ ← Lightweight floor configs (K1-L1 to K5-L2)
│ │ ├── K1-L1.yaml .. K5-L2.yaml ← Extends cycle7_batch_optimized.yaml
│ ├── cycle7_batch_optimized.yaml ← Main base batch processing config
│ ├── cycle7_batch.yaml ← Alternate batch config
│ ├── mortality_config.yaml ← Mortality (carcass) detection config
│ ├── cameras/example_camera.yaml ← Single-camera run config template
@@ -97,7 +98,7 @@ Then run:
# Run a specific floor (e.g. Kandang 1 Lantai 1)
PYTHONPATH=src venv/bin/python -m chicken_counter.cli batch \
--config configs/K1-L1.yaml \
--config configs/floor_config/K1-L1.yaml \
--date 2026-06-18
# Run archive scripts in test_run_folder
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K1-L1"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K1-L1
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K1-L2"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K1-L2
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K2-L1"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K2-L1
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K2-L2"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K2-L2
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K3-L1"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K3-L1
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K3-L2"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K3-L2
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K4-L1"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K4-L1
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K4-L2"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K4-L2
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K5-L1"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K5-L1
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
-151
View File
@@ -1,151 +0,0 @@
batch:
root_dir: "../VIDEOS/cycle7/K5-L2"
camera_glob: "*cam{num}_*.mp4"
output_subdir: output
compress_max_mb: 200
delete_intermediate: false
checkpoint_every_n_frames: 3000
location: K5-L2
db_path: db/chicken_counts.db
cycle_start_date: "2026-05-22" #day 0
execution_mode: parallel_processes # parallel_processes (default) | tensor_batching | hybrid
stages:
early_cycle:
day_min: 0
day_max: 15
detection:
conf: 0.1
min_box_area_px: 100
roi:
min_overlap_ratio: 0.1 # 0.25
mid_cycle:
day_min: 16
day_max: 999
defaults:
detection:
model_path: models/NUC5070_chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine # TensorRT engine (RTX 5070)
classes: [0]
ignored_classes: [1, 2]
conf: 0.40 # mild lift vs 0.35; 0.55 was undercounting
iou: 0.55
imgsz: 640
device: "0"
min_box_area_px: 3000
validate_while_inside: true
dedupe_radius_px: 0 # off for CC1/CC4; CC2/CC3 enable below
dedupe_frames: 12
detection_zone:
enabled: true
buffer_above_px: 250
buffer_below_px: 250
show_in_overlay: true
tracker:
tracker_config_path: configs/trackers/botsort_chicken.yaml
persist: true
track_buffer: 90
gate:
mode: two_line
lines_y: [420, 730]
direction: bottom_to_up
motion:
enabled: true
axis: vertical
forward_sign: 1.0
ema_alpha: 0.2
reverse_enter_threshold: -1.5
reverse_exit_threshold: -0.5
debounce_frames: 12
min_features: 40 # ↓ 60 → less optical flow computation
max_corners: 50 # ↓ 80 → fewer corner featuresis
stride_frames: 3 # ↑ 2 → motion detection every 3rd frame
flow_scale: 0.5
quality_level: 0.01
min_distance: 8
block_radius: 6
overlay:
show_boxes: true
show_track_trails: false
trail_length: 20
show_center_marker: false # ✗ → save 1 circle per chicken
show_track_ring: false
count_anchor: [780, 120]
inside_box_only: true
validated_only: true # NEW → only draw counted chickens
pending_blink: true
pending_colors:
- [255, 255, 0]
- [0, 255, 255]
display:
show_window: false
encoder: auto
output_bitrate_kbps: 2000 # ↓ 4000 → faster encoding
codec_preference: [avc1, mp4v, H264]
performance:
half: false
overlay_buffer_reuse: true
inference_stride: 2
stream:
enabled: true # required for dashboard live feed
shm_dir: /dev/shm
interval_frames: 5
feedback:
enabled: true
every_n_frames: 3000
save_images: false # ✗ → disable checkpoint JPEG I/O spikes
log_to_terminal: true
roi:
inset_left_px: 60
inset_right_px: 60
inset_top_px: 0
inset_bottom_px: 0
min_overlap_ratio: 0.30
cameras:
CC1:
camera_num: 1
count_anchor: [780, 120]
detection:
min_box_area_px: 2500
conf: 0.35
roi:
points:
- [250, 330]
- [1650, 330]
- [1650, 720]
- [250, 720]
CC2:
camera_num: 2
count_anchor: [900, 120]
detection:
conf: 0.5 # From 0.45
dedupe_radius_px: 32
dedupe_frames: 24 # From 18
roi:
points:
- [20, 380]
- [1880, 380]
- [1880, 720]
- [20, 720]
CC3:
camera_num: 3
count_anchor: [900, 120]
detection:
dedupe_radius_px: 24
dedupe_frames: 16 # From 12
roi:
points:
- [20, 330]
- [1880, 330]
- [1880, 720]
- [20, 720]
CC4:
camera_num: 4
count_anchor: [700, 120]
roi:
points:
- [50, 330]
- [1450, 330]
- [1450, 720]
- [50, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K1-L1
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K1-L1"
root_dir: "../VIDEOS/cycle7/K1-L1"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K1-L2
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K1-L2"
root_dir: "../VIDEOS/cycle7/K1-L2"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K2-L1
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K2-L1"
root_dir: "../VIDEOS/cycle7/K2-L1"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K2-L2
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K2-L2"
root_dir: "../VIDEOS/cycle7/K2-L2"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K3-L1
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K3-L1"
root_dir: "../VIDEOS/cycle7/K3-L1"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K3-L2
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K3-L2"
root_dir: "../VIDEOS/cycle7/K3-L2"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K4-L1
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K4-L1"
root_dir: "../VIDEOS/cycle7/K4-L1"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K4-L2
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K4-L2"
root_dir: "../VIDEOS/cycle7/K4-L2"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K5-L1
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K5-L1"
root_dir: "../VIDEOS/cycle7/K5-L1"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+17
View File
@@ -0,0 +1,17 @@
# Floor Configuration for K5-L2
# Inherits all default settings, tracker options, model path, and stage thresholds from cycle7_batch_optimized.yaml
extends: ../cycle7_batch_optimized.yaml
batch:
location: "K5-L2"
root_dir: "../VIDEOS/cycle7/K5-L2"
# Optional per-camera overrides (only uncomment and specify if this floor requires custom ROI or anchors)
# cameras:
# CC1:
# roi:
# points:
# - [250, 330]
# - [1650, 330]
# - [1650, 720]
# - [250, 720]
+11 -11
View File
@@ -14,18 +14,18 @@ fi
DATE="${1:-$(date +%Y-%m-%d)}"
MODE="${2:-parallel_processes}"
# List of all configured floors
# List of all configured floors (in configs/floor_config/)
CONFIGS=(
"configs/K1-L1.yaml"
"configs/K1-L2.yaml"
"configs/K2-L1.yaml"
"configs/K2-L2.yaml"
"configs/K3-L1.yaml"
"configs/K3-L2.yaml"
"configs/K4-L1.yaml"
"configs/K4-L2.yaml"
"configs/K5-L1.yaml"
"configs/K5-L2.yaml"
"configs/floor_config/K1-L1.yaml"
"configs/floor_config/K1-L2.yaml"
"configs/floor_config/K2-L1.yaml"
"configs/floor_config/K2-L2.yaml"
"configs/floor_config/K3-L1.yaml"
"configs/floor_config/K3-L2.yaml"
"configs/floor_config/K4-L1.yaml"
"configs/floor_config/K4-L2.yaml"
"configs/floor_config/K5-L1.yaml"
"configs/floor_config/K5-L2.yaml"
)
echo "================================================================="
+20
View File
@@ -332,6 +332,16 @@ def load_camera_config(path: str | Path, camera_id: str | None = None) -> Camera
config_path = Path(path).resolve()
raw = _load_data(config_path)
base_ref = raw.pop("extends", None) or raw.pop("base_config", None)
if base_ref:
base_path = (config_path.parent / base_ref).resolve()
if not base_path.exists():
base_path = resolve_project_path(base_ref)
if not base_path.exists():
raise FileNotFoundError(f"Base config not found: {base_ref} (referenced in {config_path.name})")
base_raw = _load_data(base_path)
raw = _deep_merge(base_raw, raw)
if "batch" in raw:
raise ValueError(
"This is a batch config file. Use 'chicken-counter batch --config ...' instead."
@@ -350,6 +360,16 @@ def load_batch_config(path: str | Path) -> BatchSettings:
config_path = Path(path).resolve()
raw = _load_data(config_path)
base_ref = raw.pop("extends", None) or raw.pop("base_config", None)
if base_ref:
base_path = (config_path.parent / base_ref).resolve()
if not base_path.exists():
base_path = resolve_project_path(base_ref)
if not base_path.exists():
raise FileNotFoundError(f"Base config not found: {base_ref} (referenced in {config_path.name})")
base_raw = _load_data(base_path)
raw = _deep_merge(base_raw, raw)
if "batch" not in raw:
raise ValueError("Batch config must contain a top-level 'batch' section")
+10
View File
@@ -166,6 +166,16 @@ def update_config_yaml_model_path(
print(f"[engine_utils] 💾 Updated YAML config '{config_path.name}' -> model_path: {formatted_path}")
return True
# If model_path was not found in this file, check if it extends a base config
extends_match = re.search(r"^\s*(?:extends|base_config):\s*['\"]?([^'\"\s#]+)['\"]?", content, re.MULTILINE)
if extends_match:
base_rel = extends_match.group(1).strip()
base_path = (config_path.parent / base_rel).resolve()
if not base_path.exists():
base_path = (PROJECT_ROOT / base_rel).resolve()
if base_path.exists():
return update_config_yaml_model_path(base_path, new_model_path)
return False