【机器学习基础】SVM算法在项目实践中的应用!
作者:蘇麗敏,Datawhale優秀學習者,北理工計算機碩士
支持向量機(Support Vector Machine)是Cortes和Vapnik于1995年首先提出的,它在解決小樣本、非線性及高維模式識別中表現出許多特有的優勢,并能夠推廣應用到函數擬合等其他機器學習問題中。
正是由于SVM具有很多獨特的優勢,基于SVM分類器在很多時候都具有較好的擬合作用。本文對SVM算法在行人檢測項目實踐中的應用進行詳細講解,同時給出調用OpenCV分類器及可視化的代碼實現,便于大家學習實踐。
目前的行人檢測基本上都是基于法國研究人員Dalal在2005的CVPR發表的HOG+SVM的行人檢測算法(Histograms of Oriented Gradients for Human Detection, Navneet Dalel,Bill Triggs, CVPR2005)。HOG+SVM作為經典算法也集成到OpenCV里面去了,可以直接調用實現行人檢測。
本文目錄
? ??1. HOG特征描述符
????????1.1. 主要思想
????????1.2. 微觀
? ? ? ? 1.3. 宏觀(硬核)
? ? ? ? 1.4. HOG算法優缺點
????2.?HOG特征的原理
????????2.1.?圖形預處理
??????? 2.2. 計算圖像梯度
? ? ? ? 2.3.?計算梯度直方圖
? ? ? ? 2.4.?Block歸一化
? ? ? ? 2.5.?獲得HOG描述子
? ? ? ? 2.6.?使用HOG特征數據
????3. 基于OpenCV的簡單實現
????????3.1. 行人檢測
????????3.2. 可視化
一、HOG特征描述符
HOG(Histogram of Oriented Gradients)HOG特征在對象檢測與模式匹配中是一種常見的特征提取技術(深度學習之前),是基于本地像素塊進行特征直方圖提取的一種算法,對像局部的變形與光照影響有很好的穩定性,最初是用HOG特征來識別人像,通過HOG特征提取+SVM訓練,可以得到很好的效果,OpenCV已經有相應的接口。
HOG特征是在2005年CVPR的會議發表,在圖像手工特征提取方面具有里程碑式的意義,當時在行人檢測領域獲得了極大成功。
1.1 主要思想
局部目標的外表和形狀可以被局部梯度的分布很好的描述,即使我們不知道對應的梯度和邊緣的位置。(本質:梯度的統計信息,梯度主要存在于邊緣edge或角落corner的地方)
1.2 宏觀
特征描述符就是通過提取圖像的有用信息,并且丟棄無關信息來簡化圖像的表示。
HOG特征描述符可以將3通道的彩色圖像轉換成一定長度的特征向量。
那么我們就需要定義什么是“有用的”,什么是“無關的”。這里的“有用”,是指對于什么目的有用,顯然特征向量對于觀察圖像是沒有用的,但是它對于像圖像識別和目標檢測這樣的任務非常有用。當將這些特征向量輸入到類似支持向量機(SVM)這樣的圖像分類算法中時,會得到較好的結果。
那什么樣的“特征”對分類任務是有用,比如我們想檢測出馬路上的車道線,那么我們可以通過邊緣檢測來找到這些車道線,在這種情況下,邊緣信息就是“有用的”,而顏色信息是無關的。
方向梯度直方圖(HOG)特征描述符常和線性支持向量機(SVM)配合使用,用于訓練高精度的目標分類器。
1.3 微觀(硬核)
在HOG特征描述符中,梯度方向的分布,也就是梯度方向的直方圖被視作特征。圖像的梯度(x和y導數)非常有用,因為邊緣和拐角(強度突變的區域)周圍的梯度幅度很大,并且邊緣和拐角比平坦區域包含更多關于物體形狀的信息。
HOG特征是一種圖像局部特征,基本思路是將圖像劃分為很多小的連通區域,即細胞單元Cell,然后對Cell的梯度幅值和方向進行投票統計,形成基于梯度特性的直方圖。把直方圖在圖像更大的范圍內(又名區間或者Block)進行歸一化。歸一化的塊描述符叫做HOG描述子feature descriptor。將檢測窗口中的所有塊的HOG描述子組合成最終的特征向量。然后使用SVM分類器進行目標和非目標的二分類(檢測)。
HOG+SVM的工作流程如下:
首先對輸入的圖片進行預處理,然后計算像素點的梯度特性,包括梯度幅值和梯度方向。然后投票統計形成梯度直方圖,然后對blocks進行normalize,最后收集到檢測窗口的HOG feature(一行多維的vector)放入SVM里進行監督學習,實現行人的檢測。接下來對上述HOG的主要步驟進行學習。
檢測窗口在整個圖像的所有位置和尺度進行掃描,并對輸出的金字塔進行非極大值抑制來檢測目標(檢測窗口的大小一般為128x64)
1.4?HOG算法優缺點
HOG算法具有以下優點:
核心思想是所檢測的局部物體外形能夠被梯度或邊緣方向的分布所描述,HOG能較好地捕捉局部形狀信息,對幾何和光學變化都有很好的不變性;
HOG是在密集采樣的圖像塊中求取的,在計算得到的HOG特征向量中隱含了該塊與檢測窗口之間的空間位置關系。
HOG算法具有以下缺點:
特征描述子獲取過程復雜,維數較高,導致實時性差;
很難處理遮擋問題,人體姿勢動作幅度過大或物體方向改變也不易檢測(這個問題后來在DPM中采用可變形部件模型的方法得到了改善);
跟SIFT相比,HOG沒有選取主方向,也沒有旋轉梯度方向直方圖,因而本身不具有旋轉不變性(較大的方向變化),其旋轉不變性是通過采用不同旋轉方向的訓練樣本來實現的;
跟SIFT相比,HOG本身不具有尺度不變性,其尺度不變性是通過縮放檢測窗口圖像的大小來實現的;
此外,由于梯度的性質,HOG對噪點相當敏感,在實際應用中,在block和Cell劃分之后,對于得到各個區域,有時候還會做一次高斯平滑去除噪點。
二、HOG特征的原理
接下來讓我們進入到計算圖像的HOG特征描述符的具體步驟。以下面這張圖片為例(寬高為100x200):
2.1 圖形預處理
預處理包括灰度化和Gamma變換。
灰度處理是可選操作,因為灰度圖像和彩色圖像都可以用于計算梯度圖。對于彩色圖像,先對三通道顏色值分別計算梯度,然后取梯度值最大的那個作為該像素的梯度。
然后進行伽馬矯正,調節圖像對比度,減少光照對圖像的影響(包括光照不均和局部陰影),使過曝或者欠曝的圖像恢復正常,更接近人眼看到的圖像。
Gamma矯正公式:,其中表示圖像,表示冪指數。(越大,圖像越暗;為1時,表示沒有變化。) 如圖,當取不同的值時對應的輸入輸出曲線( =1時輸入輸出保持一致) :
1) 當<1時,輸入圖像的低灰度值區域動態范圍變大,進而圖像低灰度值區域對比度得以增強;在高灰度值區域,動態范圍變小,進而圖像高灰度值區域對比度得以降低。最終,圖像整體的灰度變亮。
2) 當>1時,輸入圖像的低灰度值區域動態范圍變小,進而圖像低灰度值區域對比度得以降低;在高灰度值區域,動態范圍變大,進而圖像高灰度值區域對比度得以增強。最終,圖像整體的灰度變暗。
代碼:
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('*.png', 0) img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) img2 = np.power(img/float(np.max(img)),1/2.2) plt.imshow(img2) plt.axis('off') plt.show()放圖,左圖是,中圖是,右圖是:
作者在他的博士論文里有提到,對于涉及大量的類內顏色變化,如貓,狗和馬等動物,沒標準化的RGB圖效果更好,而牛,羊的圖做gamma顏色校正后效果更好。是否用gamma校正分情況吧。(●ˇ?ˇ●)2.2 計算圖像梯度
為了得到梯度直方圖,那么首先需要計算圖像水平方向和垂直方向梯度。可以通過使用以下內核過濾圖像實現,分別用于計算水平梯度和垂直梯度。
一般使用特定的卷積核對圖像濾波實現,可選用的卷積模板有:sobel算子、Prewitt算子、Roberts模板等等。
可以使用內核大小為1的sobel算子獲取相同結果,OpenCV也是如此。
利用sobel水平和垂直算子與輸入圖像卷積計算、:
進一步得到圖像梯度的幅值:
簡化計算,幅值也可以做近似:
圖像梯度的方向:
這里需要注意的是:梯度方向和圖像邊緣方向是互相正交的。
代碼:
mport cv2 import numpy as np# Read image img = cv2.imread('*.jpg') img = np.float32(img) / 255.0 # 歸一化# 計算x和y方向的梯度 gx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1) gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)# 計算合梯度的幅值和方向(角度) mag,?angle?=?cv2.cartToPolar(gx,?gy,?angleInDegrees=True)下圖展示了梯度:
第一個圖:x-梯度的絕對值,第二個圖:y梯度的絕對值 ,第三個圖:梯度的幅值,第四個圖:角度。
注意到,x-梯度在垂直線觸發,y-梯度在水平線觸發。梯度的幅值在有密集的劇烈改變時觸發。當區域很平緩時,梯度沒有明顯變化。梯度圖除去了很多不必要的信息(例如有顏色的背景),強調凸顯線條。當你看到梯度圖像,很容易想到這張圖片有一個人。
在每個像素點,梯度有一個幅值和方向。對于有顏色的圖像,計算三通道的梯度(如上圖所示)。一個像素點的梯度的幅值是三通道中梯度幅值最大的值,角度也是最大梯度對應的角度。
2.3 計算梯度直方圖
此時,每一個像素點具有兩個值:梯度幅值和梯度方向。
在這一步中,圖像被分成若干個8×8的Cell,如下圖所示,例如我們將圖像resize至64x128的大小,那么這幅圖像就被劃分為8x16個8x8的Cell單元,并為每個8×8的Cell計算梯度直方圖。當然,Cell的劃分也可以是其他值:16x16,8x16等,根據具體的場景確定。
計算梯度直方圖之前,先了解一下為什么要把圖像分為若干個Cell?
這是因為如果對一整張梯度圖逐像素計算,其中的有效特征是非常稀疏的,不但運算量大,而且會受到一些噪聲干擾。使用特征描述符便提供了緊湊的表示。一個8x8的圖像塊包含8x8x3=192個像素值。一個8x8的Cell包含了8x8x2 = 128個值(每個像素包括梯度的大小和方向)。128個值將由9-bin的直方圖(存儲9個值的向量,想想坐標應該就明白了)。同時,計算Cell上的梯度直方圖更具魯棒性。逐像素計算梯度會產生噪音,直方圖表示對噪音更不敏感。
在HOG中,每個8x8的Cell的梯度直方圖本質是一個由9個數值組成的向量, 對應于0、20、40、60…160的梯度方向(角度)。那么原本Cell中8x8x2 = 128個值就由長度為9的向量來表示,用這種梯度直方圖的表示方法,大大降低了計算量,同時又對光照等環境變化更加地魯棒。
如下圖所示,左圖是衣服64x128的圖像,被劃分為8x16個8x8的Cell;中間的圖像表示一個Cell中的梯度矢量,箭頭朝向代表梯度方向,箭頭長度代表梯度大小。
右圖是 8×8 的Cell中表示梯度的原始數值,注意角度的范圍介于0到180度之間,而不是0到360度, 這被稱為“無符號”梯度,因為兩個完全相反的方向被認為是相同的。和是相同的。(經驗表明這樣處理對于行人檢測效果更好。)
接下來,計算Cell中像素的梯度直方圖,將0-180度分成9等份,稱為9個bins,分別是0,20,40…160。然后對每個bin中梯度的貢獻進行統計:
這里采用加權投票統計,比如上面方向圖中藍圈包圍的像素,角度為80度,這個像素對應的幅值為2,所以在直方圖80度對應的bin加上2。紅圈包圍的像素,角度為10度,介于0度和20度之間,其幅值為4,那么這個梯度值就被按比例分給0度和20度對應的bin,也就是各加上2。
再比如:(如上圖所示)某像素的梯度幅值為13.6,方向為36,36度兩側的角度bin分別為20度和40度,那么按一定加權比例分別在20度和40度對應的bin加上梯度值,加權公式為:
20度對應的bin:((40-36)/20) x13.6,分母的20表示20等份,其中4份給20度對應的bin;
40度對應的bin:((36-20)/20) x13.6,分母的20表示20等份,其中16份給20度對應的bin;
還有一個細節需要注意,如果某個像素的梯度角度大于160度,也就是在160度到180度之間,那么把這個像素對應的梯度值按比例分給0度和160度對應的bin。如左下圖綠色圓圈中的角度為165度,幅值為85,則按照同樣的加權方式將85分別加到0度和160度對應的bin中。
對整個Cell進行投票統計,最終得到9-bin直方圖:
可以看到直方圖中,0度和160附近有很大的權重,說明了大多數像素的梯度向上或者向下,也就是這個Cell是個橫向邊緣。
2.4 Block歸一化
HOG特征將8×8的一個局部區域作為一個Cell,再以2×2個Cell作為一組,稱為一個block,也就是說一個block表示16x16的區域。
由于每個Cell有9個值,一個block(2×2個Cell)則有36個值,HOG是通過滑動窗口的方式來得到block的,如下圖所示:
為什么需要分Block呢?
我們已經為圖像的8×8單元構造了基于梯度的直方圖,但是圖像的梯度對整體光照很敏感。這意味著對于特定的圖像,圖像的某些部分與其他部分相比會非常明亮。雖然不能從圖像中完全消除,但是可以通過使用16×16個塊來對梯度進行歸一化來減少這種光照變化的影響。比如通過將所有像素值除以2來使圖像變暗,那么梯度幅值將減小一半,因此直方圖中的值也將減小一半。
接下來對Block進行歸一化。(再再再一次強調,歸一化的目的是為了降低光照/遷移的影響):
歸一化的方法有很多:L1-norm、L2-norm、max/min等等,一般選擇L2-norm。
例如對于一個[128,64,32]的三維向量來說,模長是:
這叫做向量的L2范數。將這個向量的每個元素除以146.64就得到了歸一化向量 [0.87, 0.43, 0.22]。
現在有一個新向量,是第一個向量的2倍 [128x2, 64x2, 32x2],也就是?[256, 128, 64],我們將這個向量進行歸一化,你可以看到歸一化后的結果與第一個向量歸一化后的結果相同。所以,對向量進行歸一化可以消除整體光照的影響。
知道了如何歸一化,現在來對block的梯度直方圖進行歸一化(注意不是Cell),一個block有4個直方圖,將這4個直方圖拼接成長度為36的向量,然后對這個向量進行歸一化。
因為使用的是滑動窗口,滑動步長為8個像素,一個Cell大小,每滑動一次,就在這個窗口上進行歸一化計算得到長度為36的向量,并重復這個過程。如上圖所示。
2.5 獲得HOG描述子
每一個16x16大小的block將會得到一個長度為36x1的特征向量,并進行歸一化。那會得到多大的特征向量呢?
對于上圖被劃分8 x16個Cell ,每個block有2x2個Cell的話,那么Cell的個數為:(8-1)x(16-1)=105。
每個16x16 block由36x1維向量,合并所有105個block的特征,最終得到由36 x105=3780維向量表示的特征描述符。
獲得HOG特征向量,就可以用來可視化和分類了。對于多維的HOG特征,SVM就可以排上用場了。
介紹以下Dalal等人的訓練方法:
提取正負樣本的HOG特征;
用正負樣本訓練一個初始的分類器,然后由分類器生產檢測器;
然后用初始分類器在負樣本原圖上進行行人檢測,檢測出來的矩形區域自然都是分類錯誤的負樣本,這就是所謂的難例(hard examples);
提取難例的HOG特征并結合第一步中的特征,重新訓練,生成最終的檢測器 ;
這種二次訓練的處理過程顯著提高了每個檢測器的表現,一般可以使得每個窗口的誤報率(FPPW False Positives Per Window)下降5%。
2.6 使用HOG特征數據
HOG特征本身是不支持旋轉不變性與多尺度檢測的,但是通過構建高斯金字塔實現多尺度的開窗檢測就會得到不同分辨率的多尺度檢測支持,如下圖所示。
OpenCV中HOG多尺度對象檢測API如下:
virtual void cv::HOGDescriptor::detectMultiScale(
? ?InputArray ?img,
? ?std::vector< Rect > & ? foundLocations,
? ?double ?hitThreshold = 0,
? ?Size ? ?winStride = Size(),
? ?Size ? ?padding = Size(),
? ?double ?scale = 1.05,
? ?double ?finalThreshold = 2.0,
? ?bool ? ?useMeanshiftGrouping = false
)
Img-表示輸入圖像
foundLocations-表示發現對象矩形框
hitThreshold-表示SVM距離度量,默認0表示,表示特征與SVM分類超平面之間
winStride-表示窗口步長
padding-表示填充
scale-表示尺度空間
finalThreshold-最終閾值,默認為2.0
useMeanshiftGrouping-不建議使用,速度太慢拉
在基于Adaboost算法的人臉檢測分類器!這一節我們利用haar特征和級聯分類器Adaboost檢測人臉時我們使用過detectMultiScale()函數,級聯分類器對象嘗試在輸入圖像的不同尺度下檢測對象,該函數有一個比較重要的參數scaleFactor(一般設置為1.3),表示一個比率:即在每層金字塔中所獲得的圖像與上一層圖像的比率,scaleFactor越小,金字塔的層數就越多,計算就越慢,計算量也會更大,但是計算結果相對更精確。
三、基于OpenCV的簡單實現
3.1 行人檢測
代碼:
import cv2 as cv import numpy as np from matplotlib import pyplot as pltif __name__ == '__main__':src = cv.imread("*.jpg")cv.imshow("input", src)hog = cv.HOGDescriptor()hog.setSVMDetector(cv.HOGDescriptor_getDefaultPeopleDetector())# Detect people in the image(rects, weights) = hog.detectMultiScale(src,winStride=(2,4),padding=(8, 8),scale=1.2,useMeanshiftGrouping=False)for (x, y, w, h) in rects:cv.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 2)cv.imshow("hog-detector", src)cv.imwrite("hog-detector.jpg",src)cv.waitKey(0)cv.destroyAllWindows()待檢測圖片:
檢測圖片(有點不完美,調參調不動了,先醬~):
3.2?可視化
feature.log函數:
image:可以是灰度圖或者彩色圖;
orientations:就是把180度分成幾份,也就是bin的數量;
pixels_per_Cell:一個Cell里包含的像素個數;
Cells_per_block:一個block包含的Cell個數;
visualize:是否返回一個hog圖像用于顯示,下面會顯示這張圖;
為了顯示效果,把Cell的尺寸改為(16, 16),對于每一個Cell,畫出它歸一化后的梯度直方圖。如下圖所示,我們可以很明顯的看出一個人的輪廓。
from skimage import feature, exposure import cv2 image = cv2.imread('hog.jpg') fd, hog_image = feature.hog(image, orientations=9, pixels_per_Cell=(16, 16),Cells_per_block=(2, 2), visualize=True) # Rescale histogram for better display hog_image_rescaled = exposure.rescale_intensity(hog_image, in_range=(0, 10)) cv2.imshow('img', image) cv2.imshow('hog', hog_image_rescaled) hog_image_rescaled = 255.0 * hog_image_rescaled cv2.imwrite('edge_hog.jpg', hog_image_rescaled) cv2.waitKey(0)==ord('q') 往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統計學習方法》的代碼復現專輯 AI基礎下載機器學習的數學基礎專輯獲取一折本站知識星球優惠券,復制鏈接直接打開:https://t.zsxq.com/yFQV7am本站qq群1003271085。加入微信群請掃碼進群:總結
以上是生活随笔為你收集整理的【机器学习基础】SVM算法在项目实践中的应用!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 还怕GPU资源不够用?多实例GPU MI
- 下一篇: 【机器学习基础】Python数据预处理: