From ec7226d17283924255b6b597a37a012037b5c227 Mon Sep 17 00:00:00 2001 From: dsutanto Date: Wed, 19 Aug 2026 10:24:46 +0700 Subject: [PATCH] docs: clarify that 2-pass mortality detection is disabled by default for higher accuracy --- README.md | 4 ++-- RUN.md | 4 ++-- src/chicken_counter/mortality.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3d4d993..002b6e0 100644 --- a/README.md +++ b/README.md @@ -266,10 +266,10 @@ chicken-counter mortality --date 2026-05-23 Key features: - **Multi-Image & Multi-Day Support**: Processes multiple images per day (e.g. morning/afternoon scans), aggregates the grand total carcass count (`total_mortality_count`), and saves outputs into date-isolated directories. -- **2-Pass Detect & Refine**: runs the YOLO segmentation model once to find candidate regions, then uses `cv2.matchTemplate` to do a similarity search over each candidate before confirming it as a detection. This reduces false positives significantly. +- **Direct High-Precision Segmentation (Default)**: Uses the **segmentation model** (`models/chicken-detection-model-v26n-seg-300e-best-2026-04-18.pt`) directly. 2-pass Detect & Refine (`two_pass: false`) is disabled by default because direct segmentation achieves higher accuracy and avoids false rejection on real farm photos. +- **Optional 2-Pass Refine (`--two-pass`)**: An optional mode combining initial segmentation candidate proposals with `cv2.matchTemplate` similarity refinement. - **Containment filtering**: boxes where `IoA > 0.50` against a larger box are suppressed. - **Centroid deduplication**: detections whose centroids are within `dedupe_radius_px` of each other are merged to prevent counting the same carcass twice. -- Uses the **segmentation model** (`models/chicken-detection-model-v26n-seg-300e-best-2026-04-18.pt`) which provides higher boundary precision than the standard detection model. Outputs for each daily run: - `output_.jpg` — annotated images with bounding boxes and carcass IDs diff --git a/RUN.md b/RUN.md index 1ac28c4..19f02d2 100644 --- a/RUN.md +++ b/RUN.md @@ -66,7 +66,7 @@ Put your model files in the `models/` directory. | :--- | :--- | :--- | | Batch video counting (TensorRT) | `models/chicken-detection-model-v26n-300e-best-2026-05-02-NEW.engine` | Maximum GPU throughput | | Base PyTorch weights | `models/chicken-detection-model-v26n-300e-best-2026-05-02-NEW.pt` | Used for portable runs and auto-recompiling engines | -| Mortality detection | `models/chicken-detection-model-v26n-seg-300e-best-2026-04-18.pt` | 2-pass segmentation model | +| Mortality detection | `models/chicken-detection-model-v26n-seg-300e-best-2026-04-18.pt` | Direct segmentation model (2-pass disabled by default for accuracy) | > **Self-Healing Recompilation on New Machines**: If you move the project to a new machine with a different GPU or OS, the pipeline will detect any incompatible `.engine`, automatically locate the matching `.pt` model, recompile a new `.engine` for the host machine, and update `configs/cycle7_batch_optimized.yaml` automatically. @@ -149,7 +149,7 @@ A `mortality_report.json` is also saved there with full detection data. | `iou` | IoU NMS threshold | | `min_box_area_px` | Minimum bounding box area in pixels | | `dedupe_radius_px` | Centroid deduplication radius in pixels | -| `two_pass` | Enable 2x Detect & Refine pipeline | +| `two_pass` | 2x Detect & Refine pipeline (`false` by default; single-pass direct achieves higher accuracy on farm footage) | | `classes` | `[0]` = chicken only; ignores background/text/equipment | --- diff --git a/src/chicken_counter/mortality.py b/src/chicken_counter/mortality.py index cade46a..04d6189 100644 --- a/src/chicken_counter/mortality.py +++ b/src/chicken_counter/mortality.py @@ -262,7 +262,7 @@ def run_mortality_count( iou_threshold = iou_threshold if iou_threshold is not None else float(cfg.get("iou", 0.45)) min_box_area_px = min_box_area_px if min_box_area_px is not None else int(cfg.get("min_box_area_px", 2500)) dedupe_radius_px = dedupe_radius_px if dedupe_radius_px is not None else float(cfg.get("dedupe_radius_px", 30.0)) - two_pass = two_pass if two_pass is not None else bool(cfg.get("two_pass", True)) + two_pass = two_pass if two_pass is not None else bool(cfg.get("two_pass", False)) device = device if device is not None else cfg.get("device", "0") classes = classes if classes is not None else cfg.get("classes", [0]) imgsz = imgsz if imgsz is not None else int(cfg.get("imgsz", 640))