I am using SVM to predict my ROI, I trained SVM and now in testing phases, it's giving me output with labels in the form of 1 and 0.
I am trying that if SVM predicts 1
mean image contains eyebrow, now I want that it should be rectangle around the eyebrow because the algorithm is predicting based on the eyebrow. How can I do this?
Below is the code I use for prediction.
h_og = cv2.HOGDescriptor()
histogram = h_og.compute(photo)
arr.append(histogram)
arr = np.float32(arr)
result = svm.predict(arr)
Now the result is in the form of number or label. How I can draw a rectangle on that ROI of testing image.
Positive data: image with eyebrows
Negative data: images not containing eyebrow
Testing data: Full face of the person
If I have to use detectMultiScale()
with it how I will use it with the above logic.
Code use for training purpose
sam = []
lab = []
# Get positive samples
for filename in glob.glob('D:\*.png'):
im = cv2.imread(filename, 1)
h_og = cv2.HOGDescriptor()
hist = h_og.compute(im)
sam.append(hist)
lab.append(1)
# Get negative samples
for file in glob.glob('D:\\*.png'):
im = cv2.imread(file, 1)
im = cv2.resize(img, (240, 160))
h_og = cv2.HOGDescriptor()
hist = h_og.compute(im)
sam.append(hist)
lab.append(0)
# Convert objects to Numpy Objects
sam = np.float32(sam)
lab = np.array(lab)
# Shuffle Samples
rand = np.random.RandomState(321)
shuffle = rand.permutation(len(sam))
sam = sam[shuffle]
lab = lab[shuffle]
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(sam, cv2.ml.ROW_SAMPLE, lab)
svm.save('file.xml')
More Explanation:
If my image contains eyebrow, my SVM prediction is successfully returning me 1
But after that I want it to display that image the below way, the rectangle should be on the coordinates based on which SVM predicts 1
Above image is just a sample image, I am doing it for eyebrow and after prediction, I want to achieve or trying to achieve the output in the above way.
svm.predict(arr)
can only predict a single image.
To get coordinates and ROIs you need something that uses this method with different parts of the image at different scales.
So yes, you need to use detectMultiScale()
. It is a method of cv2.HOGDescriptor()
, therefore you first need to set h_og.setSVMDetector(array)
with the SVM supports vectors and the rho that you have trained. You can get them using svm.getSupportVectors()
and svm.getDecisionFunction(0)
.
After that, with found, w = h_og.detectMultiScale(img)
you will have a list of rects (found) containing positive data that you can use to draw your boxes.
Try something like this, for example:
hog = cv2.HOGDescriptor()
svm = cv2.ml.SVM_load('svm.xml')
sv = svm.getSupportVectors()
rho, alpha, svidx = svm.getDecisionFunction(0)
svm_new = np.append(sv, -rho)
hog.setSVMDetector(svm_new)
for file in glob.glob("Testing\\*.jpg"):
img = cv2.imread(file, 1)
img = cv2.resize(img, (240, 160))
found, w = hog.detectMultiScale(img)
for (x, y, w, h) in found:
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow("Image", img)
cv2.waitKey()
Alternatively, try following this example. Save the model of the SVM using this:
svm.save("svm.xml")
tree = ET.parse('svm.xml')
root = tree.getroot()
SVs = root.getchildren()[0].getchildren()[-2].getchildren()[0]
rho = float( root.getchildren()[0].getchildren()[-1].getchildren()[0].getchildren()[1].text )
svmvec = [float(x) for x in re.sub( '\s+', ' ', SVs.text ).strip().split(' ')]
svmvec.append(-rho)
pickle.dump(svmvec, open("svm.pickle", 'w'))
In order to do this, you need to import pickle and ElementTree of XML:
import xml.etree.ElementTree as ET
import pickle
And then load it and use it with this:
svm = pickle.load(open("svm.pickle"))
hog.setSVMDetector( np.array(svm) )
found, w = hog.detectMultiScale(img)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With