計算機視覺基礎系列(python與opencv的操作與運用/tensorflow的基礎介紹)(二十四)---Hog+SVM的識別

訓練數據的時候,首先需要做下面幾步:

1.準備訓練樣本;2.對樣本進行Hog+Svm的訓練;3.運用test圖片進行預測

一、準備樣本

樣本分爲正樣本和負樣本,樣本的準備可以運用視頻的分幀截取圖片存儲。這裏pos文件夾下包含正樣本,包含所檢測的目標;neg不包含檢測的目標爲負樣本。樣本的準備的時候,圖片的尺寸需要注意,這裏的尺寸是64x128。

樣本的獲取的手段:1.來源於網絡;2.自己收集。一個好的樣本遠勝過一個複雜的神經網絡,容量大。通常我們是自己收集樣本的,會通過視頻截取幀來得到的,比如說一秒28幀,有100秒,則可以得到2800張圖片。

正樣本的特點:儘可能多樣性,這裏的多樣性一般是指的環境的多樣性,干擾性因素多,這樣檢測的效果較好。這裏有截取本數據集的部分代碼。如下,代碼有部分解釋,也較爲簡單,可以看懂:

# 視頻分解成圖片
# 1 load加載視頻 2 讀取info 3 解碼 單幀視頻parse 4 展示 imshow
import cv2
# 獲取一個視頻打開cap
cap = cv2.VideoCapture('1.mp4')
# 判斷是否打開
isOpened = cap.isOpened
print(isOpened)
#幀率
fps = cap.get(cv2.CAP_PROP_FPS)
#寬度
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
#高度
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(fps,width,height)

i = 0
while(isOpened):
	if i == 100:
		break
	else:
		i = i+1
	(flag,frame) = cap.read() # 讀取每一張 flag讀取是否成功 frame內容
	fileName = 'imgs\\'+str(i) + '.jpg'
	print(fileName)
	if flag == True:
		#寫入圖片
		cv2.imwrite(fileName,frame,[cv2.IMWRITE_JPEG_QUALITY,100])
print('end!')

圖片分解完後,我們這裏其實準備的數據集的尺寸是64x128,所以這裏我們需要裁剪和截取。下面是裁剪和截取的代碼,這裏的代碼前面有所介紹,這裏可以看到具體介紹

# 540 * 960 ==>64*128
import cv2

for i in range(0,100):
	fileName = 'imgs\\'+str(i+1)+'.jpg'
	print(fileName)
	img = cv2.imread(fileName)
	imgInfo = img.shape
	height = imgInfo[0]
	width = imgInfo[1]
	mode = imgInfo[2]
	dstHeight = 128
	dstWidth = 64
	dst = cv2.resize(img,(dstWidth,dstHeight))
	cv2.imwrite(fileName,dst)

這裏準備的正樣本的數量是820個,負樣本是1931個,一般來說,正負樣本的比例是1:2或者1:3。

二、訓練樣本

在訓練樣本的時候,要注意一些問題,在代碼註釋中會有詳細說明,如下,代碼很多地方都有,可以看一下說明註釋:

可以結合上一篇博客來看,就會較快的理解。

第七步(檢測)的重點介紹:
沒有直接運用svm.predict來進行預測。

resultArray是3780維的,rho是一個一行一列一維的,而最終的的數組myDetect是3781維度的,所以3780的維是來自resultArray的,最後一個維度是來自rho的。

檢測需要創建myhog,需要用myhog進行檢測,用detectMultiScale進行檢測,沒有用predict方法,得到寬高等信息返回,才能把目標繪製出來。代碼如下:

# 1.參數的設置   2.hog的創建(實例對象)  3.獲取SVM的參數
# 4.計算hog   5.label標籤    6.完成train訓練    7.完成predicr     8.繪圖draw
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 1 參數的設置:設置全局變量 在一個windows窗體中有105個block,每個block下有4個cell,每個cell下有9個bin,總共3780維
PosNum = 820      # 正樣本的個數
NegNum = 1931     # 負樣本的個數
winSize = (64, 128)       # 窗體大小
blockSize = (16, 16)      # 105個block
blockStride = (8, 8)      # block的步長
cellSize = (8, 8)
nBin = 9

# 2 hog對象的創建,HOGDescriptor創建的方法,參數設置:1.窗體的大小,2.block的大小,3.步長,4.cell的大小,5.Bin的數量
hog = cv2.HOGDescriptor(winSize, blockSize, blockStride, cellSize, nBin)

# 3 SVM分類器的創建,定義一個SVM的對象,來自機器學習的SVM創建的模塊
svm = cv2.ml.SVM_create()

# 4 計算當前的hog,需要準備各種參數,並且我們需要把參數計算完後保存在某個地方,所以我們需要新設置一定的數組,或者是當前hog特徵的維度
featureNum = int(((128-16)/8+1)*((64-16)/8+1)*4*9)
# 3780,特徵的維度,是一個int類型;((128-16)/8+1)是block的數量,((64-16)/8+1)爲windows的寬度,4就是指的一個block裏面有4個cell,9是一個cell裏面有9個Bin,這樣計算可以的惡道3780維
# 還需要創建一個feature數組和一個label數組用於裝載當前的特徵,爲接下來的第五步和第六步作準備,將標籤和特徵準備好
featureArray = np.zeros(((PosNum+NegNum), featureNum), np.float32)
# featureArray是一個二維的數組,第一個(PosNum+NegNum)是正負樣本的個數,featureNum特徵的維度
labelArray = np.zeros(((PosNum+NegNum), 1), np.int32)       # 定義一個標籤,也是一個二維的,參數和上面的一樣
# SVM 是監督學習,所以需要樣本和標籤 SVM進行學習,而學習的是圖片中的的hog特徵,所以我們可以說hog特徵可以說做是SVM真正的樣本,標籤是我們在進行SVM訓練的時候,進行監督學習使用的
# 遍歷所有的圖片:正負樣本都需要遍歷
for i in range(0, PosNum):
	fileName = 'pos\\'+str(i+1)+'.jpg'
	img = cv2.imread(fileName)             # 圖片的讀取
	hist = hog.compute(img, (8, 8))        # 當前hog的計算 3780維的數據,用hist裝載特徵,計算HOG描述子,檢測窗口移動步長(8,8)
	# 當前的問題是:我們需要將hog特徵裝載到featureArray中,而featureArray是一個二維的,而計算出來的只是一個hist,那麼這一步怎麼完成呢?
	# 其實我們這裏的hist是一個3780維的,而featureArray是一個二維的,且第一個參數是正負樣本的個數,第二個參數是featureNum,我們可以這麼操作:
	for j in range(0,featureNum):
		# featureArray裝載的是hog的特徵,比如說i=1的時候,第一個hog表示爲hog1,i=2的時候爲hog2,第二個特徵,每一個特徵是3780維的,所以hist[j]要放到i行,第j列中
		featureArray[i,j] = hist[j]        # hog特徵的裝載
	labelArray[i,0] = 1          # 正樣本標籤爲1,labelArray也是一個二維的,n行1列的,所以縱座標放置的是0,正樣本處理完畢,接下來的負樣本的設置是一樣的

for i in range(0, NegNum):
	fileName = 'neg\\'+str(i+1)+'.jpg'
	img = cv2.imread(fileName)
	hist = hog.compute(img,(8,8))
	for j in range(0,featureNum):
		featureArray[i+PosNum,j] = hist[j]         # 同樣要把特徵放在featureArray中,所以i+PosNum是要記錄負樣本的時候必須裝載在正樣本的後面
	labelArray[i+PosNum,0] = -1 # 負樣本標籤爲-1

# 設置SVM的屬性,setType設置屬性,添加當前類型,再來設置setKernel爲SVM的線性內核,再來設置setC
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_LINEAR)
svm.setC(0.01)

# 6 train,調用train進行訓練,參數:1.特徵數組;2.機器學習ROW_SAMPLE;3.標籤數組。返回值爲ret
ret = svm.train(featureArray, cv2.ml.ROW_SAMPLE, labelArray)

# 預測可以運用svm.predict來進行預測,這裏我們不用,使用其他方法來進行檢測
# 7 預測(創建myHog--->myDect參數得到-->來源於resultArray(公式得到) rho(訓練得到))
# rho是svm得到的一個hog的描述信息,這個在最後的閾值判決的時候起作用,在累加的時候起作用
# 深入到hog以及svm最後的判決中看
alpha = np.zeros((1), np.float32)
# getDecisionFunction方法最核心的還是svm的計算,svm來源於訓練方法,樣本準備好後訓練可以得到svm,然後得到rho
rho = svm.getDecisionFunction(0, alpha)
print(rho)
print(alpha)

# resultArray,定義alphaArray,我們需要用alphaArray和支持向量機數組進行相乘
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     # 一行一列的,所以第一個元素是[0, 0]
resultArray = -1*alphaArray*supportVArray       # 計算公式;resultArray 計算,支持向量的個數,只需要當成參數就行

# mydect參數,構建detect
myDetect = np.zeros(3781, np.float32)
for i in range(0, 3780):
	# 是一個一維的,myDetect
	myDetect[i] = resultArray[0,i]
myDetect[3780] = rho[0]
# myHog的創建很重要
# 構建好Hog,用HOGDescriptor方法構建
myHog = cv2.HOGDescriptor()
# 返回的myHog,用setSVMDetector設置屬性
myHog.setSVMDetector(myDetect)

# 待檢測圖片的加載
imageSrc = cv2.imread('test2.jpg', 1)
# 檢測小獅子 (8,8)winds的滑動步長 1.05 縮放係數 (32,32)窗口大小
# 完成檢測,返回的目標包含哪些信息,myHog有個方法detectMultiScale,和人臉識別比較類似,縮放。
# 它可以檢測出圖片中所有的目標,並將目標用vector保存各個目標的座標、大小(用矩形表示),函數由分類器對象調用;1.05是縮放,(8, 8)windows的滑動步長,(32, 32)窗體大小
# myHog的創建很重要
objs = myHog.detectMultiScale(imageSrc, 0, (8, 8), (32, 32), 1.05, 2)
# 起始位置、寬和高 objs三維信息,獲取目標的座標,是三維的,所以我們需要定義一個三維的座標,這些信息放在三維中的最後一維
x = int(objs[0][0][0])       # 座標,w和h是寬高
y = int(objs[0][0][1])
w = int(objs[0][0][2])
h = int(objs[0][0][3])

# 目標的繪製 圖片 起始位置 終止位置 顏色,繪製矩形框
cv2.rectangle(imageSrc, (x, y), (x+w, y+h), (255, 0, 0))
# 目標的展示
cv2.imshow('dst', imageSrc)
cv2.waitKey(0)


實驗相關數據集點擊此處下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章