2013-03-11 17 views
5

Próbuję wykształcić własny detektor do użytku z OpenCV :: HOGDescriptor, ale mam problem z wykonaniem istniejącego HOGDescriptor pracy z moją nowo wyszkoloną maszyną SVM.Szkolenie niestandardowe SVM do użycia z HOGDescriptor w OpenCV

Wyliczyłem funkcje HOG dla pozytywnych i negatywnych obrazów szkoleniowych, oznaczono je etykietami i przeszkoliłem maszynę SVM przy użyciu CvSVM. Parametry jakie stosowane są:

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

Potem obliczyć Primal postaci wektorów nośnych tak, że mam tylko jeden wektor zamiast wielu i ustawić obliczoną wektorów nośnych za pomocą HOGDescriptor.setSVMDetector (wektor);

This is Primal Form

Gdy używam CvSVM.predict() Jestem w stanie poprawnie klasyfikować obiekty z SVM, ale HOGDescriptor.detect() lub detectMultiScale() zawsze zwraca wiele pozytywnych meczów i nie daje dokładne przewidywania.

CvSVM.predict() używa oryginalnych wektorów pomocniczych do klasyfikacji, więc może być coś złego w sposobie obliczania formy pierwotnej.

Czy jest ktoś, kto wytrenował swój własny wykrywacz, który może wskazać mi właściwy kierunek?

+0

wydaje się, że błąd z biblioteki libsvm został odziedziczony, w którym kolejność etykiet zostaje pomieszana. Funkcja przewidywania jest świadoma kolejności i sprawdza, która etykieta jest która, a zatem działa dobrze. Rozwiązałem problem przez ustawienie mojej etykiety + ve na liczbę mniejszą niż moja -ve, tzn. Pos = 1, neg = 2. w przeciwnym razie może zajść potrzeba odwrócenia modelu poprzez pomnożenie przez -1. (dlatego akceptowana odpowiedź ma dziwny znak ujemny). Postanowiłem tego nie robić w ten sposób, na wypadek, gdyby naprawili błąd (nie jest to błąd, jeśli użyjesz funkcji przewidywania, ale mogą to zmienić). – QED

Odpowiedz

6

Napisałem klasę potomną CvSVM, aby wyodrębnić pierwotną formę po szkoleniu svm liniowy. Próbki dodatnie są oznaczone jako 1, a próbki ujemne oznaczone jako -1. To dziwne, że muszę umieścić znak ujemny przed alfami i pozostawić znak rho niezmieniony, aby uzyskać poprawne wyniki z 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

Bardzo ładne rozwiązanie, tylko małe pytanie @DXM: ta konwersja do pierwotnej formy działa tylko dla Liner SVM, a co z tym, kiedy używam jądra RBF? –

+1

Nie zajrzałem do kodu źródłowego przy użyciu jądra RBF w opencv. Ale domyślam się, że gdy zastosujesz jądro do swoich funkcji, powinno to być to samo, co liniowy svm. – DXM

+0

To może być bardzo wolne IMHO. Jądro Rbf oblicza odległości euklidesowe między funkcjami i wszystkimi wektorami wsparcia svm. Spójrz na kod metody przewidywania. Ciekawi mnie sposób, w jaki rozważałeś wdrożenie ... – Madhatter

4

Walczyłem z tym samym problemem. Wyszukiwanie na forach Znalazłem, że wykrywacza nie można przeszkolić za pomocą CvSVM (nie znam przyczyny). Użyłem LIBSVM do szkolenia wykrywacza. Oto kod do wyodrębnienia detektora dla HOGDescriptor.setSVMDetector (w): Szczegóły dotyczące danych znajdują się w dokumentacji/nagłówku LIBSVM. Zrobiłem całe szkolenie w C++, wypełniając dane treningowe LIBSVM z CV do LIBSVM; poniższy kod wyodrębnia wektor detektora wymagany dla cv :: HOGDescriptor. Parametr w jest 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]); 

Nadzieja to pomaga ...

+0

Czy próbowałeś tego kodu? Wydaje się wykrywać + ve nawet w fałszywych obrazach. – magarwal

0

Z tego co czytam w papierze Dalal chodzi o czujki HOG, on sugerować, że w celu usunięcia fałszywych alarmów, musimy się przekwalifikować naszego modelu. Przekwalifikowanie odbywa się poprzez zastosowanie modelu wstępnego (model, który daje wiele fałszywych alarmów), a następnie wykrywanie obiektów we wszystkich obrazach próbek negatywnych. Wszystkie zwrócone prostokąty z pewnością będą fałszywie pozytywne.

Następnie dodaj wszystkie te fałszywe alarmy do negatywnych obrazów próbek (negatywny zestaw danych), po raz kolejny wykonaj trening. Wynikowy model, jak zasugerowano w artykule, zwróci znacznie mniej fałszywych alarmów.

Niestety, próbowałem tego (ponownego szkolenia), ale wynikowy model po prostu nie rozpoznaje niczego, nawet w przypadku pozytywnych próbek obrazu. Ale myślę, że warto spróbować, ponieważ to było to, co sugerowano w artykule wynalazcy o wykrywaczu HOG