Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I train an SVM classifier using HOG features in OpenCV 3.0 in Python?

I want to train a new HoG classifier for heads and shoulders using OpenCV 3.x Python bindings. What is my pipeline for extracting features, training an SVM, and then running it on the test database?

There appears to be such a pipeline for C++ here: SVM classifier based on HOG features for "object detection" in OpenCV and here: https://github.com/DaHoC/trainHOG/wiki/trainHOG-Tutorial . For Python, there's a description of how to extract a HOG feature set here: Get HOG image features from OpenCV + Python? . However, that only works for OpenCV 2.x, because you cannot initialize a classifier with _winSize and other such variables anymore. Also, that's only for feature extraction, not training or detection using the newly trained classifier.

The output of cv2.HOGdescriptor() does have an svmDetector parameter, but I don't know how to use it because OpenCV 3.x does not come with Python documentation, and OpenCV 2.x only lists HoG in its GPU module, even though there is a CPU implementation.

Is it possible to see an end-to-end pipeline and an explanation for some of the parameters?

like image 965
Anatoliy Kats Avatar asked Jun 09 '16 00:06

Anatoliy Kats


1 Answers

Currently I have the same issue and I have seen the following document from OpenCV:

OCR of Hand-written Data using SVM

Where you can find part of your answer:

deskewed = [map(deskew,row) for row in train_cells]
hogdata = [map(hog,row) for row in deskewed]
trainData = np.float32(hogdata).reshape(-1,64)
responses = np.float32(np.repeat(np.arange(10),250)[:,np.newaxis])
svm = cv2.ml.SVM_create()
svm.setKernel(cv2.ml.SVM_LINEAR)
svm.setType(cv2.ml.SVM_C_SVC)
svm.setC(2.67)
svm.setGamma(5.383)
svm.train(trainData, cv2.ml.ROW_SAMPLE, responses)
svm.save('svm_data.dat')

That is I am working with. Once I solved it, I will update the answer. But at this moment I hope it help you.

............................................................................

You can find an example called digits.py on this opencv directory:

\opencv\sources\samples\python

Depending on your opencv version, there are some differences in methods for SVM class. This is an example for opencv 3.1.

svm = cv2.ml.SVM_create()
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_RBF) # cv2.ml.SVM_LINEAR
# svm.setDegree(0.0)
svm.setGamma(5.383)
# svm.setCoef0(0.0)
svm.setC(2.67)
# svm.setNu(0.0)
# svm.setP(0.0)
# svm.setClassWeights(None)

svm.train(samples_train, cv2.ml.ROW_SAMPLE, labels_train)

resp = svm.predict(samples_test)[1].ravel()
print resp, labels_test

err = (labels_test != resp).mean()
print('error: %.2f %%' % (err*100))

confusion = np.zeros((10, 10), np.int32)
for i, j in zip(labels_test, resp):
    confusion[i, j] += 1
print('confusion matrix:')
print(confusion)
print()

............................................................................

Finally I got it on this way:

samples = []
labels = []    

# Get positive samples
for filename in glob.glob(os.path.join(positive_path, '*.jpg')):
    img = cv2.imread(filename, 1)
    hist = hog(img)
    samples.append(hist)
    labels.append(1)

# Get negative samples
for filename in glob.glob(os.path.join(negative_path, '*.jpg')):
    img = cv2.imread(filename, 1)
    hist = hog(img)
    samples.append(hist)
    labels.append(0)

# Convert objects to Numpy Objects
samples = np.float32(samples)
labels = np.array(labels)
  
    
# Shuffle Samples
rand = np.random.RandomState(321)
shuffle = rand.permutation(len(samples))
samples = samples[shuffle]
labels = labels[shuffle]    
    
# Create SVM classifier
svm = cv2.ml.SVM_create()
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_RBF) # cv2.ml.SVM_LINEAR
# svm.setDegree(0.0)
svm.setGamma(5.383)
# svm.setCoef0(0.0)
svm.setC(2.67)
# svm.setNu(0.0)
# svm.setP(0.0)
# svm.setClassWeights(None)

# Train
svm.train(samples, cv2.ml.ROW_SAMPLE, labels)
svm.save('svm_data.dat')

Regards.

like image 79
omotto Avatar answered Sep 27 '22 20:09

omotto