ベイジアン研究所

プログラミング言語(アルゴリズム的な話が中心)やガジェットの紹介をしています。時々心理学の話も。

【opencv-python】k近傍法を利用した手書き数字認識

1. 記事の目的
参考文献[2]のk近傍法を使った手書き文字認識において、opencv-python 4.4.0に対応していなかったので、対応するコードを提供する。具体的には、次の2点を変更する必要がある。

  1. cv2.KNearest()をcv2.ml.KNearest_create()にする。
  2. train()関数の第2引数にcv2.ml.ROW_SAMPLEを加える。

以下のコードで場所を番号と対応づけて示す。 また、機械学習による手書き数字認識をとりあえずやってみたいと言う人にコードを提供する(自分で用意したデータセットを使うには向いていないので、試したい人向け)。

2. 実行確認済み環境
Mac OS Catalina 10.15.7
Python 3.8.5
opencv-python 4.4.0.46
numpy 1.19.1
matplotlib 3.3.1

3. 実装コード
まず、図1を"digits.png"と言う名前で、以下のコードを書いたpythonファイルと同じ場所に保存する(参考文献[2]からも入手できる)。見えにくいので参考URLで見ることをお勧めします。

f:id:camelsan:20201230162408p:plain
図1 手書き数字
実装コードを記す。

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread("./digits.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

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

x = np.array(cells)

train = x[:,:50].reshape(-1,400).astype(np.float32)
test = x[:,50:100].reshape(-1,400).astype(np.float32)

k = np.arange(10)
train_labels = np.repeat(k,250)[:,np.newaxis]
test_labels = train_labels.copy()

# 1. cv2.KNearest()をcv2.ml.KNearest_create()にする。
knn = cv2.ml.KNearest_create()   

# 2. train()関数の第2引数にcv2.ml.ROW_SAMPLEを加える。
knn.train(train, cv2.ml.ROW_SAMPLE, train_labels)
ret, result, neighbors, dist = knn.findNearest(test, k=5)

matches = result==test_labels
correct = np.count_nonzero(matches)
accuracy = correct*100.0/result.size
print(accuracy)

pythonファイルを"digits_knn.py"と言う名前にした場合、次のコマンドで実行が可能である。

python3 digits_knn.py

4. 実行結果
画面に手書き数字認識の精度が表示される。本環境で以下の数値が表示される。

91.76

5. 参考文献
[1] OpenCV-Pythonチュートリアル
k近傍法を使った手書き文字認識 — OpenCV-Python Tutorials 1 documentation
[2] OpenCV github
opencv/digits.png at master · opencv/opencv · GitHub