Understanding SVM

The svm_introduction.py script carries out a simple example in order to see how to use SVMs in OpenCV. First of all, we create the training data and the labels:

# Set up training data:
labels = np.array([1, 1, -1, -1, -1])
data = np.matrix([[500, 10], [550, 100], [300, 10], [500, 300], [10, 600]], dtype=np.float32)

As you can see, five points are created. The first two points are assigned the 1 class, while the other three points are assigned the -1 class. The next step is to initialize the SVM model using the svm_init() function:

# Initialize the SVM model:
svm_model = svm_init(C=12.5, gamma=0.50625)

The svm_init() function creates an empty model and assigns the main parameters and returns the model:

def svm_init(C=12.5, gamma=0.50625):
"""Creates empty model and assigns main parameters"""

model = cv2.ml.SVM_create()
model.setGamma(gamma)
model.setC(C)
model.setKernel(cv2.ml.SVM_LINEAR)
model.setType(cv2.ml.SVM_C_SVC)
model.setTermCriteria((cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-6))

return model

In this case, the SVM kernel type is set to LINEAR (no mapping is done) and the type of SVM is set to C_SVC (can be used for n-class classification where n ≥ 2).

Then, we train the SVM using the svm_train() function:

# Train the SVM:
svm_train(svm_model, data, labels)

Here, the svm_train() function trains the model using both the samples and the responses, and then returns the trained model:

def svm_train(model, samples, responses):
"""Trains the model using the samples and the responses"""

model.train(samples, cv2.ml.ROW_SAMPLE, responses)
return model

The next step is to create an image where the SVM response will be drawn:

# Create the canvas (black image with three channels)
# This image will be used to show the prediction for every pixel:
img_output = np.zeros((640, 640, 3), dtype="uint8")

And finally, we show the SVM response using the show_svm_response() function:

# Show the SVM response:
show_svm_response(svm_model, img_output)

Therefore, the img_ouput image shows the SVM response. The code for the show_svm_response() function is as follows:

def show_svm_response(model, image):
"""Show the prediction for every pixel of the image, the training data and the support vectors"""

colors = {1: (255, 255, 0), -1: (0, 255, 255)}

# Show the prediction for every pixel of the image:
for i in range(image.shape[0]):
for j in range(image.shape[1]):
sample = np.matrix([[j, i]], dtype=np.float32)
response = svm_predict(model, sample)

image[i, j] = colors[response.item(0)]

# Show the training data:
# Show samples with class 1:
cv2.circle(image, (500, 10), 10, (255, 0, 0), -1)
cv2.circle(image, (550, 100), 10, (255, 0, 0), -1)
# Show samples with class -1:
cv2.circle(image, (300, 10), 10, (0, 255, 0), -1)
cv2.circle(image, (500, 300), 10, (0, 255, 0), -1)
cv2.circle(image, (10, 600), 10, (0, 255, 0), -1)

# Show the support vectors:
support_vectors = model.getUncompressedSupportVectors()
for i in range(support_vectors.shape[0]):
cv2.circle(image, (support_vectors[i, 0], support_vectors[i, 1]), 15, (0, 0, 255), 6)

As can be seen, the function shows the following:

The output of this script can be seen in the next screenshot:

As you can see, the SVM has been trained using the training data and the labels composed of five points (two points are assigned class 1, while the other three points are assigned class -1) and it is later used to classify all of the pixels in the image. This classification results in a division of the image in a yellow and a cyan region. Additionally, you can see that the boundary between both regions corresponds to the optimal separation between the two classes because the distance to the nearest element of each of the two classes is the largest. The support vectors are shown with a red line border.