OpenCV:使用python-cv2+Hog特征+SVM实现狮子识别
文章目录
SVM
支持向量机:寻求一个最优的超平面,实现样本的分类
下面我们用SVM实现一个根据身高体重对男女生分类的问题
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 准备数据
rand1 = np.array([[155,48],[159,50],[164,53],[168,56],[172,60]])
rand2 = np.array([[152,53],[156,55],[160,56],[172,64],[176,65]])
# 0为女生 1为男生
label = np.array([[0],[0],[0],[0],[0],[1],[1],[1],[1],[1]])
data = np.vstack((rand1,rand2)) # 合并两组数据
data = np.array(data, dtype = 'float32')
svm = cv2.ml.SVM_create() # 创建svm学习模型
svm.setType(cv2.ml.SVM_C_SVC) # 类型为svm分类
svm.setKernel(cv2.ml.SVM_LINEAR) # 设置svm的内核为线性分类器
svm.setC(0.01)
#训练
svm.train(data,cv2.ml.ROW_SAMPLE,label)
# 预测
pt_data = np.array([[167,55],[162,57]])
pt_data = np.array(pt_data, dtype = 'float32')
#pt_label = [[0],[1]]
predict = svm.predict(pt_data)
predict[1]
array([[0.],
[1.]], dtype=float32)
Hog特征
看下面这个例子:
这里有一个图像img(整个白色区域), win
窗口(蓝色区域)为图像中Hog特征计算的最大模板,官方模板大小为64*128
。block
(红色区域部分)为win
窗口中的小模板,大小一般为16*16
。block
中又有很多的小模板cell
(绿色区域),大小一般为8*8
。
cell bin: 通过计算像素的梯度得到梯度的大小和方向, 方向为0-360度, 如果以40度进行划分,将会得到9块,将这9块设置为9个单元,每一个单元就是一个bin。
hot特征维度: win窗口中block模板的个数 * cell模板个数 * bin的个数
hog特征: 像素都有一个梯度,win窗口中所有的像素梯度构成了hog特征
如何计算梯度:
我们使用俩个模板:水平梯度模板[1 0 -1]
, 竖直梯度模板[[1],[0],[-1]]
,即相邻像素之差。
求得幅值为:f = sqrt(x^2 + y^2)
,角度angle = arctan(a / b)
bin的划分:如果以40度进行划分,将会得到9个bin,则bin1的区域为(0-20度)和180-200度,即关于180度对称的夹角
如果某个梯度的角度正好在bin角度范围的正中心, 如d = 10,则将其规划到bin1区域。否则将该梯度分解到相邻的俩个bin单元中:d1 = d * d(夹角), d2 = d * (1 - d(夹角))
计算整体的hog特征
1.首先计算每个cell
下所有bin的值,每一个bin的计算方式为所有划分到该bin下的幅值之和sum(d)
2.得到图像特征的维度,以上面的为例,该图像的特征维度为win窗口中block模板的个数 * cell模板个数 * bin的个数 = 105* 4 * 9 = 3780
3.通过使用svm支持向量机对特征进行分类,得到一个3780维的分类结果,用hog * svm得到一个值 f,让 f 与我们的判决门限进行比较,如果大于判决门限则认为是目标。
Hog特征+SVM实现狮子识别
这里使用正样本(PosNum) 820张图片,负样本(NegNum)1931张图片进行训练模型,最终完成训练,最后采用带有小狮子的图片进行测试
这里使用的正负样本的数据集如下百度云链接中:
链接:https://pan.baidu.com/s/1jNpN8ecMKhOHLiy1KlEj4w
提取码:61hr
训练步骤如下:
1.设置参数
2.创建Hog:我们使用cv2.HOGDescriptor(winSize,blockSize,blockStride,cellSize,Bin)
函数来创建
3.创建svm,我们使用cv2.ml.SVM_create()
函数来创建,并设置属性
4.计算Hog,准备标签label
5.训练
6.预测
7.绘图
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 1.设置参数
PosNum = 820
NegNum = 1931
winSize = (64,128)
blockSize = (16,16) # 105
blockStride = (8,8)
cellSize = (8,8)
Bin = 9 # 3780
#2.创建hog
hog = cv2.HOGDescriptor(winSize,blockSize,blockStride,cellSize,Bin)
#3.创建svm
svm = cv2.ml.SVM_create()
#svm属性设置
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_LINEAR)
svm.setC(0.01) # 优化
#4.计算hog
featureNum = int(((128 - 16) / 8 + 1) * ((64 - 16) / 8 + 1) * 4 * 9) # 3780
featureArray = np.zeros((PosNum + NegNum, featureNum),np.float32)
labelArray = np.zeros((PosNum + NegNum, 1),np.int32)
# 处理正样本
for i in range(PosNum):
filename = 'pos\\' + str(i + 1) + '.jpg'
img = cv2.imread(filename)
# 计算图像的hog特征, shape (3780,1)
hist = hog.compute(img, (8,8)) # 第二个参数: winStride Window stride
# 将该hog特征值存到featureArray里面
featureArray[i] = hist.reshape(-1)
labelArray[i] = 1
# 处理负样本
for i in range(PosNum, PosNum + NegNum):
filename = 'neg\\' + str(i + 1 - PosNum) + '.jpg'
img = cv2.imread(filename)
# 计算图像的hog特征, shape (3780,1)
hist = hog.compute(img, (8,8)) # 第二个参数: winStride Window stride
# 将该hog特征值存到featureArray里面
featureArray[i] = hist.reshape(-1)
labelArray[i] = -1
# 5.训练
svm.train(featureArray,cv2.ml.ROW_SAMPLE, labelArray)
# 6.检测
alpha = np.zeros((1), np.float32)
rho = svm.getDecisionFunction(0, alpha) # 得到分类阙值
print(rho)
print(alpha)
alphaArray = np.zeros((1,1),np.float32)
supportVArray = np.zeros((1,featureNum), np.float32)
resultArray = np.zeros((1,featureNum), np.float32)
alphaArray[0,0] = alpha
resultArray = -1 * alphaArray * supportVArray
# 7.绘图
myDetect = np.zeros((3781), np.float32)
for i in range(3780):
myDetect[i] = resultArray[0,i]
myDetect[3780] = rho[0]
# 构建hog
myHog = cv2.HOGDescriptor()
myHog.setSVMDetector(myDetect)
# 加载待检测图片
imageSrc = cv2.imread('test.jpg', 1)
cv2.imshow('img', imageSrc)
# 参数:(8,8)win滑动步长,(32,32)win大小,缩放系数 目标大小
objects = myHog.detectMultiScale(imageSrc, 0, (8,8), (32,32), 1.05, 2)
x = int(objects[0][0][0])
y = int(objects[0][0][1])
w = int(objects[0][0][2])
h = int(objects[0][0][3])
cv2.rectangle(imageSrc, (x,y),(x+w,y+h),(255,0,0),2)
cv2.imshow('img', imageSrc)
print(objects)
cv2.waitKey(0)
(0.2555259476741386, array([[1.]]), array([[0]], dtype=int32))
[0.]
(array([[ 0, 0, 64, 128]], dtype=int32), array([[0.25552595]]))