Instructions to use lojony/yolo11n-cigarette-butt-detector with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- ultralytics
How to use lojony/yolo11n-cigarette-butt-detector with ultralytics:
from huggingface_hub import hf_hub_download from ultralytics import YOLO # pick the weights file from this repo's "Files and versions" tab weights = hf_hub_download("lojony/yolo11n-cigarette-butt-detector", "<weights>.pt") model = YOLO(weights) source = 'http://images.cocodataset.org/val2017/000000039769.jpg' model.predict(source=source, save=True) - Notebooks
- Google Colab
- Kaggle
YOLO11n cigarette-butt detector
A small object detector that finds cigarette butts on city pavement in high-resolution ground photos. It is part of an open project working towards a robot that collects cigarette litter. The model is YOLO11n (2.6 M parameters), chosen over a larger YOLO11s because its speed makes it the closest to running on a robot.
- Try it in the browser: web demo (runs on your device; uploaded photos stay there)
- Code, training and evaluation notebooks: GitHub
- Data: Cigarette Litter Street Photo Dataset (CC BY 4.0)
What it was trained for
- Images: phone photos of pavement at about robot camera height, 4000Γ1800 px, daylight without rain.
- Objects: cigarette butts, 25β254 px long in those photos (90% between 35 and 170 px). Cigar and cigarillo ends are out of scope.
- How it runs: on 640 px tiles cut from the full photo every 384 px, with boxes merged across tiles. Resizing a whole photo down to 640 px makes butts a few pixels long and the model will miss them; use the tiling below.
Use
from huggingface_hub import hf_hub_download
from PIL import Image
import torch, torchvision
from ultralytics import YOLO
model = YOLO(hf_hub_download('lojony/yolo11n-cigarette-butt-detector', 'yolo11n-cigarette-butts.onnx'))
TILE, STRIDE = 640, 384 # the tiling the model was trained and scored with
def starts(n):
s = list(range(0, n - TILE + 1, STRIDE))
return s + [n - TILE] if s[-1] + TILE < n else s # last tile ends at the border
def detect(path, conf=0.25):
im = Image.open(path).convert('RGB')
boxes, scores = [], []
for y in starts(im.height):
for x in starts(im.width):
r = model.predict(im.crop((x, y, x + TILE, y + TILE)), imgsz=TILE, conf=conf, verbose=False)[0].boxes
boxes += [[a + x, b + y, c + x, d + y] for a, b, c, d in r.xyxy.tolist()]
scores += r.conf.tolist()
if not boxes:
return []
keep = torchvision.ops.nms(torch.tensor(boxes), torch.tensor(scores), 0.3).tolist()
return sorted(((scores[i], *boxes[i]) for i in keep), reverse=True)
for score, x0, y0, x1, y1 in detect('photo.jpg'):
print(f'{score:.2f} ({x0:.0f}, {y0:.0f}) β ({x1:.0f}, {y1:.0f})')
The photo must be at least 640 px on each side. A lower conf finds more butts and raises more false alarms (see
the curve below).
Evaluation
Scored on 19 validation photos (43 butts) that were labelled without any detector suggestions on screen and never used in training, and once on 19 test photos (29 butts), labelled the same way and never used for any choice before. Each photo is scored whole: a butt is found when a detection's centre lies inside its box or the boxes overlap with IoU β₯ 0.3; a false positive is a detection on no labelled box. Bracketed ranges are 95% intervals.
| Recall at threshold 0.25 | 81.4% (35 of 43; 67.4β90.3%) |
| False positives per photo at 0.25 | 0.74 (0.37β1.16) |
| False positives per photo at 72% / 81% / 86% recall | 0.00 / 0.37 / 1.95 |
| Highest recall reached | 88.4% |
| Test photos (19 photos, 29 butts, scored once), threshold 0.25 | recall 75.9% (22 of 29; 57.9β87.8%), 1.37 (0.63β2.21) false positives per photo |
| 5-fold cross-validation, 106 photos, 260 butts, threshold 0.25 | recall 81.9% (76.8β86.1%), 1.01 (0.77β1.22) false positives per photo |
| Time per 4000Γ1800 photo (50 tiles), laptop CPU (i5-1145G7) | 2.1 s |
| Compute per photo | 322 GFLOPs |
For comparison on the same 19 photos: YOLO11s trained the same way finds 83.7% at 0.84 false positives per photo and takes 6.5 s; the zero-shot OWLv2 model reaches 97.7% recall but with 7.3 false positives per photo at its operating point and 119 s per photo. The interactive curve shows all three at every threshold. One butt is about 2 points of recall on the validation photos and about 3.5 on the test photos, so small differences are noise: the test result is lower than the validation result, and their intervals overlap.
Training
- Data: 87 training photos with 217 labelled butts (Valencia, Spain, one phone, one session on 2026-10-01), cut into 640 px tiles every 384 px; a butt counts in a tile when 80% of it is inside.
- Recipe (
06-cv-yolo11n.json): boxes the annotator was unsure of are painted grey, 10% of the training tiles hold no butt, and extra tiles are centred on lookalikes the annotator rejected (leaves, paper, stones). Ultralytics 8.4.184, COCO-pretrained YOLO11n, 100 epochs, default augmentation, final epoch kept. - Reproduce:
pipeline/train.ipynbandpipeline/evaluate.ipynbin the GitHub repository.
Limitations
- One capture session: one phone, one area of one city, daylight without rain. Validation photos come from the same walk as the training photos, held out by time, not location. Performance at new places is unmeasured and probably lower.
- Not a robot camera: the photos come from a phone. A robot's sensor, motion blur and mounting are untested, and no robot or GPU board has run the model.
- Small data: 87 training photos and one training seed; the intervals above are wide.
- Lookalikes: in an error analysis of the YOLO11s model trained the same way, most false positives were local lookalikes (leaves and paper the largest group), and crushed or flattened butts were the most common misses, then blurred and small ones. This model was not analysed separately.
- Labels: one annotator; small, unsaturated butts are probably under-labelled.
Intended use
Research and prototyping of litter detection, especially for robots and for counting litter in field photos, with the limits above stated alongside any result. It is not suited to enforcement or to any decision about a person.
Contributing
The project is open and looking for help. The open questions list what is untested: more varied photos, lookalike-focused training, context at tile edges, larger models, robot hardware. Photos taken with the capture protocol, reports of how the model does on your own photos, and pull requests are all welcome.
Files
yolo11n-cigarette-butts.onnx: the model for ONNX Runtime (no Ultralytics pickle); runs with the example above.yolo11n-cigarette-butts.pt: the same weights in Ultralytics' format (last.ptof the training run).run_config.json: every setting of the training run and of its evaluation, as used. With the.ptfile, the evaluation notebook (RUN_CONFIGandWEIGHTSsettings) reproduces the validation result above.
Licence
Model: AGPL-3.0. Ultralytics states that models trained with its library fall under AGPL-3.0 (Ultralytics licensing): if you build this model into a product, service or device, that project must be open-sourced under AGPL-3.0, or you need an Enterprise licence from Ultralytics. The training code is open source under AGPL-3.0 on GitHub. Training data: CC BY 4.0.
- Downloads last month
- 25