欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

如何使用OpenCV進行手寫數字分類器C++/Python

系統 1917 0

如何使用OpenCV進行手寫數字分類器C++/Python_第1張圖片

在本教程中,我們將使用OpenCV構建一個簡單的手寫數字分類器。我們將共享用C ++和Python編寫.

圖像分類管道

本章節(jié)暫不討論圖像分類管道,大家可以自行搜索相關知識,下次我們補充。

如何使用OpenCV進行手寫數字分類器C++/Python_第2張圖片

?

我們將使用方向梯度直方圖作為特征描述符和支持向量機(SVM)作為分類的機器學習算法。

使用OpenCV的光學字符識別(OCR)示例(C ++ / Python)

我想與代碼共享一個示例,以使用HOG + SVM演示圖像分類。與此同時,我希望盡可能保持簡單,這樣除了HOG和SVM之外我們不需要太多東西。這個靈感和數據來自OpenCV的教程在這里:

http://docs.opencv.org/trunk/dd/d3b/tutorial_py_svm_opencv.html

原始教程僅在Python中,并且由于一些奇怪的原因實現了它自己的簡單HOG描述符。我們用OpenCV的HOG描述符替換了他們自己開發(fā)的HOG。

OCR的數字數據集

如何使用OpenCV進行手寫數字分類器C++/Python_第3張圖片

我們將使用上面的圖像作為OpenCV樣本附帶的數據集。它共包含5000張圖像 - 每個數字500張圖像。每幅圖像均為20×20灰度,背景為黑色。這些數字中的4500個將用于訓練,其余500個將用于測試算法的性能。您可以點擊上面的圖片放大。

讓我們完成構建和測試分類器所需的步驟。

第1步:糾偏(預處理)

人們通常將學習算法視為塊框。在一端輸入圖像,在另一端輸出結果。實際上,您可以稍微協助算法,并注意到性能的巨大提升。例如,如果您正在構建面部識別系統,則將圖像與參考面對齊通常會導致性能的顯著提高。典型的對準操作使用面部特征檢測器來對準每個圖像中的眼睛。

在構建分類器之前對齊數字同樣會產生更好的結果。在面部的情況下,對準是相當明顯的 - 您可以對面部圖像應用相似變換,以將眼睛的兩個角對準參考面的兩個角。

歪斜的例子

如何使用OpenCV進行手寫數字分類器C++/Python_第4張圖片

在手寫數字的情況下,我們沒有明顯的特征,如我們可以用于對齊的眼角。然而,人們寫作的明顯變化是他們的寫作傾向。有些作者有一個向右或向前的傾斜,其中數字向前傾斜,有些具有向后或向左傾斜,有些沒有傾斜。我們可以通過修復這個垂直斜面來幫助算法,因此它不必學習數字的這種變化。左側的圖像顯示第一列中的原始數字,并且它是傾斜(固定)版本。

可以使用圖像矩來實現對簡單灰度圖像的這種偏斜校正。OpenCV有一個瞬間的實現,它在計算有用的信息時很方便,如質心,面積,黑色背景的簡單圖像的偏斜。

事實證明,偏斜的度量是由兩個中心力矩(mu11 / mu02)的比率給出的。如此計算的偏度可以用于計算對圖像進行校正的仿射變換。

偏移的代碼如下:

C++

            
              Mat deskew(Mat& img)

{

Moments m = moments(img);

if(abs(m.mu02) < 1e-2)

{

// No deskewing needed.

return img.clone();

}

// Calculate skew based on central momemts.

double skew = m.mu11/m.mu02;

// Calculate affine transform to correct skewness.

Mat warpMat = (Mat_
              
                (2,3) << 1, skew, -0.5*SZ*skew, 0, 1 , 0);

Mat imgOut = Mat::zeros(img.rows, img.cols, img.type());

warpAffine(img, imgOut, warpMat, imgOut.size(),affineFlags);

return imgOut;

}
              
            
          

Python

            
              def deskew(img):

m = cv2.moments(img)

if abs(m['mu02']) < 1e-2:

# no deskewing needed.

return img.copy()

# Calculate skew based on central momemts.

skew = m['mu11']/m['mu02']

# Calculate affine transform to correct skewness.

M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])

# Apply affine transform

img = cv2.warpAffine(img, M, (SZ, SZ), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)

return img
            
          

步驟2:計算定向梯度直方圖(HOG)描述符

在此步驟中,我們將使用HOG特征描述符將灰度圖像轉換為特征向量。

我們發(fā)現理論與實踐之間存在巨大差距。獲取知識很容易。我可以閱讀論文和書籍。如果我們不理解這個概念或數學,我們可以閱讀更多的論文和書籍。這很容易。將這些知識付諸實踐的難點。部分原因是很多這些算法在繁瑣的手動操作之后起作用,并且如何設置正確的參數并不明顯。例如,在Harris角點檢測器中,為什么自由參數k設置為0.04?為什么不是1或2或0.34212呢?為什么42是生命,宇宙和一切的答案?

隨著我獲得更多真實世界的經驗,我意識到在某些情況下你可以做出有根據的猜測,但在其他情況下,沒有人知道為什么。人們經常進行參數掃描 - 他們以原則方式改變不同的參數,以查看產生最佳結果的因素。有時,最好的參數有一個直觀的解釋,有時他們沒有。

牢記這一點,讓我們看看為我們的HOG描述符選擇了哪些參數。我們也會嘗試解釋為什么它們有意義,但我會提供有力的手工操作而不是嚴格的證據!

C++

            
              HOGDeor hog(

Size(20,20), //winSize

Size(10,10), //blocksize

Size(5,5), //blockStride,

Size(10,10), //cellSize,

9, //nbins,

1, //derivAper,

-1, //winSigma,

0, //histogramNormType,

0.2, //L2HysThresh,

1,//gammal correction,

64,//nlevels=64

1);//Use signed gradients
            
          

Python

            
              winSize = (20,20)

blockSize = (10,10)

blockStride = (5,5)

cellSize = (10,10)

nbins = 9

derivAperture = 1

winSigma = -1.

histogramNormType = 0

L2HysThreshold = 0.2

gammaCorrection = 1

nlevels = 64

signedGradients = True

hog = cv2.HOGDeor(winSize,blockSize,blockStride,cellSize,nbins,derivAperture,winSigma,histogramNormType,L2HysThreshold,gammaCorrection,nlevels, useSignedGradients)
            
          

我們不打算來形容derivAperture,winSigma,histogramNormType,L2HysThreshold,伽瑪校正和NLEVELS,因為我從來沒有在使用HOG描述符來改變這些參數。除非您仔細閱讀原始HOG文件,否則我建議您使用默認值。讓我們探討其他參數的選擇。

winSize:此參數設置為20×20,因為我們的數據集中的數字圖像的大小是20×20,我們想要為整個圖像計算一個描述符。

cellSize:我們的數字是20×20灰度圖像。換句話說,我們的圖像由20×20 = 400個數字表示。描述符的大小通常遠小于圖像中的像素數。基于進行分類的重要特征的尺度來選擇cellSize。一個非常小的cellSize會炸掉特征向量的大小,而一個非常大的cellSize可能無法捕獲相關信息。您應該使用本文中共享的代碼自行測試。我們在本教程中選擇了10×10的cellSize。我們可以選擇8嗎?是的,那也行得通。

blockSize:塊的概念存在以解決照明變化。較大的塊大小使本地更改不太重要,而較小的塊大小權重本地更改更多。通常,blockSize設置為2 x cellSize,但在我們的數字分類示例中,照明并不是一個挑戰(zhàn)。在我的實驗中,10×10的blockSize給出了最好的結果。

blockStride:blockStride確定相鄰塊之間的重疊并控制對比度標準化程度。通常,blockStride設置為blockSize的50%。

nbins:nbins設置漸變直方圖中的bin數。HOG論文的作者建議使用值9來捕獲0到180度之間的漸變,以20度為增量。在我的實驗中,將此值增加到18并沒有產生任何更好的結果。

signedGradients:通常,漸變可以具有0到360度之間的任何方向。這些梯度被稱為“有符號”梯度,而不是“無符號”梯度,它們使符號下降并取0到180度之間的值。在原始HOG紙中,無符號梯度用于行人檢測。在我的實驗中,對于這個問題,簽名漸變產生了稍好的結果。

上面定義的HOG描述符可用于使用以下代碼計算圖像的HOG特征。

C++

            
              // im is of type Mat

vector
              
                 deors;

hog.compute(im,deor);
              
            
          

Python

            
              deor = hog.compute(im)
            
          

對于我們選擇的參數,該描述符的大小為81×1。

第3步:訓練模型(又稱學習分類器)

在此之前,我們已經對原始圖像進行了校正,并為我們的圖像定義了描述符。這使我們能夠將數據集中的每個圖像轉換為大小為81×1的向量。

我們現在準備訓練一個模型,對我們訓練集中的圖像進行分類。為此,我們選擇了支持向量機(SVM)作為我們的分類算法。雖然SVM背后的理論和數學涉及并超出了本教程的范圍,但它的工作原理非常直觀且易于理解。您可以查看我之前解釋線性SVM的帖子。

要快速回顧一下,如果在n維空間中有點并且類標簽附加到點,則線性SVM將使用平面劃分空間,使得不同的類位于平面的不同側。在下圖中,我們有兩個由紅色和藍色圓點表示的類。如果將此數據輸入到線性SVM中,則可以通過查找明確區(qū)分這兩個類的行來輕松構建分類器。有許多行可以分離這些數據。SVM選擇處于任一類的最大距離數據點的那個。

如何使用OpenCV進行手寫數字分類器C++/Python_第5張圖片

與我們的數字分類問題相比,上圖中顯示的兩類示例可能看起來很簡單,但在數學上它們非常相似。我們的圖像描述符不是二維空間中的點,而是81維空間中的點,因為它們由81×1向量表示。附加到這些點的類標簽是圖像中包含的數字,即0,1,2,... 9.而不是2D中的線,SVM將在高維空間中找到超平面來進行分類。

SVM參數C.

在訓練SVM時您需要了解的兩個常見參數之一稱為C.真實世界數據不像上面所示那樣干凈。有時,訓練數據可能有錯誤標記的示例。在其他時候,一組的一個例子在外觀上可能與另一個例子太接近。例如,手寫數字2可能看起來像3。

在下面的動畫中,我們創(chuàng)建了這個場景。請注意,藍點太靠近紅色簇。選擇默認值C = 1時,藍點被錯誤分類。為C選擇值100將其正確分類。

如何使用OpenCV進行手寫數字分類器C++/Python_第6張圖片

但是現在由黑線代表的決策邊界太接近其中一個類。您是否愿意選擇C為1,其中一個數據點被錯誤分類,但類之間的分離要好得多(減去一個數據點)?參數C允許您控制此權衡。

那么,你如何選擇C?我們選擇在提供的測試集上提供最佳分類的C. 該組中的圖像未用于訓練。

SVM參數Gamma:非線性SVM

你注意到了,我偷了幾次“線性”這個詞?在分類任務中,如果包含數據的空間可以使用平面(或2D中的線)進行分區(qū)以分隔類,則由多個類組成的數據集稱為線性可分。

如果數據不是線性可分的怎么辦?下圖顯示了使用紅色和藍色點的兩個類,這些點不是線性可分的。您無法在平面上繪制一條線來分隔這兩個類。使用黑線表示的良好分類器更像是一個圓圈。

如何使用OpenCV進行手寫數字分類器C++/Python_第7張圖片

在現實生活中,數據是混亂的,而不是線性可分的。

我們還可以使用SVM嗎?答案是肯定的!

為此,您使用了一種稱為Kernel Trick的技術。這是一個巧妙的技巧,可將非線性可分離數據轉換為線性可分離數據。在我們的示例中,紅色和藍色點位于2D平面上。讓我們使用以下等式為所有數據點添加第三維。

如果您聽過人們使用帶有高斯核的奇異項徑向基函數(RBF),他們只是在談論上面的等式。RBF只是一個實值函數,它僅取決于與原點的距離(即僅取決于)。的高斯核是指上式的高斯形式。更一般地,RBF可以具有不同種類的內核。你可以在這里看到其中一些。

因此,我們根據其他兩個維度中的數據制作了第三維。下圖顯示了這個三維(x,y,z)數據。我們可以看到它可以被包含黑色圓圈的平面分開!

如何使用OpenCV進行手寫數字分類器C++/Python_第8張圖片

?

參數Gamma(\伽瑪)控制第三維中的數據拉伸。它有助于分類,但也會扭曲數據。像金發(fā)姑娘一樣,你必須選擇這個參數“恰到好處”。這是人們在訓練SVM時選擇的兩個重要參數之一。

有了這些知識,我們現在準備使用OpenCV訓練SVM。

使用OpenCV訓練和測試SVM

在幕后,OpenCV使用LIBSVM。OpenCV 2.4.x中的SVM仍然使用C API。幸運的是,從3.x開始,OpenCV現在使用了更好的C ++ API。以下是在C ++和Python中使用OpenCV設置SVM的方法。

C++

            
              // Set up SVM for OpenCV 3

Ptr
              
                 svm = SVM::create();

// Set SVM type

svm->setType(SVM::C_SVC);

// Set SVM Kernel to Radial Basis Function (RBF)

svm->setKernel(SVM::RBF);

// Set parameter C

svm->setC(12.5);

// Set parameter Gamma

svm->setGamma(0.50625);

// Train SVM on training data

Ptr
                
                   td = TrainData::create(trainData, ROW_SAMPLE, trainLabels);

svm->train(td);

// Save trained model

svm->save("digits_svm_model.yml");

// Test on a held out test set

svm->predict(testMat, testResponse);
                
              
            
          

Python

            
              # Set up SVM for OpenCV 3

svm = cv2.ml.SVM_create()

# Set SVM type

svm.setType(cv2.ml.SVM_C_SVC)

# Set SVM Kernel to Radial Basis Function (RBF)

svm.setKernel(cv2.ml.SVM_RBF)

# Set parameter C

svm.setC(C)

# Set parameter Gamma

svm.setGamma(gamma)

# Train SVM on training data

svm.train(trainData, cv2.ml.ROW_SAMPLE, trainLabels)

# Save trained model

svm->save("digits_svm_model.yml");

# Test on a held out test set

testResponse = svm.predict(testData)[1].ravel()
            
          

自動訓練SVM

可以想象,選擇正確的SVM參數C和Gamma可能非常耗時。幸運的是,OpenCV 3.x C ++ API提供了一個功能,可以自動為您執(zhí)行此超參數優(yōu)化,并提供最佳的C和Gamma值。在上面的代碼中,您可以將svm-> train(td)更改為以下內容

svm->trainAuto(td);

這種訓練可能需要很長時間(比svm->訓練多5倍),因為它基本上是多次訓練。

OpenCV SVM錯誤

我們在使用OpenCV SVM時遇到了兩個錯誤。第一個是確認的,但另外兩個不是。

SVM模型不會在Python API中加載。如果您使用的是Python,您剛剛保存的訓練有素的SVM模型將無法加載!錯誤修復會來嗎?不!檢查出來這里

trainAuto似乎沒有通過Python API公開。

帶有RBF內核的SVM在iOS / Android中不起作用。很高興被證明是錯誤的,但在移動平臺(iOS / Android)上,我們無法使用受RBF內核訓練的SVM。SVM響應始終相同。線性SVM模型工作得很好。

結果

經過訓練和一些超參數優(yōu)化,我們在數字分類上達到了98.6%!不是,只需幾秒鐘的培訓就不好了。

在訓練集中的500個圖像中,有7個被錯誤分類。圖像及其錯誤分類的標簽如下所示。就像父親看著他孩子的錯誤一樣,我想說的是這些錯誤是可以理解的。

如何使用OpenCV進行手寫數字分類器C++/Python_第9張圖片

源碼地址關注微信公眾號:“ 圖像算法 ”或者微信搜索賬號 imalg_cn 關注公眾號 回復 數字分類器


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 偷拍亚洲制服另类无码专区 | 亚洲欧洲高清有无 | 日本无码免费久久久精品 | 国产一区二区在线免费观看 | 色综合色综合色综合 | 久草在线在线精品观看 | 天天躁日日躁狠狠躁中文字幕 | 成人福利在线免费观看 | 亚洲精品www | 麻豆精品视频在线 | 国产精品久久久久久久久免费 | 激情综合婷婷久久 | 免费高清成人 | 国产欧美一区二区三区在线看 | 草草浮力影视 | 中文字幕久久精品 | 91香蕉国产视频 | 天天色综合天天 | 欧美日皮视频 | 日韩大片在线永久观看视频网站免费 | 污污成人一区二区三区四区 | 欧美一级久久 | 国内精品视频在线观看 | 国产欧美综合一区二区 | 99久久久无码国产精品 | 日本三级网 | 91免费精品国偷自产在线在线 | 一区二区成人国产精品 | 窝窝午夜精品一区二区 | 狠狠狠狠狠狠狠狠狠狠 | 精品国产一区二区三区久久久 | 色插视频 | 欧美精品国产综合久久 | 午夜精品久久久久久久99热浪潮 | 国产 日韩 欧美在线 | 日韩卡1卡2 卡三卡2021老狼 | 欧美综合自拍亚洲综合网 | 国产精品美女久久久久久久久久久 | 亚洲综合婷婷 | 国产欧美一区二区三区另类精品 | 久久99精品久久久久久噜噜 |