2013-03-11 5 views
5

Sto provando ad addestrare il mio rilevatore per l'uso con OpenCV :: HOGDescriptor ma sto riscontrando problemi nel far funzionare l'HOGDescriptor esistente con il mio SVM appena formato.Formazione SVM personalizzata da utilizzare con HOGDescriptor in OpenCV

Ho calcolato le caratteristiche di HOG per le immagini di addestramento positive e negative, le ho etichettate e ho addestrato l'SVM utilizzando CvSVM. I parametri che ho usato sono:

CvSVMParams params; 
    params.svm_type =CvSVM::EPS_SVR; 
    params.kernel_type = CvSVM::LINEAR; 
    params.C = 0.01; 
    params.p = 0.5; 

Poi ho calcolare Modulo Primal dei vettori di supporto in modo che ho solo ottenere un vettore al posto di molti e impostare il vettore supporto calcolato utilizzando HOGDescriptor.setSVMDetector (vettoriale);

This is Primal Form

Quando uso CvSVM.predict() sono in grado di classificare correttamente gli oggetti con la SVM, ma HOGDescriptor.detect() o detectMultiScale() restituisce sempre un sacco di partite positive e non dà precise predizioni.

CvSVM.predict() utilizza i vettori di supporto originali per la classificazione, quindi potrebbe esserci qualcosa di sbagliato nel modo in cui sto calcolando la forma primaria.

C'è qualcuno che ha addestrato il proprio rilevatore che può indicarmi la giusta direzione?

+0

sembra che un errore da libsvm sia stato ereditato in cui l'ordine delle etichette viene incasinato. La funzione di previsione è a conoscenza dell'ordine e cerca quale etichetta è quale, e quindi funziona bene. Ho risolto il problema impostando la mia etichetta + ve su un numero inferiore al mio -ve, cioè pos = 1, neg = 2. altrimenti potrebbe essere necessario invertire il modello moltiplicando per -1. (questo è il motivo per cui la risposta accettata ha lo strano segno negativo). Ho scelto di non farlo in questo modo nel caso in cui risolvono il bug (non è un bug se usi la previsione, ma potrebbero cambiarlo) – QED

risposta

6

Ho scritto una classe figlia di CvSVM per estrarre la forma primitiva dopo che un svm lineare è stato addestrato. I campioni positivi sono etichettati 1 e quelli negativi sono etichettati -1. È strano che io debba mettere un segno negativo davanti agli alfa e lasciare invariato il segno di rho per ottenere risultati corretti da HogDescriptor.

LinearSVM.h

#ifndef LINEAR_SVM_H_ 
#define LINEAR_SVM_H_ 
#include <opencv2/core/core.hpp> 
#include <opencv2/ml/ml.hpp> 

class LinearSVM: public CvSVM { 
public: 
    void getSupportVector(std::vector<float>& support_vector) const; 
}; 

#endif /* LINEAR_SVM_H_ */ 

LinearSVM.cc

#include "linear_svm.h"  
void LinearSVM::getSupportVector(std::vector<float>& support_vector) const { 

    int sv_count = get_support_vector_count(); 
    const CvSVMDecisionFunc* df = decision_func; 
    const double* alphas = df[0].alpha; 
    double rho = df[0].rho; 
    int var_count = get_var_count(); 
    support_vector.resize(var_count, 0); 
    for (unsigned int r = 0; r < (unsigned)sv_count; r++) { 
     float myalpha = alphas[r]; 
     const float* v = get_support_vector(r); 
     for (int j = 0; j < var_count; j++,v++) { 
     support_vector[j] += (-myalpha) * (*v); 
     } 
    } 
    support_vector.push_back(rho); 
} 
+0

Soluzione molto bella, solo una piccola domanda @DXM: questa conversione alla forma originale funziona solo con Liner SVM, e quando utilizzo i kernel RBF? –

+1

Non ho esaminato il codice sorgente dell'uso del kernel RBF in opencv. Ma la mia ipotesi è che una volta applicato il kernel alle funzionalità, dovrebbe essere lo stesso di svm lineare. – DXM

+0

Questo può essere molto lento IMHO. Il kernel Rbf calcola le distanze euclidee tra le caratteristiche e tutti i vettori di supporto svm. Dai un'occhiata al codice del metodo di previsione. Sono curioso di sapere come lo stavi implementando ... – Madhatter

4

Ero alle prese con lo stesso problema. Cercando nei forum ho scoperto che il rivelatore non può essere addestrato usando CvSVM (non ne conosco il motivo). Ho usato LIBSVM per addestrare il rilevatore. Ecco il codice per estrarre il rilevatore per HOGDescriptor.setSVMDetector (w): Per i dettagli dei dati vedere la documentazione/intestazione di LIBSVM. Ho fatto tutto il training in C++, riempiendo i dati di addestramento LIBSVM da CV a LIBSVM; il codice sottostante estrae il vettore del rivelatore necessario per cv :: HOGDescriptor. Il parametro w è std::vector<float> w

const double * const *sv_coef = model.sv_coef; 
const svm_node * const *SV = model.SV; 
int l = model.l; 
model.label; 

const svm_node* p_tmp = SV[0]; 
int len = 0; 
while(p_tmp->index != -1) 
{ 
    len++; 
    p_tmp++; 
} 
w.resize(len+1); 

for(int i=0; i<l; i++) 
{ 
    double svcoef = sv_coef[0][i]; 
    const svm_node* p = SV[i]; 
    while(p->index != -1) 
    { 
     w[p->index-1] += float(svcoef * p->value); 
     p++; 
    } 
} 
w[len] = float(-model.rho[0]); 

Spero che questo aiuti ...

+0

Hai provato questo codice? Sembra rilevare + ve anche nelle immagini false. – magarwal

0

Da quello che ho letto sul giornale di Dalal su rilevatore HOG, si suggerisce che per rimuovere i falsi positivi, abbiamo bisogno di riqualificare il nostro modello. La riqualificazione viene eseguita applicando il modello preliminare (il modello che fornisce molti falsi positivi), quindi rileva gli oggetti in tutte le immagini campione negative. Tutti i rettangoli restituiti sarebbero sicuramente falsi positivi.

Quindi, aggiungere tutti questi falsi positivi alle immagini del campione negativo (set di dati negativo), eseguire di nuovo l'allenamento. Il modello risultante, come suggerito nel documento, restituirà molto meno falsi positivi.

Sfortunatamente, l'ho provato (ri-allenamento), ma il modello risultante non riconosce nulla, anche su campioni di immagini positive. Ma penso che valga la pena di provare perché era quello che suggeriva nel documento dell'inventore sul rivelatore HOG