A computer-vision project for detecting and classifying German traffic signs (bounding boxes + class labels). This repository provides conversion tools, validators and training scripts to convert the SynsetSignsetGermany raw data into a YOLOv8-compatible dataset, train a YOLOv8 model, and run inference.
- Reproduce
1.1 Detected images - Training pictures & data
- What this repo does (summary)
- Dataset
- Convert & prepare dataset
- Validate dataset
- Train (yolov8m) — example
- Inference example
git clone https://github.com/jantrw/traffic-sign-detector.git
cd traffic-sign-detectorLinux / macOS
python3 -m venv yolov8traffictracking
source yolov8traffictracking/bin/activateWindows (PowerShell)
python -m venv yolov8traffictracking
.\yolov8traffictracking\Scripts\Activate.ps1
# (or for cmd): yolov8traffictracking\Scripts\activate.batpip install --upgrade pip
pip install -r requirements.txtThe model training_results/yolov8m_run_013/weights/best.pt is stored with Git LFS because it exceeds GitHub's 100 MB file size limit. After cloning the repo you must pull LFS objects to get the real .pt file (otherwise you only get a pointer file).
Linux / macOS
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
sudo apt install git-lfs # or use your distro package manager
git lfs installWindows (PowerShell / admin)
choco install git-lfs # Or Download installer from https://git-lfs.github.com/
git lfs installDownload LFS objects (this fetches the real model and not just the pointer)
git lfs pull # fetches LFS objects for the current refsThe repo includes run_detect.py for convenient and reproducible runs.
Example: single-image
python run_detect.py images/steileKurve.jpgExample: with your own Image
python run_detect.py C:/Users/deinUserName/Downloads/image.pngExample: multi-image detection
python run_detect.py images/- No detections: try
--conf 0.01orconf=0.05andimgsz=1024. - Detections but many false positives: raise
confto0.3–0.5, use temporal smoothing in video (require detection in 2 consecutive frames). - Model checkpoint missing or wrong: ensure
training_results/.../best.ptexists and is a detection checkpoint . Useyolo val model=... data=data2.yamlto verify performance on the validation set.
- Convert SynsetSignsetGermany → YOLO format (images +
.txtlabels with normalized bboxes). - Produce
data/yolo_signscontaining:train/images,train/labelsval/images,val/labelsclasses.txt(one class name per line)data.yaml(YOLO/Ultralytics dataset file with relative paths)
- Validate dataset integrity with
scripts/validate_yolo_dataset.py. - Train YOLOv8 (we use
yolov8m.ptby default) usingscripts/train_model/start_train.pywith W&B logging and TensorBoard.
Current dataset:
SynsetSignsetGermany (replaces GTSRB for this project).
Download location (example / internal):
https://owncloud.fraunhofer.de/index.php/s/OLQ6E5BVN4pRGu8?path=%2FSynsetSignsetGermany
Place the extracted SynsetSignsetGermany archive under data/raw/ so the converter scripts can find the expected folders.
Typical extracted structure (important folders):
data/raw/SynsetSignsetGermany/
Ogre/ # images organized in class subfolders (0..210)
Masks/ # masks per-class (0..210) used to compute bboxes
Labels/ # optional semantic labels per-class (0..210)
CsvFiles/ # various csv splits and metadata (optional)
Cycles/ # JSON metadata per-image (optional)
Notes:
- Each Ogre class folder contains the original image files + .json with metadata (e.g.
0_ogre.png,0_ogre.json,1_ogre.png,1_ogre.json…). - Masks and Labels folders are used to extract bounding boxes (masks -> contours -> bbox).
- Many helper scripts expect these folders to exist under
data/raw/SynsetSignsetGermany.
From project root, example conversion command:
python scripts/convert_synset_to_yolo.py `
--raw data/raw/SynsetSignsetGermany `
--masks data/raw/SynsetSignsetGermany/Masks `
--semantic data/raw/SynsetSignsetGermany/Labels `
--out data/yolo_signs `
--split 0.8 0.2 0.0
This will compute bboxes from masks and write images + .txt labels into data/yolo_signs/train|val.
Quick check:
python scripts/validate_yolo_dataset.pyWhat it prints:
- counts for
trainandvalimages/labels, - up to N sample images missing labels, or labels missing images,
- basic YOLO label format issues.
Run:
python scripts/create_data_yaml.py
data/yolo_signs/data.yaml will use relative paths (so the trainer resolves train: train/images, val: val/images when path: .).
Example data.yaml contents:
path: data/yolo_signs train: train/images val: val/images nc: 211 names: 0: "0_Geschwindigkeit20" 1: "100_VerbotReiter" ...
Important: Ultralytics accepts either names list or mapping; classes.txt can be used by many visualization tools to map id->name.
Start training locally (example):
python scripts/train_model/start_train.py
# or with ultralytics directly:
# python -c "from ultralytics import YOLO; YOLO('yolov8m.pt').train(data='data/yolo_signs/data.yaml', epochs=50, imgsz=640, batch=16, name='yolov8m_run')"Notes:
- Adjust
batch/imgszto your GPU memory. - The trainer supports W&B and prints a TensorBoard command if logs are enabled.
- If you see Git LFS pointer files instead of
.pt, rungit lfs installandgit lfs pull.
Below is a minimal snippet that runs inference and draws bounding boxes labeled by class names (labels come from classes.txt):
from ultralytics import YOLO
import cv2, json, pathlib
model = YOLO("runs/train/your_run/weights/best.pt") # or yolov8m.pt (finetune)
res = model("some_test_image.jpg") # returns results
# load class names
names = [l.strip() for l in open("data/yolo_signs/classes.txt", encoding="utf8").read().splitlines()]
# draw (first result)
boxes = res[0].boxes # ultralytics result
img = cv2.imread("some_test_image.jpg")
for box in boxes:
x1,y1,x2,y2 = map(int, box.xyxy[0].tolist())
cls = int(box.cls[0].item())
label = names[cls] if cls < len(names) else str(cls)
cv2.rectangle(img, (x1,y1), (x2,y2), (0,255,0), 2)
cv2.putText(img, label, (x1, max(0,y1-6)), cv2.FONT_HERSHEY_SIMPLEX, 0.45, (255,255,255), 1)
cv2.imwrite("inference_with_labels.jpg", img)This draws borders with the folder/class names (as requested) by mapping class IDs to names using classes.txt.




