8.2.2. 手書きデータセットに対する OCR 用のサポートベクターマシンの使用

SVMによる手書きデータ認識

目標

この章では

  • ただし、kNN の代わりに SVM を使用して、手書きデータの OCR を再度学習します。

手書き数字のOCR

kNN では、ピクセル強度を特徴ベクトルとして直接使用します。今回は、特徴ベクトルとして方向性勾配ヒストグラム(HOG)を使用します。

HOG を見つける前に、その 2 番目のモーメントを使用して画像を修正します。そこで、最初にデジタル画像を取得して修正する関数deskew()を定義します。これが deskew() 関数です。

def deskew(img):
    m = cv.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 = cv.warpAffine(img,M,(SZ, SZ),flags=affine_flags)
    return img

以下の図は、ゼロ画像に適用された上記の補正関数を示しています。左の画像が元の画像、右の画像が補正後の画像です。

画像
次に、各セルの HOG 記述子を見つける必要があります。これを行うには、X 方向と Y 方向の各要素のソーベル導関数を見つけます。次に、各ピクセルでその大きさと勾配の方向を見つけます。勾配は 0 ~ 16 の整数に量子化されます。この画像を 4 つのサブ正方形に分割します。各サブスクエアについて、サイズを使用して重み付けされた方向のヒストグラム (16 ビン) が計算されます。したがって、各部分正方形から 16 個の値を持つベクトルが得られます。4 つのそのようなベクトル (4 つの部分正方形) を合わせると、64 の値を持つ特徴ベクトルが得られます。これは、データのトレーニングに使用した特徴ベクトルです。
def hog(img):
    gx = cv.Sobel(img, cv.CV_32F, 1, 0)
    gy = cv.Sobel(img, cv.CV_32F, 0, 1)
    mag, ang = cv.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

最後に、前と同様に、最初に大規模なデータセットを独立したユニットに分割します。各数値について、250 ユニットがトレーニング データ用に予約され、残りの 250 ユニットはテスト用に残されます。完全なコードは次のとおりです。ここからダウンロードすることもできます。

#!/usr/bin/env python

import cv2 as cv
import numpy as np

SZ=20
bin_n = 16 # Number of bins

affine_flags = cv.WARP_INVERSE_MAP|cv.INTER_LINEAR

def deskew(img):
    m = cv.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 = cv.warpAffine(img,M,(SZ, SZ),flags=affine_flags)
    return img
    
def hog(img):
    gx = cv.Sobel(img, cv.CV_32F, 1, 0)
    gy = cv.Sobel(img, cv.CV_32F, 0, 1)
    mag, ang = cv.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 = cv.imread('digits.png',0)
if img is None:
    raise Exception("we need the digits.png image from samples/data here !")
    
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]

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

svm = cv.ml.SVM_create()
svm.setKernel(cv.ml.SVM_LINEAR)
svm.setType(cv.ml.SVM_C_SVC)
svm.setC(2.67)
svm.setGamma(5.383)

svm.train(trainData, cv.ml.ROW_SAMPLE, responses)
svm.save('svm_data.dat')

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

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

この特定のテクニックにより、ほぼ 94% の精度が得られました。SVM のさまざまなパラメータに異なる値を設定して、精度が向上するかどうかを確認してください。あるいは、その分野の技術論文を読んで実装してみることもできます。

追加のリソース

  1. 方向性のある勾配ヒストグラムのビデオ

練習する

  1. OpenCV の例には Digits.py があります。これは上記の方法をわずかに改良し、より良い結果を実現します。参考資料も掲載しています。読んで理解してください。

おすすめ

転載: blog.csdn.net/qq_33319476/article/details/130435826