一、SVM支援向量機
1、SVM原理
在機器學習,支援向量機的監督學習模型與相關的學習演算法可以分析用於資料分類和迴歸分析。給定一組訓練樣例,每個訓練樣例被標記為屬於兩個類別中的一個或另一個,SVM訓練演算法建立一個模型,將新的例子分配給一個類別或另一個類別,使其成為非概率二元線性分類器(儘管方法如Platt縮放存在以在概率分類設定中使用SVM)。SVM模型是將這些例子表示為空間中的點的對映,以便將各個類別的例子除以儘可能寬的明顯差距。然後將新示例對映到同一空間中,並預測屬於基於它們落在哪一側的類別。
比如,我們有兩種顏色的球在桌子上,我們要分開它們。
我們拿到一根棍子放在桌子上,是否完成得很漂亮?
有些賤人來了,桌子上放了更多的球,這種方法很有效,但其中一個球在錯誤的一邊,現在可能有一個更好的地方放置棒。
SVM試圖通過儘可能在棒的兩側留出儘可能大的間隙來將棒放置在最佳位置。
現在,當賤人回來時,棍子仍然是一個不錯的位置。
SVM工具箱還有另一個更重要的技巧。賤人已經看到你用棍子有多好,所以他給了你一個新的挑戰。
世界上沒有任何棍棒可以讓你分球,所以你會怎麼做?你當然翻桌子!把球扔進空中。然後,用你的專業忍者技能,你抓住一張紙並將其滑入球之間。
現在,賤人站著看球,他們的球會看起來被一些彎曲的線條分開。
再之後,無聊的大人們,把這些球叫做 「data」,把棍子 叫做 「classifier」, 最大間隙trick 叫做「optimization」, 拍桌子叫做「kernelling」, 那張紙叫做「hyperplane」。
2、opencv的SVM引數
OpenCV 3.3中給出了支援向量機(Support Vector Machines)的實現,即cv::ml::SVM類,此類的宣告在include/opencv2/ml.hpp檔案中,實現在modules/ml/src/svm.cpp檔案中,它既支援兩分類,也支援多分類,還支援迴歸等,OpenCV中SVM的實現源自libsvm庫。其中:
(1)、cv::ml::SVM類:繼承自cv::ml::StateModel,而cv::ml::StateModel又繼承自cv::Algorithm;
(2)、create函式:為static,new一個SVMImpl用來建立一個SVM物件;
(3)、setType/getType函式:設定/獲取SVM公式型別,包括C_SVC、NU_SVC、ONE_CLASS、EPS_SVR、NU_SVR,用於指定分類、迴歸等,預設為C_SVC;
(4)、setGamma/getGamma函式:設定/獲取核函式的γ引數,預設值為1;
(5)、setCoef0/getCoef0函式:設定/獲取核函式的coef0引數,預設值為0;
(6)、setDegree/getDegree函式:設定/獲取核函式的degreee引數,預設值為0;
(7)、setC/getC函式:設定/獲取SVM優化問題的C引數,預設值為0;
(8)、setNu/getNu函式:設定/獲取SVM優化問題的υ引數,預設值為0;
(9)、setP/getP函式:設定/獲取SVM優化問題的ε引數,預設值為0;
(10)、setClassWeights/getClassWeights函式:應用在SVM::C_SVC,設定/獲取weights,預設值是空cv::Mat;
(11)、setTermCriteria/getTermCriteria函式:設定/獲取SVM訓練時迭代終止條件,預設值是cv::TermCriteria(cv::TermCriteria::MAX_ITER + TermCriteria::EPS,1000, FLT_EPSILON);
(12)、setKernel/getKernelType函式:設定/獲取SVM核函式型別,包括CUSTOM、LINEAR、POLY、RBF、SIGMOID、CHI2、INTER,預設值為RBF;
(13)、setCustomKernel函式:初始化CUSTOM核函式;
(14)、trainAuto函式:用最優引數訓練SVM;
(15)、getSupportVectors/getUncompressedSupportVectors函式:獲取所有的支援向量;
(16)、getDecisionFunction函式:決策函式;
(17)、getDefaultGrid/getDefaultGridPtr函式:生成SVM引數網格;
(18)、save/load函式:儲存/載入已訓練好的model,支援xml,yaml,json格式;
(19)、train/predict函式:用於訓練/預測,均使用基類StatModel中的。
原文連結:http://bytesizebio.net/2014/02/05/support-vector-machines-explained-well/
公式連結:https://en.wikipedia.org/wiki/Support_vector_machine
SVM引數連結:https://docs.opencv.org/master/d1/d2d/classcv_1_1ml_1_1SVM.html
例項
svm_type()—— 指定SVM的型別:
引數:
- C_SVC:C表示懲罰因子,C越大表示對錯誤分類的懲罰越大。
- NU_SVC:和C_SVC相同。
- ONE_CLASS:不需要類標號,用於支援向量的密度估計和聚類.
- EPSILON_SVR:-不敏感損失函式,對樣本點來說,存在著一個不為目標函式提供任何損失值的區域,即-帶。
- NU_SVR:由於EPSILON_SVR需要事先確定引數,然而在某些情況下選擇合適的引數卻不是一件容易的事情。而NU_SVR能夠自動計算引數。
kernel_type()—— SVM的核心型別:
引數:
- LINEAR:線性核函式(linear kernel)
- POLY:多項式核函式(ploynomial kernel)
- RBF:徑向機核函式(radical basis function)
- SIGMOID: 神經元的非線性作用函式核函式(Sigmoid tanh)
- PRECOMPUTED:使用者自定義核函式
train()
引數:
- InputArray samples, 訓練樣本
- int layout, 排版,引數:ROW_SAMPLE,每個訓練樣本是一行樣本,COL_SAMPLE,每個訓練樣本佔據一列樣本
- InputArray responses, 與訓練樣本相關聯的響應向量
getDecisionFunction()
引數:
- int i,決策函式的索引。如果解決的問題是迴歸,1類或2類分類,那麼只會有一個決策函式,並且索引應該總是0.否則,在N類分類的情況下,將會有N(N- 1 )/ 2 決策功能。
- OutputArray alpha,
α 權重的可選輸出向量,對應於不同的支援向量。線上性SVM的情況下,所有的alpha都是1。- OutputArray svidx, 支援向量矩陣內的支援向量索引的可選輸出向量。線上性SVM的情況下,每個決策函式由單個“壓縮”支援向量組成。
import cv2
import numpy as np
import matplotlib.pyplot as plt
#1 準備data
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]])
# 男生身高和體重資料
# 2 建立分組標籤,0代表女生,1代表男生
label = np.array([[0],[0],[0],[0],[0],[1],[1],[1],[1],[1]])
# 3 合併資料
data = np.vstack((rand1,rand2))
data = np.array(data,dtype=`float32`)
# 4 訓練
# ml 機器學習模組 SVM_create() 建立
svm = cv2.ml.SVM_create()
# 屬性設定
svm.setType(cv2.ml.SVM_C_SVC) # svm type
svm.setKernel(cv2.ml.SVM_LINEAR) # line
svm.setC(0.01)
# 訓練
result = svm.train(data,cv2.ml.ROW_SAMPLE,label)
# 預測
pt_data = np.vstack([[167,55],[162,57]]) #0 女生 1男生
pt_data = np.array(pt_data,dtype=`float32`)
print(pt_data)
(par1,par2) = svm.predict(pt_data)
print(par2)
複製程式碼
結果:
[[167. 55.]
[162. 57.]]
[[0.]
[1.]]
複製程式碼
二、Hog特徵
方向梯度直方圖(Histogram of Oriented Gradient, HOG)特徵是一種在計算機視覺和影像處理中用來進行物體檢測的特徵描述子。它通過計算和統計影像區域性區域的梯度方向直方圖來構成特徵。Hog特徵結合SVM分類器已經被廣泛應用於影像識別中,尤其在行人檢測中獲得了極大的成功。需要提醒的是,HOG+SVM進行行人檢測的方法是法國研究人員Dalal在2005的CVPR上提出的,而如今雖然有很多行人檢測演算法不斷提出,但基本都是以HOG+SVM的思路為主。
HOG特徵提取演算法的實現過程:
HOG特徵提取方法就是將一個image(你要檢測的目標或者掃描視窗):
1)灰度化(將影像看做一個x,y,z(灰度)的三維影像);
2)採用Gamma校正法對輸入影像進行顏色空間的標準化(歸一化);目的是調節影像的對比度,降低影像區域性的陰影和光照變化所造成的影響,同時可以抑制噪音的干擾;
3)計算影像每個畫素的梯度(包括大小和方向);主要是為了捕獲輪廓資訊,同時進一步弱化光照的干擾。
4)將影像劃分成小cells(例如6*6畫素/cell);
5)統計每個cell的梯度直方圖(不同梯度的個數),即可形成每個cell的descriptor;
6)將每幾個cell組成一個block(例如3*3個cell/block),一個block內所有cell的特徵descriptor串聯起來便得到該block的HOG特徵descriptor。
7)將影像image內的所有block的HOG特徵descriptor串聯起來就可以得到該image(你要檢測的目標)的HOG特徵descriptor了。這個就是最終的可供分類使用的特徵向量了。
原文連結:https://blog.csdn.net/liulina603/article/details/8291093
三、例項
HOGDescriptor()
引數:
- Size win_size=Size(64, 128),檢測視窗大小。
- Size block_size=Size(16, 16),塊大小,目前只支援Size(16, 16)
- Size block_stride=Size(8, 8),塊的滑動步長,大小隻支援是單元格cell_size大小的倍數。
- Size cell_size=Size(8, 8),單元格的大小,目前只支援Size(8, 8)。
- int nbins=9, 直方圖bin的數量(投票箱的個數),目前每個單元格Cell只支援9個。
- double win_sigma=DEFAULT_WIN_SIGMA,高斯濾波視窗的引數。
- double threshold_L2hys=0.2,塊內直方圖歸一化型別L2-Hys的歸一化收縮率
- bool gamma_correction=true,是否gamma校正
- nlevels=DEFAULT_NLEVELS,檢測視窗的最大數量
正樣本:
負樣本:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 第一步:確定標準
PosNum = 820
# 正樣本個數
NegNum = 1931
# 負樣本個人
winSize = (64,128)
# 一個視窗(win)的大小是64x128
blockSize = (16,16)
# 每個塊的大小是16x16
blockStride = (8,8)
# 每個塊的步長是8x8
# 一個視窗有((64-16)/8+1)*((128-16)/8+1) = 7*15 = 105個塊(block)
cellSize = (8,8)
# 每個胞元的大小是8x8
# 一個塊(block)有 (16/8)*(16/8) = 4胞元(cell)
nBin = 9
# 一個胞元有 9 個bin,表示每一個胞元對應的向量就是9維
# 視窗對應的一維特徵向量維數n = 105 * 4 * 9 = 3780
# hog+svm檢測行人,最終的檢測方法是最基本的線性判別函式,wx + b = 0,剛才所求的3780維向量其實就是w,而加了一維的b就形成了opencv預設的3781維檢測運算元
# 第二步:創造一個HOG描述子和檢測器
hog = cv2.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nBin)
# 第三步:啟動SVM分離器
svm = cv2.ml.SVM_create()
# 第四步:計算Hog
featureNum = int(((128-16)/8+1)*((64-16)/8+1)*4*9)
# 視窗對應的一維特徵向量維數n
featureArray = np.zeros(((PosNum+NegNum),featureNum),np.float32)
# 建立Hog特徵矩陣
labelArray = np.zeros(((PosNum+NegNum),1),np.int32)
# 建立標籤矩陣
# 給圖片樣本打標籤,正樣本是1,負樣本是-1
for i in range(0,PosNum):
fileName = `pos/`+str(i+1)+`.jpg`
# 匯入正樣本圖片
img = cv2.imread(fileName)
hist = hog.compute(img,(8,8))
# 每個hog特性的維數是3780
for j in range(0,featureNum):
featureArray[i,j] = hist[j]
# featureArray裝載hog特徵, [1,:]代表hog特徵1, [2,:]代表hog特徵2
labelArray[i,0] = 1
# 正樣本的label是 1
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]
labelArray[i+PosNum,0] = -1
# 負樣本的label是 -1
# SVM屬性設定
svm.setType(cv2.ml.SVM_C_SVC)
# SVM模型型別:C_SVC表示SVM分類器,C_SVR表示SVM迴歸
svm.setKernel(cv2.ml.SVM_LINEAR)
# 核函式型別: LINEAR:線性核函式(linear kernel),POLY:多項式核函式(ploynomial kernel),RBF:徑向機核函式(radical basis function),SIGMOID: 神經元的非線性作用函式核函式(Sigmoid tanh),PRECOMPUTED:使用者自定義核函式
svm.setC(0.01)
# SVM型別(C_SVC/ EPS_SVR/ NU_SVR)的引數C,C表示懲罰因子,C越大表示對錯誤分類的懲罰越大
# 第六步:訓練函式
ret = svm.train(featureArray,cv2.ml.ROW_SAMPLE,labelArray)
# 第七步:檢測 (1、建立myhog,引數myDeteect)
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
myDetect = np.zeros((3781),np.float32)
for i in range(0,3780):
myDetect[i] = resultArray[0,i]
myDetect[3780] = rho[0]
# myDetect是3781維,其中3780維來自resultArray,最後一維來自rho
myHog = cv2.HOGDescriptor()
myHog.setSVMDetector(myDetect)
# 第八步:匯入待檢測圖片的載入
imageSrc = cv2.imread(`Test2.jpg`,1)
# 載入待檢測圖片
objs = myHog.detectMultiScale(imageSrc,0,(8,8),(32,32),1.05,2)
# 檢測圖片
x = int(objs[0][0][0])
y = int(objs[0][0][1])
w = int(objs[0][0][2])
h = int(objs[0][0][3])
# 原始座標(x,y),寬w,高h
# 第九步:繪製展示
cv2.rectangle(imageSrc,(x,y),(x+w,y+h),(255,0,0),2)
cv2.imshow(`dst`,imageSrc)
cv2.waitKey(0)
複製程式碼
待檢測圖片:
結果:
(0.19296025963377925, array([[1.]]), array([[0]], dtype=int32))
[0.]
複製程式碼