Zaawansowany system do re-identyfikacji osób w nagraniach wideo CCTV łączący:
- YOLOv8 (Ultralytics) - wykrywanie osób
- OSNet (torchreid) - ekstrakcja cech i identyfikacja
┌─────────────────┐
│ Wideo Input │
│ (CCTV) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ YOLOv8 │ ← Detekcja osób (bbox)
│ Detector │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Crop Person │ ← ROI extraction
│ (ROI) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ OSNet │ ← Ekstrakcja cech (512-d)
│ Feature Extract │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Cosine Sim. │ ← Porównanie z galerią
│ Matching │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Assign ID │ ← Istniejące lub nowe ID
└─────────────────┘
- Python 3.8 lub nowszy
- CUDA 11.8+ (opcjonalnie, dla GPU)
- FFmpeg (dla lepszego wsparcia video)
git clone https://github.com/antosiowsky/OSNet-reidentification.git
cd OSNet-reidentification# Zainstaluj PyTorch z CUDA
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118
# Zainstaluj pozostałe zależności
pip install -r requirements.txtpip install -r requirements.txtpython -c "import torch; import torchreid; from ultralytics import YOLO; print('✅ Wszystko OK!')"python main.py --input video.mp4Uruchom przetwarzanie na żywo z kamery podłączonej do systemu:
# Przetwarzanie z domyślnej kamery (index 0)
python main.py --live
# Wybierz kamerę (np. 1) i zapisz wynik
python main.py --live --camera 1 --output live_output.mp4
# Użycie na CPU i bez wyświetlania okna
python main.py --live --device cpu --no-displayNaciśnij ESC w oknie podglądu aby zakończyć przetwarzanie.
python main.py --input video.mp4 --output wynik.mp4python main.py \
--input video.mp4 \
--output wynik.mp4 \
--threshold 0.7 \
--confidence 0.6 \
--skip 2python main.py -i biuro.mp4 -o biuro_reid.mp4 --threshold 0.7 --confidence 0.6python main.py -i sklep.mp4 -o sklep_reid.mp4 --threshold 0.5 --confidence 0.4 --skip 2python main.py -i dworzec.mp4 -o dworzec_reid.mp4 --threshold 0.6 --yolo-model yolov8m.ptpython main.py -i video.mp4 --device cpu --skip 3 --no-display# YOLO wykrywa bounding boxy osób na każdej klatce
detections = yolo(frame)
# Filtrujemy tylko klasę 'person' (ID: 0 w COCO)
persons = [d for d in detections if d.class_id == 0]# Wycinamy każdą wykrytą osobę z klatki
x1, y1, x2, y2 = bbox
person_crop = frame[y1:y2, x1:x2]transform = transforms.Compose([
transforms.Resize((256, 128)), # OSNet wymaga H=256, W=128
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406], # ImageNet statistics
std=[0.229, 0.224, 0.225]
)
])Dlaczego te wartości?
(256, 128)- standardowy input size dla OSNetmean/std- OSNet trenowany na ImageNet, wymaga tej normalizacji- RGB, nie BGR! (OpenCV używa BGR, trzeba konwertować)
# OSNet generuje 512-wymiarowy wektor cech
features = osnet_model(person_crop) # shape: (512,)
# KLUCZOWE: Normalizacja L2
features = features / np.linalg.norm(features)Dlaczego normalizacja?
- Cosine similarity dla znormalizowanych wektorów:
sim = dot(A, B) - Bez normalizacji musielibyśmy:
sim = dot(A, B) / (||A|| * ||B||) - Normalizacja = szybsze obliczenia + stabilność numeryczna
# Porównaj z każdą osobą w galerii
for person in gallery:
similarity = np.dot(embedding, person['embedding'])
if similarity > threshold:
return person['id'] # Znaleziono dopasowanie!
# Brak dopasowania - nowa osoba
new_id = create_new_person()
gallery.append({'id': new_id, 'embedding': embedding})Interpretacja threshold:
0.9+- Prawie identyczne (bardzo restrykcyjne)0.7-0.8- Wysokie podobieństwo (zalecane)0.5-0.6- Umiarkowane (więcej False Positives)<0.5- Niskie (dużo błędnych dopasowań)
| Parametr | Typ | Domyślnie | Opis |
|---|---|---|---|
--input, -i |
str | wymagany | Ścieżka do pliku wideo |
--output, -o |
str | None |
Ścieżka zapisu wyniku |
--yolo-model |
str | yolov8n.pt |
Model YOLO (n/s/m/l/x) |
--osnet-model |
str | osnet_x1_0 |
Model OSNet |
--threshold, -t |
float | 0.6 |
Próg podobieństwa ReID |
--confidence, -c |
float | 0.5 |
Próg pewności YOLO |
--device |
str | cuda |
GPU/CPU |
--skip |
int | 1 |
Co ile klatek |
--no-display |
flag | False |
Bez okna preview |
| Model | Rozmiar | Prędkość | Dokładność | Użycie |
|---|---|---|---|---|
yolov8n.pt |
6 MB | ⚡⚡⚡ | ★★☆ | Szybkie testy |
yolov8s.pt |
22 MB | ⚡⚡ | ★★★ | Zalecany |
yolov8m.pt |
52 MB | ⚡ | ★★★★ | Produkcja |
yolov8l.pt |
87 MB | 🐌 | ★★★★★ | Maksymalna dokładność |
| Model | Parametry | Prędkość | Dokładność |
|---|---|---|---|
osnet_x0_25 |
0.2M | ⚡⚡⚡ | ★★☆ |
osnet_x0_5 |
0.9M | ⚡⚡ | ★★★ |
osnet_x0_75 |
1.5M | ⚡⚡ | ★★★★ |
osnet_x1_0 |
2.2M | ⚡ | ★★★★★ |
- Procesor: Intel Core i5 / AMD Ryzen 5
- RAM: 8 GB
- Dysk: 5 GB wolnego miejsca
- Prędkość: ~2-5 FPS (1080p video)
- GPU: NVIDIA GTX 1060 6GB lub lepszy
- RAM: 16 GB
- VRAM: 6 GB+
- Prędkość: ~15-30 FPS (1080p video)
- GPU: NVIDIA RTX 3060/4060 lub lepszy
- RAM: 32 GB
- VRAM: 8 GB+
- Prędkość: ~30-60 FPS (1080p video)
OSNet-reidentification/
├── main.py # Główny skrypt aplikacji
├── reid_engine.py # Silnik ReID (OSNet + matching)
├── requirements.txt # Zależności
├── README.md # Dokumentacja
└── examples/ # Przykładowe nagrania (opcjonalnie)
Rozwiązanie:
# Użyj mniejszego modelu YOLO
python main.py -i video.mp4 --yolo-model yolov8n.pt
# Lub pomiń klatki
python main.py -i video.mp4 --skip 3
# Lub użyj CPU
python main.py -i video.mp4 --device cpuRozwiązanie:
# Zwiększ threshold
python main.py -i video.mp4 --threshold 0.75Rozwiązanie:
# Zmniejsz threshold
python main.py -i video.mp4 --threshold 0.5
# Zwiększ confidence YOLO (lepsze detekcje)
python main.py -i video.mp4 --confidence 0.6Rozwiązanie:
# Pomiń co drugą klatkę
python main.py -i video.mp4 --skip 2
# Użyj mniejszego modelu
python main.py -i video.mp4 --yolo-model yolov8n.pt --osnet-model osnet_x0_5- YOLOv8: Ultralytics Documentation
- OSNet: Paper - Zhou et al. 2019
- torchreid: GitHub Repository
MIT License - zobacz plik LICENSE
Senior Computer Vision Engineer
Projekt stworzony: 2025-12-02
Pull requests mile widziane! Dla większych zmian, najpierw otwórz issue.
Jeśli projekt Ci pomógł, zostaw gwiazdkę! ⭐