OpenCV-Python教程:53.使用SVM進(jìn)行手寫數(shù)據(jù)的OCR

手寫數(shù)字的OCR

在kNN里,我們直接使用像素亮度來作為特征向量,這次我們會(huì)使用方向梯度的直方圖(HOG)作為特征向量。

這里,在找HOG之前,我們使用圖像的二階矩模型來抗色偏。所以我們首先定義一個(gè)函數(shù)deskew()取一個(gè)數(shù)字圖像并對他抗色偏。下面是deskew()函數(shù):

def deskew(img):
? ? m = cv2.moments(img)
? ? if abs(m['mu02']) < 1e-2:
? ? ? ? return img.copy()
? ? skew = m['mu11']/m['mu02']
? ? M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])
? ? img = cv2.warpAffine(img,M,(SZ, SZ),flags=affine_flags)
? ? return img

下面的圖片顯示了上面的deskew函數(shù)應(yīng)用在數(shù)字0的圖像上。左邊的圖像是原始圖像,右邊的圖像是抗色偏之后的圖像

接著我們得找到每個(gè)單元的HOG描述子。為了這個(gè),我們找每個(gè)單元在X和Y方向的Sobel導(dǎo)數(shù)。然后找他們在每個(gè)像素的等級和方向的梯度。這個(gè)梯度是量化到16整數(shù)值得。把這個(gè)圖像分成四個(gè)子部分。對于每個(gè)子部分,計(jì)算他們級別權(quán)重的方向直方圖(16bins)。所以每個(gè)子塊給你一個(gè)包含16值得向量,4個(gè)這樣的向量(四個(gè)子塊)在一起給我們包含了64個(gè)值的特征向量。這個(gè)是我們用來訓(xùn)練我們數(shù)據(jù)的特征向量。

def hog(img):def hog(img):
? ? gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
? ? gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
? ? mag, ang = cv2.cartToPolar(gx, gy)

? ? # quantizing binvalues in (0...16)
? ? bins = np.int32(bin_n*ang/(2*np.pi))

? ? # Divide to 4 sub-squares
? ? bin_cells = bins[:10,:10], bins[10:,:10], bins[:10,10:], bins[10:,10:]
? ? mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
? ? hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
? ? hist = np.hstack(hists)
? ? return hist

最后,跟前面例子一樣,我們把我們的大數(shù)據(jù)集分割成單元,對于每個(gè)數(shù)字,250個(gè)單元來做訓(xùn)練數(shù)據(jù),剩下250個(gè)做測試,全部代碼如下:

import cv2
import numpy as np

SZ=20
bin_n = 16 # Number of bins

svm_params = dict( kernel_type = cv2.SVM_LINEAR,?svm_type = cv2.SVM_C_SVC,?C=2.67, gamma=5.383 )

affine_flags = cv2.WARP_INVERSE_MAP|cv2.INTER_LINEAR

def deskew(img):
? ? m = cv2.moments(img)
? ? if abs(m['mu02']) < 1e-2:
? ? ? ? return img.copy()
? ? skew = m['mu11']/m['mu02']
? ? M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])
? ? img = cv2.warpAffine(img,M,(SZ, SZ),flags=affine_flags)
? ? return img

def hog(img):
? ? gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
? ? gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
? ? mag, ang = cv2.cartToPolar(gx, gy)
? ? bins = np.int32(bin_n*ang/(2*np.pi))? ? # quantizing binvalues in (0...16)
? ? bin_cells = bins[:10,:10], bins[10:,:10], bins[:10,10:], bins[10:,10:]
? ? mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
? ? hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
? ? hist = np.hstack(hists)? ? # hist is a 64 bit vector
? ? return hist

img = cv2.imread('digits.png',0)

cells = [np.hsplit(row,100) for row in np.vsplit(img,50)]

# First half is trainData, remaining is testData
train_cells = [ i[:50] for i in cells ]
test_cells = [ i[50:] for i in cells]

######? ? Now training? ? ? ########################

deskewed = [map(deskew,row) for row in train_cells]
hogdata = [map(hog,row) for row in deskewed]
trainData = np.float32(hogdata).reshape(-1,64)
responses = np.float32(np.repeat(np.arange(10),250)[:,np.newaxis])

svm = cv2.SVM()
svm.train(trainData,responses, params=svm_params)
svm.save('svm_data.dat')

######? ? Now testing? ? ? ########################

deskewed = [map(deskew,row) for row in test_cells]
hogdata = [map(hog,row) for row in deskewed]
testData = np.float32(hogdata).reshape(-1,bin_n*4)
result = svm.predict_all(testData)

#######? Check Accuracy? ########################

mask = result==responses
correct = np.count_nonzero(mask)
print correct*100.0/result.size

這個(gè)技術(shù)可以給我們94%的準(zhǔn)確率,你可以嘗試不同的數(shù)據(jù)用不同的SVM參數(shù)來檢查是否可能更高準(zhǔn)確率。或者可以閱讀者個(gè)領(lǐng)域的論文來自己嘗試實(shí)現(xiàn)他們。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容