可使用一条直线将线性可分离的数据分为两组,这条直线在SVM算法中称为“决策边界”;非线性可分离的数据转换为高维数据后可称为线性可分离数据。这是SVM算法的理论基础。
1.图解SVM算法
下面的代码在图像中选择了5个点,分为两类,类别标志分别为0和1。将5个点和标志作为已知分类数据训练SVM模型;然后用模型对图像中的所有点进行分类,根据分类结果设置图像颜色,从而直观显示图像像素的分类结果。
import cv2
import numpy as np
import matplotlib.pyplot as plt
准备训练数据,假设图像高240,宽320,在其中选择5个点。
traindata = np.matrix([[140,60],[80,120],[160,110],[160,190],[240,180]]
,dtype=np.float32)
5个点,前3个点为一类,标志为0;后2个点为一类,标志为1
labels = np.array([0,0,0,1,1])
svm = cv2.ml.SVM_create() #创建SVM分类器
svm.setGamma(0.50625) #设置相关参数
svm.setC(12.5)
svm.setKernel(cv2.ml.SVM_LINEAR)
svm.setType(cv2.ml.SVM_C_SVC)
svm.setTermCriteria((cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-6))
svm.train(traindata, cv2.ml.ROW_SAMPLE, labels) #训练模型
img = np.zeros((240,320,3), dtype="uint8") #创建图像,用于SVM分类
colors = {0:(102,255,204),1:(204,204,102)}
用SVM分类器对图像像素分类,根据结果设置像素颜色
for i in range(240):
for j in range(320):
point = np.matrix([[j,i]],dtype=np.float32) #将像素坐标转换为测试数据
label = svm.predict(point)[1].ravel() #执行预测,返回结果
img[i,j] = colors[label[0]] #根据预测结果,设置像素颜色
svm_vectors = svm.getUncompressedSupportVectors() #获得SVM向量
for i in range(svm_vectors.shape[0]): #在图像中绘制SVM向量(红色圆)
cv2.circle(img, (svm_vectors[i,0],svm_vectors[i,1]),8,(0,0,255),2)
在图像中绘制训练数据点,类别标志0使用蓝色,类别标志1使用绿色
cv2.circle(img, (140,60),5,(255,0,0),-1)
cv2.circle(img, (80,120),5,(255,0,0),-1)
cv2.circle(img, (160,110),5,(255,0,0),-1)
cv2.circle(img, (160,190),5,(0,255,0),-1)
cv2.circle(img, (240,180),5,(0,255,0),-1)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #转换为RGB格式
plt.imshow(img)
plt.show() #显示结果
2.使用SVM算法识别手写数据
前面的例子中,kNN算法直接使用了像素值作为特征向量。SVM算法可使用图像的定向梯度直方图(Histogram of Oriented Gradients,HOG)作为特征向量来对图像进行分类。
import cv2
import numpy as np
def hog(img): #定义HOG描述符计算函数
hog = cv2.HOGDescriptor((20,20),(8,8), #定义HOGDescriptor对象
(4,4),(8,8),9,1,-1,0,0.2,1,64,True)
hog_descriptor=hog.compute(img) #计算HOG描述符
hog_descriptor=np.squeeze(hog_descriptor) #转换为一维数组
return hog_descriptor #返回HOG描述符,144位
img = cv2.imread('digits.png',0)
digits=[np.hsplit(row,100) for row in np.vsplit(img,50)]#分解图像,50行100列
labels = np.repeat(np.arange(10),500)[:,np.newaxis] #定义对应的标记
hogdata = [list(map(hog,row)) for row in digits] #计算图像的HOG描述符
trainData = np.float32(hogdata).reshape(-1,144) #转换为测试数据
svm = cv2.ml.SVM_create() #创建SVM分类器
设置相关参数
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, labels) #训练模型
用绘图工具创建的手写数字5图像(大小为20*20)进行测试
test= cv2.imread('d5.jpg',0) #打开图像
test_data=hog(test)
test_data=test_data.reshape(1,144).astype(np.float32) #转换为测试数据
result = svm.predict(test_data)[1]
print('识别结果:',np.squeeze(result))
用绘图工具创建的手写数字8图像(大小为20*20)进行测试
test= cv2.imread('d8.jpg',0)
test_data=hog(test)
test_data=test_data.reshape(1,144).astype(np.float32) #转换为测试数据
result = svm.predict(test_data)[1]
print('识别结果:',np.squeeze(result))