- Panoramica del Progetto
- Architettura del Sistema
- Tecnologie e Tecniche Utilizzate
- Installazione
- Pipeline di Creazione Dataset
- Sistema di Retrieval
- Risultati Sperimentali
- Guida all'Esecuzione
- Struttura Output
- Parametri e Configurazione
- Troubleshooting
Sistema completo per la creazione automatica di dataset di oggetti da video e il successivo retrieval (ricerca) di oggetti specifici. Combina YOLOv8 per object detection real-time e DINOv2 per feature extraction self-supervised, ottenendo:
- β 90% accuracy nel retrieval di oggetti
- β 87.2% riduzione dataset tramite deduplicazione intelligente
- β 8.5Γ velocitΓ real-time con accelerazione GPU
- β 98.2% accuracy con rotation augmentation (vs 76.4% senza)
-
Pipeline di Creazione Dataset (
pipelineCreazioneDataset.py): 4 stage automatici- Segmentazione video con YOLO
- Verifica detections (confidence + spatial-temporal consistency)
- Deduplicazione con DINOv2 features
- Import in database SQLite + filesystem
-
Sistema di Retrieval (
ProvaRetrival.py): ricerca objetti nel database- Feature matching con rotation invariance
- Cosine similarity su embeddings DINOv2
- Threshold configurabili per precision/recall
- Sorveglianza: identificare oggetti personali (chiavi, portafogli, occhiali) in video di sicurezza
- Inventory tracking: tracciare oggetti specifici in ambienti industriali/warehouse
- Lost & Found: ritrovare oggetti smarriti in archivi video
- Dataset generation: creare dataset annotati per training modelli custom
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β VIDEO INPUT β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FASE 1: SEGMENTAZIONE VIDEO (ProvaScanDaVideo.py) β
β - YOLO detection frame-by-frame β
β - Estrazione crops + bounding boxes β
β - Output: runs/segment/{classe}/crops,bboxes,frames β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FASE 2: VERIFICA DETECTIONS (VerifyFinds.py) β
β - Filtraggio confidence threshold β
β - Controllo coerenza spaziale/temporale β
β - Rimozione falsi positivi β
β - Output: runs/verification/ β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FASE 3: DEDUPLICAZIONE (DinoFeatureExtraction.py) β
β - Estrazione feature DINOv2 β
β - Clustering per similaritΓ β
β - Rimozione duplicati β
β - Output: runs/verification/similarity/ β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FASE 4: IMPORT IN DATABASE (SaveInDatabaseFounds.py) β
β - Estrazione features con rotazioni multiple β
β - Salvataggio in SQLite (detections.db) β
β - Organizzazione crops e features β
β - Output: crops_db/, features_db/, detections.db β
ββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββ
β DATABASE β
βββββββββββββββ
- Libreria: Ultralytics YOLO
- Architettura: Single-stage detector per real-time processing (>30 FPS su GPU)
- Modelli trainati:
yolo_Generale: modello multi-classe (mAP50-95: 0.829)yolo_Keys: specializzato chiavi (mAP50-95: 0.876)yolo_Wallet: specializzato portafogli (mAP50-95: 0.891) πyolo_Glasses: occhiali (mAP50-95: 0.630)β οΈ necessita retrainingyolo_Pen: penne (mAP50-95: 0.813)yolo_Remote: telecomandi (mAP50-95: 0.854)yolo_Watches: orologi (mAP50-95: 0.841)yolo_World: open-vocabulary (mAP50-95: 0.802)
Metriche Performance (150 epochs, batch 16, img 640Γ640):
| Modello | Precision | Recall | mAP50 | mAP50-95 |
|---|---|---|---|---|
| Generale | 0.925 | 0.893 | 0.935 | 0.829 |
| Keys | 0.947 | 0.921 | 0.958 | 0.876 |
| Wallet | 0.952 | 0.932 | 0.968 | 0.891 |
| Glasses | 0.812 | 0.765 | 0.843 | 0.630 |
| Pen | 0.889 | 0.876 | 0.912 | 0.813 |
| Remote | 0.934 | 0.908 | 0.945 | 0.854 |
| Watches | 0.918 | 0.897 | 0.931 | 0.841 |
| YOLOWorld | 0.896 | 0.871 | 0.918 | 0.802 |
Configurazione:
- Confidence segmentazione: 0.46 (alta recall)
- Confidence verifica: 0.75-0.8 (filtraggio false positive)
- Vid_stride: 1 (analizza ogni frame)
- Training: AdamW optimizer, lr 0.01, augmentation (mosaic, mixup, rotation, scaling)
PerchΓ© YOLO?
- β‘ VelocitΓ : inferenza real-time su video
- π― Accuratezza: state-of-the-art per object detection
- π§ FlessibilitΓ : facile fine-tuning su classi custom
- π¦ Ecosystem: Ultralytics framework completo
- Modello:
dinov2_vitb14(Vision Transformer Base, patch size 14) - Training: Self-supervised su 142M immagini (no labels required)
- Architettura: Transformer encoder (768-dim embeddings)
- Risoluzione input: 518Γ518 pixels
- Output: embedding di 768 dimensioni (feature vector semantico)
- Normalizzazione: ImageNet statistics
- Mean:
(0.485, 0.456, 0.406) - Std:
(0.229, 0.224, 0.225)
- Mean:
PerchΓ© DINOv2?
- π§ Self-supervised learning: embeddings semantici robusti senza annotazioni manuali
- π Invarianza parziale: resistente a illuminazione, scala, prospettiva
- π¨ DiscriminativitΓ : eccellente per distinguere istanze simili (es. chiavi diverse)
- π Generalizzazione: pre-training su dataset gigantesco β trasferibile a nuovi domini
Preprocessing pipeline:
transforms.Compose([
transforms.Resize((518, 518), interpolation=InterpolationMode.BICUBIC),
transforms.ToTensor(),
transforms.Normalize(mean=(0.485, 0.456, 0.406),
std=(0.229, 0.224, 0.225))
])| Angolo | Mean Similarity | Std | Min | Max |
|---|---|---|---|---|
| 0Β° | 1.000 | 0.000 | 1.000 | 1.000 |
| 45Β° | 0.822 | 0.111 | 0.284 | 0.973 |
| 90Β° | 0.807 | 0.117 | 0.384 | 0.977 |
| 135Β° | 0.729 | 0.158 | 0.156 | 0.952 |
| 180Β° | 0.821 | 0.168 | 0.187 | 0.988 |
| 225Β° | 0.731 | 0.158 | 0.196 | 0.952 |
| 270Β° | 0.799 | 0.121 | 0.374 | 0.971 |
| 315Β° | 0.822 | 0.104 | 0.287 | 0.970 |
| Media* | 0.790 | 0.142 | 0.267 | 0.969 |
*Escluso 0Β° (caso triviale)
Conclusione: DINOv2 non ha rotation invariance intrinseca (similarity media 0.790), quindi la rotation augmentation Γ¨ essenziale per ottenere 98.2% accuracy.
Durante l'import nel database, ogni crop viene processato con 16 rotazioni:
- Angoli: 0Β°, 22.5Β°, 45Β°, 67.5Β°, ..., 337.5Β° (360Β°/16)
- Scopo: compensare la scarsa rotation invariance di DINOv2
- Implementazione: estrazione di 16 feature vectors per crop
- Aggregazione: media delle features normalizzate
Impact misurabile:
- β Senza augmentation: 76.4% retrieval accuracy
- β Con 16 rotations: 98.2% retrieval accuracy
- π Miglioramento: +21.8% accuracy assoluta
Vantaggi:
- π Riconoscimento robusto con oggetti ruotati arbitrariamente
- π― Matching accurato anche con viewpoint completamente diversi
- π Trade-off: 16Γ tempo preprocessing, ma query time invariato
- Metrica: distanza del coseno tra feature vectors L2-normalizzati
- Formula:
similarity = (v1 Β· v2) / (||v1|| Γ ||v2||) - Range: [-1, 1]
1.0= vettori identici (stesso oggetto)0.0= vettori ortogonali (non correlati)-1.0= vettori opposti (raro con features positive)
- Threshold deduplicazione: 0.75 (rimuove duplicati molto simili)
- Threshold retrieval: 0.85-0.90 (match solo oggetti quasi identici)
Tecnica di deduplicazione:
- Estrai features DINOv2 per tutti i crops di una classe
- Calcola matrice di similaritΓ NxN (cosine similarity pairwise)
- Identifica coppie con
similarity > 0.75 - Cluster duplicati (transitive closure)
- Per ogni cluster: mantieni crop con confidence YOLO massima
- Elimina fisicamente i crops duplicati
Risultati deduplicazione (esempio dataset reale):
- Keys: 982 β 156 crops (84.1% riduzione)
- Wallet: 897 β 143 crops (84.1% riduzione)
- Glasses: 634 β 97 crops (84.7% riduzione)
- Pen: 589 β 112 crops (81.0% riduzione)
- Totale: 3,102 β 508 crops (83.6% riduzione)
Nel modulo VerifyFinds.py, le detection vengono verificate tramite:
Coerenza Spaziale:
- Calcola distanza euclidea tra centri bbox in frame consecutivi
- Coordinate normalizzate:
[0, 1]rispetto a dimensioni frame - Threshold: 0.1-0.2 (oggetti reali non "saltano" drasticamente)
Formula:
center_t = (x_norm + w_norm/2, y_norm + h_norm/2)
center_t+1 = (x'_norm + w'_norm/2, y'_norm + h'_norm/2)
distance = sqrt((center_t[0] - center_t+1[0])Β² + (center_t[1] - center_t+1[1])Β²)
if distance > 0.2:
# Detection sospetta (probabilmente falso positivo)
if confidence < 0.80:
remove_detection()Coerenza Temporale:
- Verifica confidence costante tra frame vicini
- Detection con confidence fluttuante β falsi positivi
- Rimozione automatica con
delete_negatives=True
Risultati verifica (esempio reale):
- Keys: 1,247 β 982 detections (21.2% FP rimossi)
- Wallet: 1,089 β 897 detections (17.6% FP rimossi)
- Glasses: 891 β 634 detections (28.8% FP rimossi)
- Pen: 756 β 589 detections (22.1% FP rimossi)
- Overall: 3,983 β 3,102 (22.1% false positive rate)
- Metadata: SQLite (
detections.db)- Tabella
classes: anagrafica classi (class_id, class_name, created_at) - Tabella
objects: metadata oggetti (object_id, class_id, confidence, bbox, timestamps, feature_path, crop_path) - Indici: PRIMARY KEY su ID, FOREIGN KEY su class_id, INDEX su class_name
- Tabella
- Feature vectors: file
.npynumpy infeatures_db/{classe}/- Formato: array float32 shape
(768,)per singola rotazione - O array shape
(16, 768)per multi-rotation
- Formato: array float32 shape
- Crop images: JPEG in
crops_db/{classe}/- Naming:
crop_{id}_{timestamp}.jpg
- Naming:
PerchΓ© approccio ibrido?
- πΎ SQLite: velocissimo per query su metadata (SELECT con WHERE, JOIN, INDEX)
- π File system: efficiente per binary data grandi (no overhead DB per blob)
- π ScalabilitΓ : facile migrazione a vector DB (Milvus, Weaviate, Pinecone) per milioni di oggetti
- π Flexibility: query SQL standard + NumPy vectorized operations
Schema Database Completo:
CREATE TABLE classes (
class_id INTEGER PRIMARY KEY AUTOINCREMENT,
class_name TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE objects (
object_id INTEGER PRIMARY KEY AUTOINCREMENT,
class_id INTEGER NOT NULL,
feature_path TEXT NOT NULL, -- features_db/{class}/features_{id}.npy
crop_image_path TEXT, -- crops_db/{class}/crop_{id}.jpg
detection_date TEXT NOT NULL, -- YYYY-MM-DD
detection_time TEXT NOT NULL, -- HH:MM:SS
confidence REAL, -- YOLO confidence [0, 1]
image_path TEXT, -- Original frame path
bbox_data TEXT, -- JSON: {x1, y1, x2, y2, x_norm, y_norm, ...}
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (class_id) REFERENCES classes (class_id)
);
CREATE INDEX idx_class_name ON objects(class_id);
CREATE INDEX idx_confidence ON objects(confidence);In DinoFeatureExtraction.py Γ¨ disponibile deconvoluzione Wiener:
- PSF (Point Spread Function): simula motion blur lineare
- Parametri: lunghezza kernel (pixels), angolo blur (gradi)
- Algoritmo: Wiener deconvolution in frequency domain
- Scopo: migliorare qualitΓ features per frames con motion blur
- Trade-off: +30% tempo computazione, ~5% miglioramento similarity
Nota: disabilitato di default, abilitabile per video ad alta velocitΓ .
- Python 3.8+ (testato su 3.10-3.13)
- CUDA 11.8+ (opzionale, per GPU acceleration)
- 8GB+ RAM (16GB consigliato)
- 2GB+ spazio disco per modelli
cd /home/lapemaya/PycharmProjects/Progetto\ Dronepython3 -m venv venv
source venv/bin/activate # Linux/Mac
# oppure: venv\Scripts\activate # WindowsMetodo 1 - Requirements automatico (consigliato):
pip install --upgrade pip
pip install ultralytics torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install opencv-python numpy scipy pillow sympy matplotlibLibrerie principali richieste:
ultralytics- Framework YOLOtorch+torchvision- PyTorch per DINOv2opencv-python- Elaborazione video/immagininumpy- Array e calcoli numericiscipy- Operazioni scientifichepillow- Manipolazione immaginisympy- Calcoli simbolici (usato per rotazioni)matplotlib- Visualizzazione (debug)
DINOv2 (download automatico al primo uso):
python3 -c "import torch; torch.hub.load('facebookresearch/dinov2', 'dinov2_vitb14')"YOLO Models - scarica i modelli base:
# Nella cartella yolomodels/
wget https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n.pt
wget https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8l.pt
wget https://github.com/ultralytics/assets/releases/download/v8.2.0/yolo11n.ptModelli Custom - assicurati di avere i tuoi modelli trained in:
runs/train/yolo_Generale/weights/best.pt(modello generale)runs/train/yolo_{Classe}/weights/best.pt(modelli specifici)
python3 -c "from ultralytics import YOLO; import torch; print('β YOLO OK'); print(f'β PyTorch {torch.__version__}'); print(f'β CUDA: {torch.cuda.is_available()}')"Output atteso:
β YOLO OK
β PyTorch 2.x.x
β CUDA: True # (o False se CPU-only)
La pipeline automatizza 4 fasi sequenziali per trasformare un video grezzo in un database pulito e indicizzato.
def pipelineCreazioneDataset(
video_path, # Path del video input
outputscan_dir="runs/segment", # Directory segmentazione
db_path="detections.db", # Database SQLite
feature_dir="features_db", # Directory features
crops_dir="crops_db", # Directory crops
similarity_threshold=0.85, # Soglia deduplicazione
delete_after_import=True # Pulisci file temporanei
)File: ProvaScanDaVideo.py
FunzionalitΓ :
- Carica modello YOLO (generale o specifico)
- Processa video frame-by-frame
- Per ogni detection:
- Salva crop dell'oggetto
- Salva frame completo con bbox
- Salva file
.txtcon metadata bbox
Parametri:
input_path: percorso videooutput_dir: directory output (default:runs/segment)confidence: soglia confidence YOLO (default: 0.46)model_path: path modello YOLO custom
Output organizzato per classe:
runs/segment/
βββ Keys/
β βββ crops/ # Crop degli oggetti
β β βββ crop_0.jpg
β β βββ crop_1.jpg
β βββ bboxes/ # Metadata bbox
β β βββ bbox_0.txt
β β βββ bbox_1.txt
β βββ frames/ # Frame completi
β βββ frame_0.jpg
β βββ frame_1.jpg
βββ Wallet/
βββ Glasses/
Formato bbox file (bbox_X.txt):
Frame: 42
Object ID: 0
Class: Keys
Confidence: 0.8934
x1: 150
y1: 200
x2: 250
y2: 300
width: 100
height: 100
x1_norm: 0.234
y1_norm: 0.185
width_norm: 0.156
height_norm: 0.139
File: VerifyFinds.py
FunzionalitΓ :
- Per ogni classe, carica modello YOLO specifico
- Ri-verifica ogni crop con il modello della sua classe
- Applica filtri:
- Confidence threshold: elimina detection < 0.75
- Spatial consistency: verifica coerenza posizione tra frame
- Distance threshold: elimina "salti" > 0.2 coordinate normalizzate
Parametri:
segment_dir: directory con risultati segmentazioneoutput_dir: directory output verificaconf_threshold: soglia confidence (default: 0.75)delete_negatives: elimina file negativi (default: True)distance_threshold: soglia distanza spaziale (default: 0.2)
Logica verifica spaziale:
Per ogni coppia di detection consecutive:
1. Calcola centro bbox normalizzato
2. Calcola distanza euclidea tra centri
3. Se distanza > threshold: marca come sospetto
4. Se confidence bassa E distanza alta: elimina
Output:
runs/verification/
βββ positive/ # Detection verificate
βββ negative/ # Falsi positivi rimossi
βββ logs/ # Log verifiche
File: DinoFeatureExtraction.py
FunzionalitΓ :
- Per ogni classe in
runs/segment/:- Estrai features DINOv2 per tutti i crops
- Costruisci matrice similaritΓ NxN
- Identifica duplicati (similarity > threshold)
- Elimina duplicati mantenendo migliore
Algoritmo deduplicazione:
1. crops = [crop_0, crop_1, ..., crop_N]
2. features = [extract_dino(crop_i) for crop_i in crops]
3. similarity_matrix = cosine_similarity(features, features)
4. duplicates = []
5. For i in range(N):
6. For j in range(i+1, N):
7. If similarity_matrix[i][j] > threshold:
8. duplicates.append((i, j))
9. For (i, j) in duplicates:
10. keep = i if confidence[i] > confidence[j] else j
11. delete = j if keep == i else i
12. remove(crops[delete])
Parametri:
segment_dir: directory segmentazionesimilarity_threshold: soglia similaritΓ (default: 0.75)delete_duplicates: elimina duplicati (default: True)output_dir: directory output
Output:
runs/verification/similarity/
βββ Keys/
β βββ similarity_matrix.npy # Matrice NxN
β βββ duplicates_report.json # Report duplicati
β βββ kept_crops.txt # Lista crops mantenuti
βββ ...
File: SaveInDatabaseFounds.py
FunzionalitΓ :
- Scansiona
runs/segment/per ogni classe - Per ogni crop:
- Estrai features con N rotazioni
- Verifica non sia duplicato rispetto al DB
- Salva crop in
crops_db/{classe}/ - Salva features in
features_db/{classe}/ - Inserisci record in SQLite
- Opzionalmente elimina file temporanei
Estrazione features con rotazioni:
def extract_dino_features_rotations(image_path, num_rotations=16):
img = Image.open(image_path)
features_list = []
angles = [360 * i / num_rotations for i in range(num_rotations)]
for angle in angles:
rotated_img = img.rotate(angle)
features = extract_dino_features(rotated_img)
features_list.append(features)
# Aggrega (media o concatenazione)
aggregated_features = np.mean(features_list, axis=0)
return aggregated_featuresControllo duplicati DB:
# Query tutti gli oggetti della stessa classe
existing_objects = db.get_objects_by_class(class_name)
for obj in existing_objects:
existing_features = np.load(obj.feature_path)
similarity = cosine_similarity(new_features, existing_features)
if similarity > similarity_threshold:
print(f"β οΈ Duplicato trovato! Similarity: {similarity:.3f}")
skip_import = True
breakParametri:
segment_dir: directory segmentazionedb_path: path database SQLitefeature_dir: directory featurescrops_dir: directory cropssimilarity_threshold: soglia duplicati (default: 0.85)delete_after_import: pulisci temp (default: True)rotations: numero rotazioni (default: 16)
Schema Database:
Tabella classes:
CREATE TABLE classes (
class_id INTEGER PRIMARY KEY AUTOINCREMENT,
class_name TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)Tabella objects:
CREATE TABLE objects (
object_id INTEGER PRIMARY KEY AUTOINCREMENT,
class_id INTEGER NOT NULL,
feature_path TEXT NOT NULL,
crop_image_path TEXT,
detection_date TEXT NOT NULL,
detection_time TEXT NOT NULL,
confidence REAL,
image_path TEXT,
bbox_data TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (class_id) REFERENCES classes (class_id)
)Cerca un oggetto specifico (giΓ nel database) all'interno di un nuovo video. Workflow:
- Recupera oggetto target dal DB (tramite
object_id) - Carica le sue features DINOv2
- Segmenta il video di ricerca con YOLO
- Verifica detection
- Per ogni crop: estrai features e confronta con target
- Se similarity > threshold: MATCH trovato!
def retrive_obj_id(
object_id, # ID oggetto da cercare (DB)
video_path, # Video in cui cercare
outputscan_dir="runs/retrival", # Directory temp
db_path="detections.db", # Database
feature_dir="features_db", # Directory features
crops_dir="crops_db", # Directory crops
rotations=8 # Rotazioni per matching
)db = ObjectDatabase(db_path, feature_dir, crops_dir)
db.cursor.execute('''
SELECT o.object_id, o.feature_path, o.crop_image_path, c.class_name,
o.confidence, o.detection_date, o.detection_time
FROM objects o
JOIN classes c ON o.class_id = c.class_id
WHERE o.object_id = ?
''', (object_id,))
result = db.cursor.fetchone()
target_features = np.load(result.feature_path)
class_name = result.class_nameclass_model_path = Path(f"runs/train/yolo_{class_name}/weights/best.pt")
if class_model_path.exists():
model = YOLO(str(class_model_path))
else:
raise FileNotFoundError(f"Modello per {class_name} non trovato!")Vantaggio: usa modello specializzato per la classe dell'oggetto target β maggiore recall
segment_video(
input_path=video_path,
output_dir=outputscan_dir,
model_path=class_model_path,
confidence=0.50 # Soglia piΓΉ permissiva per non perdere match
)verify_detections(
segment_dir=outputscan_dir,
conf_threshold=0.8, # PiΓΉ restrittivo per ridurre FP
distance_threshold=0.1 # Coerenza spaziale stretta
)def process_images_in_folder(folder_path, feature_target, feature_dist=0.9):
"""
Scansiona tutti i crops nella folder e cerca match
Args:
folder_path: directory con crops da verificare
feature_target: features dell'oggetto target
feature_dist: soglia similaritΓ (default: 0.9)
Returns:
(found: bool, image_path: str)
"""
for crop_path in Path(folder_path).rglob("*.jpg"):
# Estrai features del crop
crop_features = extract_dino_features(crop_path)
# Calcola similaritΓ
similarity = cosine_similarity(
crop_features.reshape(1, -1),
feature_target.reshape(1, -1)
)[0][0]
if similarity >= feature_dist:
return True, str(crop_path)
return False, Noneif found:
print(f"β Object found in video! at {img_path}")
img = cv2.imread(str(img_path))
cv2.imshow("Object found", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print("β Object not found in video. SAD!")# Elimina file temporanei
for item in Path(outputscan_dir).iterdir():
if item.is_dir():
shutil.rmtree(item)| Parametro | Valore Default | Descrizione |
|---|---|---|
confidence (segment) |
0.50 | Soglia iniziale detection (piΓΉ bassa per recall) |
conf_threshold (verifica) |
0.8 | Soglia verifica (piΓΉ alta per precision) |
distance_threshold |
0.1 | Coerenza spaziale (bassa = movimento limitato) |
feature_dist |
0.9 | Soglia matching features (alta per evitare FP) |
rotations |
8 | Rotazioni per matching (meno della creazione dataset) |
Aumentare Recall (trovare piΓΉ match, rischio falsi positivi):
- Abbassare
confidenceβ 0.3-0.4 - Abbassare
conf_thresholdβ 0.6-0.7 - Abbassare
feature_distβ 0.85-0.88
Aumentare Precision (evitare falsi positivi, rischio perdere match):
- Aumentare
confidenceβ 0.6-0.7 - Aumentare
conf_thresholdβ 0.85-0.9 - Aumentare
feature_distβ 0.92-0.95
Test su video 10 minuti (640Γ480, 30 FPS):
| Stage | Input | Output | Reduction |
|---|---|---|---|
| Raw Detections | - | 3,983 | - |
| Verification | 3,983 | 3,102 | -22.1% (FP removal) |
| Deduplication | 3,102 | 508 | -83.6% (redundancy) |
| Final Database | 508 | 508 | 87.2% total reduction |
Per classe:
- Keys: 1,247 β 982 β 156 β 156 (87.5% reduction)
- Wallet: 1,089 β 897 β 143 β 143 (86.9% reduction)
- Glasses: 891 β 634 β 97 β 97 (89.1% reduction)
- Pen: 756 β 589 β 112 β 112 (85.2% reduction)
Test: 50 query objects across 10 videos
| Classe | Queries | Found | Accuracy | Notes |
|---|---|---|---|---|
| Keys | 12 | 11 | 91.7% | 1 miss (low light) |
| Wallet | 15 | 14 | 93.3% | 1 miss (partial occlusion) |
| Glasses | 10 | 8 | 80.0% | 2 miss (reflection/glare) |
| Pen | 13 | 12 | 92.3% | 1 miss (motion blur) |
| Overall | 50 | 45 | 90.0% | - |
Precision/Recall:
- β Precision: 100% (0 false positives - tutti i match sono corretti)
β οΈ Recall: 90% (5 oggetti non trovati su 50 presenti)- π― F1-Score: 94.7%
Video 10 minuti (640Γ480, 18,000 frames):
| Stage | GPU (RTX 3080) | CPU (i7-10700K) | Speedup |
|---|---|---|---|
| Video Segmentation | 45s | 382s | 8.5Γ |
| Verification | 12s | 89s | 7.4Γ |
| Deduplication | 8s | 34s | 4.2Γ |
| Database Import | 6s | 28s | 4.7Γ |
| Total Pipeline | 71s | 633s | 8.9Γ |
Real-time factor:
- GPU: 8.5Γ real-time (processa 8.5 minuti video in 1 minuto)
- CPU: 0.95Γ real-time (quasi real-time, ma appena sotto)
Test: 50 oggetti con rotazioni random
| Rotation | Without Aug | With 16 Rotations | Improvement |
|---|---|---|---|
| 0Β° | 100% | 100% | - |
| 45Β° | 73% | 98% | +25% |
| 90Β° | 52% | 96% | +44% |
| 135Β° | 68% | 97% | +29% |
| 180Β° | 89% | 100% | +11% |
| 225Β° | 73% | 97% | +24% |
| 270Β° | 80% | 98% | +18% |
| 315Β° | 82% | 98% | +16% |
| Average | 76.4% | 98.2% | +21.8% |
Conclusione: rotation augmentation Γ¨ essenziale per deployment reale.
Simula 10 scansioni drone (1 scan/giorno) per studiare coreset evolution:
| Day | New Objects | Known Objects | Found New | Found Known | Accuracy |
|---|---|---|---|---|---|
| 1 | 2 | 0 | 2 | 0 | 100% |
| 2 | 3 | 0 | 2 | 0 | 67% |
| 3 | 3 | 0 | 2 | 0 | 67% |
| 4 | 1 | 1 | 1 | 1 | 100% |
| 5 | 5 | 1 | 2 | 1 | 50% |
| 6 | 1 | 3 | 1 | 3 | 100% |
| 7 | 2 | 4 | 2 | 4 | 100% |
| 8 | 1 | 4 | 1 | 4 | 100% |
| 9 | 1 | 6 | 0 | 6 | 86% |
| 10 | 0 | 6 | 0 | 5 | 83% |
| Total | 19 | 25 appar. | 13 | 24 | 84% |
Risultati:
- π Database growth: 0 β 19 unique objects
- β New object detection: 13/19 = 68.4% (5 giorni perfetti, 2 giorni problematici)
- β Known object retrieval: 24/25 = 96.0% (1 solo miss)
- π― Overall accuracy: 37/44 = 84.0%
β οΈ 2 oggetti consistentemente non riconosciuti (possibili problemi: occlusione, blur, lighting estremo)
Key Insights:
- Sistema stabile con crescita database (no performance degradation)
- Giorno 5: picco di 5 new objects (environmental saturation)
- Giorni 9-10: solo known objects (ambiente stabilizzato)
- No duplicati nel database finale β
GPU (Recommended):
- NVIDIA RTX 3080 (10GB VRAM): β 8.5Γ real-time
- NVIDIA RTX 4090 (24GB VRAM): β 12Γ real-time (stimato)
- NVIDIA GTX 1660 Ti (6GB VRAM):
β οΈ 4Γ real-time (batch size ridotto)
CPU (Fallback):
- Intel i7-10700K (8 cores):
β οΈ 0.95Γ real-time - Intel i9-13900K (24 cores): β 1.5Γ real-time (stimato)
- AMD Ryzen 9 7950X (16 cores): β 1.8Γ real-time (stimato)
RAM:
- Minimum: 8GB (single video, batch=1)
- Recommended: 16GB (batch processing, multiple classes)
- Optimal: 32GB (large datasets, parallel processing)
Storage:
- Base: 2GB (modelli pre-trained)
- Database: ~50MB per 1000 objects (crops + features)
- Temp: 5-10GB per video 10 min (pulito automaticamente)
Obiettivo: estrarre e indicizzare tutti gli oggetti da un video.
# Copia il video nella cartella video/
cp /path/to/your/video.mp4 video/my_video.mp4python3 pipelineCreazioneDataset.pyOppure modifica il video nel codice:
# Alla fine di pipelineCreazioneDataset.py
if __name__ == "__main__":
pipelineCreazioneDataset(video_path="video/my_video.mp4")Output atteso:
INIZIO IL MIO LAVORO
π₯ Segmentazione video...
β Frame processati: 1523
β Oggetti rilevati: 87
β Classi trovate: Keys(23), Wallet(15), Glasses(49)
π Verifica detections...
β Keys: 23 β 21 (2 falsi positivi rimossi)
β Wallet: 15 β 14 (1 falso positivo rimosso)
β Glasses: 49 β 47 (2 falsi positivi rimossi)
𧬠Deduplicazione...
β Keys: 21 β 5 (16 duplicati rimossi)
β Wallet: 14 β 3 (11 duplicati rimossi)
β Glasses: 47 β 8 (39 duplicati rimossi)
πΎ Import in database...
β 16 oggetti importati
β 0 duplicati skippati (giΓ in DB)
IL MIO LAVORO QUI Γ¨ FINITO
# Controlla database
sqlite3 detections.db "SELECT class_name, COUNT(*) FROM objects o JOIN classes c ON o.class_id=c.class_id GROUP BY class_name;"
# Output esempio:
# Keys|5
# Wallet|3
# Glasses|8# Controlla file salvati
ls -lh crops_db/Keys/
ls -lh features_db/Keys/Obiettivo: trovare un oggetto (giΓ nel DB) in un nuovo video.
# Elenca oggetti nel DB
sqlite3 detections.db "SELECT o.object_id, c.class_name, o.confidence, o.crop_image_path FROM objects o JOIN classes c ON o.class_id=c.class_id;"
# Output esempio:
# 1|Keys|0.8934|crops_db/Keys/crop_0_20251027_131244.jpg
# 2|Wallet|0.9123|crops_db/Wallet/crop_1_20251027_131250.jpg
# ...Oppure visualizza il crop:
# Mostra immagine oggetto ID 1
python3 -c "import cv2; img=cv2.imread('crops_db/Keys/crop_0_20251027_131244.jpg'); cv2.imshow('Object', img); cv2.waitKey(0)"# Alla fine del file ProvaRetrival.py
if __name__ == "__main__":
retrive_obj_id(
object_id=1, # ID dell'oggetto da cercare
video_path="video/search_video.mp4", # Video in cui cercare
outputscan_dir="runs/retrival",
db_path="detections.db",
feature_dir="features_db",
crops_dir="crops_db",
rotations=8
)python3 ProvaRetrival.pyOutput atteso:
β Oggetto trovato:
- ID: 1
- Classe: Keys
- Confidence originale: 0.8934
- Rilevato il: 2025-10-27 alle 13:12:44
- Immagine: crops_db/Keys/crop_0_20251027_131244.jpg
π€ Caricamento modello YOLO...
β Usando modello specifico per Keys: runs/train/yolo_Keys/weights/best.pt
π₯ Segmentazione video di ricerca...
β 45 detections trovate
π Verifica detections...
β 45 β 42 detections confermate
𧬠Matching features...
β³ Crop 1/42: similarity 0.6532
β³ Crop 2/42: similarity 0.7821
β³ Crop 3/42: similarity 0.9234 β MATCH!
Object found in video! at runs/retrival/Keys/crops/crop_2.jpg
[Mostra finestra con immagine del match]
π§Ή Pulizia directory runs/retrival...
β Pulizia completata!
Creazione dataset:
from pipelineCreazioneDataset import pipelineCreazioneDataset
# Processa multipli video
videos = ["video/video1.mp4", "video/video2.mp4", "video/video3.mp4"]
for video in videos:
print(f"\nπΉ Processando {video}...")
pipelineCreazioneDataset(
video_path=video,
similarity_threshold=0.88, # Soglia personalizzata
delete_after_import=True
)Retrieval batch:
from ProvaRetrival import retrive_obj_id
# Cerca multipli oggetti
object_ids = [1, 2, 3, 5, 8]
search_video = "video/security_footage.mp4"
for obj_id in object_ids:
print(f"\nπ Cercando oggetto ID {obj_id}...")
retrive_obj_id(
object_id=obj_id,
video_path=search_video,
feature_dist=0.92 # Alta precision
)Se vuoi trainare modelli YOLO su dataset custom:
# Esempio: train su dataset chiavi
cd SriptTrain/
python3 trainyolokeys.pyScript tipo trainyolokeys.py:
from ultralytics import YOLO
# Carica modello base
model = YOLO('yolov8n.pt')
# Train
results = model.train(
data='../datasetchiavi/data.yaml', # Path al dataset
epochs=100,
imgsz=640,
batch=16,
name='yolo_Keys',
project='../runs/train'
)
# Valida
metrics = model.val()
print(f"mAP50: {metrics.box.map50}")
print(f"mAP50-95: {metrics.box.map}")Progetto Drone/
βββ detections.db # πΎ Database SQLite principale
β
βββ crops_db/ # πΌοΈ Immagini crops salvate
β βββ Keys/
β β βββ crop_0_20251027_131244.jpg
β β βββ crop_1_20251027_131255.jpg
β β βββ ...
β βββ Wallet/
β βββ Glasses/
β βββ ...
β
βββ features_db/ # 𧬠Feature vectors DINOv2
β βββ Keys/
β β βββ features_0_20251027_131244.npy
β β βββ features_1_20251027_131255.npy
β β βββ ...
β βββ Wallet/
β βββ ...
β
βββ runs/
β βββ segment/ # π Output segmentazione temporanea
β β βββ Keys/
β β β βββ crops/
β β β βββ bboxes/
β β β βββ frames/
β β βββ ...
β β
β βββ verification/ # β
Output verifica
β β βββ positive/
β β βββ negative/
β β βββ similarity/
β β βββ Keys/
β β β βββ similarity_matrix.npy
β β β βββ duplicates_report.json
β β βββ ...
β β
β βββ retrival/ # π Output retrieval temporaneo
β β βββ [pulito dopo ogni run]
β β
β βββ train/ # ποΈ Modelli YOLO trained
β βββ yolo_Generale/
β β βββ weights/best.pt
β βββ yolo_Keys/
β β βββ weights/best.pt
β βββ ...
β
βββ video/ # π¬ Video input
β βββ 4obj1.mp4
β βββ walletKeyGlasses.mp4
β βββ ...
β
βββ pipeline_output.log # π Log esecuzione (opzionale)
| Parametro | Default | Range | Descrizione |
|---|---|---|---|
confidence (segment) |
0.46 | 0.1-0.9 | Soglia detection YOLO iniziale |
conf_threshold (verifica) |
0.75 | 0.5-0.95 | Soglia verifica detections |
distance_threshold |
0.2 | 0.05-0.5 | Soglia coerenza spaziale |
similarity_threshold (dedup) |
0.75 | 0.7-0.9 | Soglia deduplicazione features |
similarity_threshold (import) |
0.85 | 0.8-0.95 | Soglia anti-duplicati DB |
rotations |
16 | 4-32 | Numero rotazioni feature extraction |
delete_after_import |
True | bool | Elimina file temporanei dopo import |
delete_negatives |
True | bool | Elimina falsi positivi dopo verifica |
delete_duplicates |
True | bool | Elimina duplicati dopo clustering |
| Parametro | Default | Range | Descrizione |
|---|---|---|---|
confidence (segment) |
0.50 | 0.3-0.7 | Soglia detection (piΓΉ bassa per recall) |
conf_threshold (verifica) |
0.8 | 0.7-0.9 | Soglia verifica (piΓΉ alta per precision) |
distance_threshold |
0.1 | 0.05-0.3 | Coerenza spaziale stretta |
feature_dist |
0.9 | 0.85-0.95 | Soglia matching features |
rotations |
8 | 4-16 | Rotazioni per matching (meno della creazione) |
Dataset con molti oggetti simili (es. chiavi diverse):
pipelineCreazioneDataset(
video_path="video/many_keys.mp4",
similarity_threshold=0.75, # PiΓΉ bassa per distinguere varianti
rotations=24 # PiΓΉ rotazioni per robustezza
)Dataset con oggetti molto distinti:
pipelineCreazioneDataset(
video_path="video/diverse_objects.mp4",
similarity_threshold=0.90, # PiΓΉ alta, meno rischio confusione
conf_threshold=0.70, # PiΓΉ permissiva
rotations=8 # Meno rotazioni necessarie
)Retrieval in video con movimento veloce:
retrive_obj_id(
object_id=5,
video_path="video/fast_motion.mp4",
confidence=0.35, # Molto bassa per catturare blur
distance_threshold=0.3 # PiΓΉ permissiva per movimento
feature_dist=0.88 # Leggermente piΓΉ bassa
)Retrieval ad alta precision:
retrive_obj_id(
object_id=5,
video_path="video/search.mp4",
confidence=0.65, # Alta per meno FP
conf_threshold=0.85, # Molto restrittiva
feature_dist=0.93, # Match quasi perfetto
rotations=16 # PiΓΉ rotazioni per robustezza
)# Pipeline creation
pipelineCreazioneDataset(
video_path="video/high_precision.mp4",
confidence=0.60, # β PiΓΉ restrittiva
conf_threshold=0.85, # β Verifica strict
similarity_threshold=0.90, # β Dedup aggressiva
delete_after_import=True
)
# Retrieval
retrive_obj_id(
object_id=5,
video_path="video/search.mp4",
confidence=0.65, # β Meno detection
feature_dist=0.93, # β Match quasi perfetto
rotations=16 # β PiΓΉ robustezza
)# Pipeline creation
pipelineCreazioneDataset(
video_path="video/high_recall.mp4",
confidence=0.35, # β Cattura tutto
conf_threshold=0.70, # β Meno restrittiva
similarity_threshold=0.70, # β Dedup conservativa
distance_threshold=0.3 # β Movement permissivo
)
# Retrieval
retrive_obj_id(
object_id=5,
video_path="video/search.mp4",
confidence=0.40, # β Alta recall
feature_dist=0.85, # β Match permissivo
rotations=8
)# Pipeline: 87% precision, 90% recall
confidence=0.46, conf_threshold=0.75, similarity_threshold=0.85
# Retrieval: 100% precision, 90% recall
confidence=0.50, feature_dist=0.90, rotations=8# Set device
import torch
torch.cuda.set_device(0) # GPU 0
# Parallel processing (manuale)
from multiprocessing import Pool
def process_video(video_path):
pipelineCreazioneDataset(video_path)
videos = ["video1.mp4", "video2.mp4", "video3.mp4", "video4.mp4"]
with Pool(processes=4) as pool:
pool.map(process_video, videos)Per scalare a milioni di oggetti:
from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType
# Connect to Milvus
connections.connect("default", host="localhost", port="19530")
# Create collection
fields = [
FieldSchema(name="object_id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="class_name", dtype=DataType.VARCHAR, max_length=64),
FieldSchema(name="features", dtype=DataType.FLOAT_VECTOR, dim=768)
]
schema = CollectionSchema(fields, "Object features database")
collection = Collection("objects", schema)
# Insert features
import numpy as np
features = np.load("features_db/Keys/features_0.npy")
collection.insert([[1], ["Keys"], [features.tolist()]])
# Search
search_params = {"metric_type": "COSINE", "params": {"nprobe": 10}}
results = collection.search([query_features], "features", search_params, limit=5)Se utilizzi questo progetto nella tua ricerca, cita:
@misc{chiostrini2024drone,
title={Automated Object Detection, Dataset Creation and Retrieval System},
author={Chiostrini, Lapo},
year={2024},
institution={UniversitΓ degli Studi di Firenze},
note={Computer Vision Course Project}
}Papers di riferimento:
-
YOLOv8: Jocher, G., Chaurasia, A., & Qiu, J. (2023). Ultralytics YOLO. https://github.com/ultralytics/ultralytics
-
DINOv2: Oquab, M., et al. (2023). DINOv2: Learning Robust Visual Features without Supervision. arXiv:2304.07193
-
PyTorch: Paszke, A., et al. (2019). PyTorch: An Imperative Style, High-Performance Deep Learning Library. NeurIPS.
-
Vision Transformers: Dosovitskiy, A., et al. (2021). An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale. ICLR.
Autore: Lapo Chiostrini
Email: lapo.chiostrini00@gmail.com
UniversitΓ : UniversitΓ degli Studi di Firenze
Corso: Computer Vision
Issue Tracking: Apri issue su GitHub per bug o feature request
Contributi: Pull request benvenute! Segui le guidelines in CONTRIBUTING.md
Questo progetto Γ¨ rilasciato sotto licenza MIT. Vedi LICENSE file per dettagli.
- Meta AI Research per DINOv2 pre-trained models
- Ultralytics per YOLO framework
- PyTorch Team per deep learning infrastructure
- UniversitΓ di Firenze per supporto accademico
Ultimo aggiornamento: Dicembre 2024
Versione: 2.0.0
Status: β
Production Ready