Files
chicken-counting-sukawarna-det/src/chicken_counter/batch_runner.py
T

124 lines
4.9 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Run CC1–CC4 sequentially, then compress videos and write the JSON report."""
from __future__ import annotations
from datetime import date as date_type
from pathlib import Path
from chicken_counter.batch_discovery import discover_camera_videos
from chicken_counter.compress import compress_video_to_target
from chicken_counter.config import BatchSettings, build_camera_config_from_batch
from chicken_counter.pipeline import run_pipeline
from chicken_counter.report import build_batch_report, persist_batch_reports
from chicken_counter.tracking import DetectionTracker
from chicken_counter.types import CameraBatchResult
def run_daily_batch(settings: BatchSettings, date: str | None = None, *, verbose: bool = False, no_video: bool = False, show_progress: bool = False) -> Path:
run_date = date or date_type.today().isoformat()
day_dir = Path(settings.batch.root_dir) / run_date
output_dir = day_dir / settings.batch.output_subdir
output_dir.mkdir(parents=True, exist_ok=True)
print(f"[batch] starting daily run for {run_date}")
print(f"[batch] input folder: {day_dir}")
print(f"[batch] output folder: {output_dir}")
if no_video:
print("[batch] --no-video: skipping video output, overlay, and compression")
discovery = discover_camera_videos(day_dir, settings)
camera_order = sorted(settings.cameras.items(), key=lambda item: item[1].camera_num)
first_camera_id = next(
camera_id for camera_id, _preset in camera_order if camera_id in discovery.found
)
first_source = discovery.found[first_camera_id]
init_output_path = output_dir / f"{first_camera_id}_vis.mp4" if not no_video else None
init_config = build_camera_config_from_batch(
settings,
first_camera_id,
source=first_source,
output_path=init_output_path,
checkpoint_dir=output_dir / "checkpoints" / first_camera_id,
)
shared_tracker = DetectionTracker(init_config)
camera_results: list[CameraBatchResult] = []
report_path = output_dir / f"counts_{run_date}.json"
for camera_id, _preset in camera_order:
if camera_id in discovery.skipped:
skip_reason = discovery.skipped[camera_id]
print(f"[batch] skipping {camera_id}: {skip_reason}")
camera_results.append(
CameraBatchResult(
camera_id=camera_id,
skipped=True,
skip_reason=skip_reason,
)
)
persist_batch_reports(run_date, camera_results, output_dir)
continue
source_path = discovery.found[camera_id]
vis_path = output_dir / f"{camera_id}_vis.mp4" if not no_video else None
checkpoint_dir = output_dir / "checkpoints" / camera_id
print(f"[batch] processing {camera_id} from {source_path.name}")
camera_config = build_camera_config_from_batch(
settings,
camera_id,
source=source_path,
output_path=vis_path,
checkpoint_dir=checkpoint_dir,
)
camera_config.performance.verbose = verbose
pipeline_result = run_pipeline(camera_config, tracker=shared_tracker, show_progress=show_progress)
camera_results.append(
CameraBatchResult(
camera_id=camera_id,
pipeline=pipeline_result,
)
)
print(
f"[batch] finished {camera_id}: total_entered={pipeline_result.total_entered_count} "
f"frames={pipeline_result.frames_processed} reason={pipeline_result.stopped_reason}"
)
persist_batch_reports(run_date, camera_results, output_dir)
if no_video:
report = build_batch_report(run_date, camera_results, output_dir=output_dir)
print(
f"[batch] complete for {run_date}: total_entered_sum={report.total_entered_sum} "
f"report={report_path}"
)
return report_path
print("[batch] all cameras complete; starting compression")
for item in camera_results:
if item.skipped or item.pipeline is None:
continue
vis_path = item.pipeline.vis_video_path
if not vis_path:
continue
compressed_path = output_dir / f"{item.camera_id}_compressed.mp4"
size_mb = compress_video_to_target(
vis_path,
compressed_path,
max_mb=settings.batch.compress_max_mb,
)
item.compressed_video_path = str(compressed_path)
item.compressed_size_mb = size_mb
if settings.batch.delete_intermediate:
Path(vis_path).unlink(missing_ok=True)
persist_batch_reports(run_date, camera_results, output_dir)
report = build_batch_report(run_date, camera_results, output_dir=output_dir)
print(
f"[batch] complete for {run_date}: total_entered_sum={report.total_entered_sum} "
f"report={report_path}"
)
return report_path