--- license: agpl-3.0 library_name: ultralytics pipeline_tag: object-detection tags: - yolo - ultralytics - object-detection - agriculture - livestock - cattle - estrus-detection - computer-vision --- # Cowcatcher
### Check out the website for all the information: [cowcatcherai.com](https://jacobsfarm.github.io/website/) **The website is available in multiple languages such as Deutsch, FranΓ§ais, Nederlands, and EspaΓ±ol.** Cowcatcher is a vision model that detects **mounting behaviour** in cattle from camera images. Mounting is one of the clearest visual signals that a cow is in heat, so a reliable detector lets a barn camera flag oestrus automatically instead of relying on someone watching the herd. All models are single-class (`mounting`) Ultralytics models, trained at 640 px on farm camera footage from multiple dairy and beef sites, in daylight, night/IR and robot-barn conditions. **Latest and best model: `cowcatcherV17.2.pt`.** It is the only model in the comparison that produces **zero false alarms** on the null set, at any threshold from 0.50 upward. --- ## Available models | File | Task | Base | Train imgsz / epochs | Size | Notes | |---|---|---|---|---|---| | **`cowcatcherV17.2.pt`** | Detection | `yolo26m` | 640 / 50 | 44 MB | **Recommended.** Best precision and best confidence separation | | `cowcatcherV17.pt` | Detection | `yolo26m` | 640 / 400 | 131 MB | Previous main model, higher recall at low thresholds | | `cowcatcherV16.pt` | Detection | `yolo26m` | 640 / 400 | 88 MB | Highest recall at 0.88, but 21 false alarms | | `cowcatcherV15.pt` | Detection | `yolo12m` | 640 / 100 | 81 MB | Older generation | | `cowcatcherV14.pt` | Detection | `yolo12m` | 640 / 100 | 41 MB | Older generation, very few false alarms but low recall | | `cowcatcherV13.pt` | Detection | `yolo12m` | 640 / 100 | 81 MB | Oldest published model, kept for reference | | `cowcatcherV1-seg.pt` | Segmentation | `yolo11m` | 640 / 100 | 45 MB | Experimental mask model, not part of the benchmark below | All six detection models are published here and all six appear in the benchmark tables below. --- ## Quick start ```bash pip install ultralytics ``` ```python from ultralytics import YOLO model = YOLO("cowcatcherV17.2.pt") # Single image results = model.predict("barn_frame.jpg", conf=0.50) for r in results: for box in r.boxes: print("mounting", float(box.conf), box.xyxy.tolist()) ``` ```python # Live camera / RTSP stream for result in model.predict(source="rtsp://camera/stream", stream=True, conf=0.50): if len(result.boxes): print("Mounting detected") ``` ### Which confidence threshold? For `cowcatcherV17.2` the false-positive count stays at **0** across the entire 0.50β0.99 sweep, so the threshold only trades away recall. F1 peaks at **0.50**; anything up to ~0.80 is still a sensible operating point if you want extra headroom. | Threshold | Found (TP) | Missed (FN) | False alarms | Recall | Precision | F1 | |---|---|---|---|---|---|---| | **0.50** | 896 | 4 | 0 | 99.56% | 100% | **99.78%** | | 0.60 | 892 | 8 | 0 | 99.11% | 100% | 99.55% | | 0.70 | 879 | 21 | 0 | 97.67% | 100% | 98.82% | | 0.80 | 869 | 31 | 0 | 96.56% | 100% | 98.25% | | 0.88 | 822 | 78 | 0 | 91.33% | 100% | 95.47% | | 0.92 | 638 | 262 | 0 | 70.89% | 100% | 82.96% | | 0.95 | 125 | 775 | 0 | 13.89% | 100% | 24.39% | --- ## Training Every model in this repository was trained with the same script ([`train.py`](train.py)) β only the base checkpoint and the epoch count change per version. ```python from ultralytics import YOLO # Load model model = YOLO("yolo26m.pt") # Train with added augmentation model.train( data="dataset.yaml", imgsz=640, batch=16, epochs=50, patience=10, #fraction=0.05, # currently uses 100% of the dataset; 0.8 = 80% of the set save_period=5, workers=0, device=0, #close_mosaic=10, # Augmentation settings augment=True, # General augmentation on/off degrees=10, # Rotation up to 10 degrees translate=0.1, # Translation up to 10% scale=0.5, # Scaling between 0.5 and 1.5 fliplr=0.5, # 50% chance of horizontal flip hsv_h=0.015, # Minor hue variations hsv_s=0.7, # Saturation variations hsv_v=0.4, # Brightness variations mosaic=1.0 # Mosaic augmentation (combines 4 images) ) ``` Per-version settings β everything else in the script stays identical: | Model | Base checkpoint | Epochs | |---|---|---| | `cowcatcherV17.2.pt` | `yolo26m.pt` | 50 | | `cowcatcherV17.pt` | `yolo26m.pt` | 400 | | `cowcatcherV16.pt` | `yolo26m.pt` | 400 | | `cowcatcherV15.pt` | `yolo12m.pt` | 100 | | `cowcatcherV14.pt` | `yolo12m.pt` | 100 | | `cowcatcherV13.pt` | `yolo12m.pt` | 100 | | `cowcatcherV1-seg.pt` | `yolo11m-seg.pt` | 100 | `dataset.yaml` points at the single-class (`mounting`) farm-camera dataset, which is not published here. `patience=10` stops a run early once validation stops improving, so the effective epoch count can be lower than the number listed. Training ran on a single GPU (`device=0`), with `workers=0` for Windows compatibility. --- ## Benchmark **Test set:** 1000 held-out images β 900 real mounting events and 100 null/noise images (cattle, barns and robots without mounting). Six models evaluated on 2026-07-23. Of the 900 mounting events, 11 are found by *no* model at 0.88, and 536 are missed by at least one model. ### Performance at threshold 0.88 | Model | Recall % | Precision % | F1 % | False alarms | Missed | Accuracy % | ms/image | |---|---|---|---|---|---|---|---| | **cowcatcherV17.2** | 91.33 | **100.00** | 95.47 | **0** | 78 | 92.2 | 24.1 | | cowcatcherV16 | **96.33** | 97.64 | **96.98** | 21 | 33 | 94.6 | 24.4 | | cowcatcherV17 | 86.89 | 99.11 | 92.60 | 7 | 118 | 87.5 | 24.3 | | cowcatcherV15 | 74.44 | 97.95 | 84.60 | 14 | 230 | 75.6 | 27.3 | | cowcatcherV14 | 65.00 | 99.66 | 78.68 | 2 | 315 | 68.3 | 27.4 | | cowcatcherV13 | 50.11 | 99.34 | 66.62 | 3 | 449 | 54.8 | 29.0 | Note that 0.88 is a legacy production threshold. It suits V16, but it sits far above the optimum for V17.2 β see the next table. ### Best achievable operating point (max F1) | Model | Best threshold | Found | Missed | False alarms | Recall % | Precision % | F1 % | |---|---|---|---|---|---|---|---| | **cowcatcherV17.2** | 0.50 | 896 | 4 | **0** | 99.56 | **100.00** | **99.78** | | cowcatcherV17 | 0.50 | 897 | 3 | 14 | 99.67 | 98.46 | 99.06 | | cowcatcherV14 | 0.50 | 886 | 14 | 24 | 98.44 | 97.36 | 97.90 | | cowcatcherV16 | 0.80 | 891 | 9 | 33 | 99.00 | 96.43 | 97.70 | | cowcatcherV15 | 0.61 | 894 | 6 | 41 | 99.33 | 95.61 | 97.44 | | cowcatcherV13 | 0.50 | 867 | 33 | 24 | 96.33 | 97.31 | 96.82 | ### Confidence separation The gap between the mean confidence on real mounts and on null images decides how easy the model is to threshold. V17.2 is in a different class here: it is almost silent on noise (mean 0.008) while staying confident on real events (mean 0.918). | Model | Avg conf β real mounts | Avg conf β null noise | Margin | |---|---|---|---| | **cowcatcherV17.2** | 0.9180 | **0.0079** | **0.9101** | | cowcatcherV17 | 0.9026 | 0.1469 | 0.7557 | | cowcatcherV14 | 0.8718 | 0.2215 | 0.6503 | | cowcatcherV13 | 0.8409 | 0.2250 | 0.6159 | | cowcatcherV16 | 0.9316 | 0.4190 | 0.5126 | | cowcatcherV15 | 0.8893 | 0.3875 | 0.5018 | The same effect shows in the safety margin (5th percentile of real mounts minus 95th percentile of nulls). Every other model is negative β its distributions overlap β while V17.2 reaches **+0.827**: | Model | Lowest conf on a real mount | Highest conf on a null | P05 mounts | P95 nulls | Safety margin | |---|---|---|---|---|---| | **cowcatcherV17.2** | 0.1558 | 0.4382 | 0.8450 | 0.0176 | **+0.8274** | | cowcatcherV16 | 0.0051 | 0.9304 | 0.8866 | 0.9130 | β0.0264 | | cowcatcherV17 | 0.4547 | 0.9107 | 0.8251 | 0.8907 | β0.0656 | | cowcatcherV15 | 0.4584 | 0.9060 | 0.8194 | 0.8965 | β0.0772 | | cowcatcherV14 | 0.0004 | 0.8925 | 0.7553 | 0.8407 | β0.0854 | | cowcatcherV13 | 0.0001 | 0.8995 | 0.6154 | 0.8643 | β0.2489 | ### Confidence distribution on null images Number of null images falling in each confidence bin β lower and further left is better. | Bin | V13 | V14 | V15 | V16 | V17 | **V17.2** | |---|---|---|---|---|---|---| | 0.00β0.20 | 68 | 70 | 51 | 47 | 79 | **99** | | 0.20β0.60 | 11 | 6 | 6 | 7 | 9 | **1** | | 0.60β0.86 | 15 | 19 | 28 | 17 | 4 | **0** | | 0.86β0.94 | 6 | 5 | 15 | 29 | 8 | **0** | | 0.94β1.00 | 0 | 0 | 0 | 0 | 0 | **0** | --- ## Choosing a model - **Default choice β `cowcatcherV17.2`.** Best F1, zero false alarms, widest usable threshold window. Pick this unless you have a specific reason not to. - **`cowcatcherV16`** still has the highest raw recall at the legacy 0.88 threshold, but pays for it with 21 false alarms out of 100 nulls and heavily overlapping confidence distributions. ## Limitations - Single class only: the model detects mounting, not cow identity, lameness or other behaviours. - Trained and evaluated on fixed barn cameras. Very different mounting angles, heavy occlusion or unusual camera placements are under-represented. - The 100-image null set is small; a false-positive rate of 0 on it should be read as "no false alarms observed", not as a guarantee. - Benchmark timings (24β29 ms/image) were measured on the evaluation machine and will differ on other hardware. ## License **AGPL-3.0.** These weights are trained with [Ultralytics](https://github.com/ultralytics/ultralytics), which is licensed under AGPL-3.0. Every checkpoint in this repository carries the Ultralytics AGPL-3.0 notice in its metadata, so the derived weights inherit that license. In practice this means that if you use these models in a network-accessible service, AGPL-3.0 requires you to make the corresponding source of that service available to its users. If that does not work for your deployment, Ultralytics sells a commercial Enterprise License that removes the copyleft obligation β see [ultralytics.com/license](https://www.ultralytics.com/license).