Python,OpenCV使用KNN來構建手寫數字及字母識別OCR
- 1. 原理
- 1.1 手寫數字識別
- 1.2 字母識別
- 2. 原始碼
- 2.1 手寫數字OCR
- 2.2 字母OCR
- 參考
這篇博客將介紹如何借助OpenCV提供的手寫數字及字母資料集,來構建訓練KNN模型,以進行手寫數字及字母的識別,
并分別達到手寫數字 91% 的精確度,字母93%的精確度,
提升模型精確度的方法有1)增加訓練資料集以及 2)增加錯誤的資料集;
OCR 即 Optical Character Recognition 光學字符識別,表示在影像上進行文本等的識別;
1. 原理
1.1 手寫數字識別
OpenCV提供了手寫數字資料集:digits.png 共包括5000個手寫數字(0~10),每個數字500個,

- 加載資料集 digits.png(得到5000個資料集,10個標簽(0~9)
- 拆分為訓練資料集、測驗資料集(各2500個,10個標簽)
- 用訓練資料集+標簽 訓練KNN模型
- 用測驗資料集+標簽 進行KNN模型準確度的驗證;
- 存盤訓練資料集+標簽,通過使用 np.savez(‘images/knn_data.npz’, train=train, train_labels=train_labels)進行保存,
1.2 字母識別
OpenCV提供了字母資料集:letter-recognition.data ,共包括 20000行,20000個字母資料集,每行第一列是字母標簽,接下來的16個數字是從 UCI 機器學習存盤庫中獲得的字母對應的特征;

- 加載資料集 (20000個)
- 拆分為訓練資料集、測驗資料集(前10000個作為訓練資料,后10000個作為測驗資料)
- 用訓練資料集+標簽 訓練KNN模型
- 用測驗資料集+標簽 進行KNN模型準確度的驗證;
2. 原始碼
2.1 手寫數字OCR
# 構建手寫數字OCR的應用程式
#
# 需要一些 train_data 和 test_data, OpenCV 附帶一個影像digits.png,其中有 5000 個手寫數字(每個數字 500 個),每個數字都是一個 20x20 的影像,、
# 第一步是將這個影像分成 5000 個不同的數字,對于每個數字,我們將其展平為 400 像素的一行,那就是我們的特征集,即所有像素的強度值,這是我們可以創建的最簡單的功能集,
# 第二部使用每個數字的前 250 個樣本作為 train_data,剩下的250 個樣本作為 test_data
# 然后訓練資料;
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('images/digits.png') # 原始影像包括5000個不同的數字
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 分割影像為5000個單元,每個20x20像素
cells = [np.hsplit(row, 100) for row in np.vsplit(gray, 50)]
# 轉為Numpy陣列,shape將為 (50,100,20,20)
x = np.array(cells)
# 準備訓練集和測驗集
train = x[:, :50].reshape(-1, 400).astype(np.float32) # Size = (2500,400)
test = x[:, 50:100].reshape(-1, 400).astype(np.float32) # Size = (2500,400)
# 為訓練資料和測驗資料創建標簽
k = np.arange(10)
train_labels = np.repeat(k, 250)[:, np.newaxis]
test_labels = train_labels.copy()
# 初始化KNN,訓練模型,然后對測驗集使用k=1進行測驗
knn = cv2.ml.KNearest_create()
print('knn: ', knn)
knn.train(train, cv2.ml.ROW_SAMPLE, train_labels)
ret, result, neighbours, dist = knn.findNearest(test, k=5)
print("result: ", result, result.shape)
print("neighbours: ", neighbours)
print("distance: ", dist)
# 檢查分類的準確性
# 將預測分類的結果與其所屬的測驗標簽進行比較,判斷成功還是失敗
matches = result == test_labels
correct = np.count_nonzero(matches)
accuracy = correct * 100.0 / result.size
# 識別手寫數字得到了91.76% 的準確率,提高準確性的一種選擇是添加更多用于訓練的資料,尤其是錯誤的資料,
# 可以把訓練的資料/模型保存下來,這樣下次就能直接從檔案中加載資料/模型,然后進行分類,可借助Numpy函式(如 np.savetxt、np.savez、np.load 等)來保存模型
print("OCR digits accuracy: ", accuracy)
# 保存訓練資料
# 需要大約 4MB 的記憶體,由于使用強度值(uint8 資料)作為特征,因此最好先將資料轉換為 np.uint8,然后再保存,這樣只需要1MB,然后在加載時再轉換回float32,
np.savez('images/knn_data.npz', train=train, train_labels=train_labels)
# 加載
with np.load('images/knn_data.npz') as data:
print(data.files)
train = data['train']
train_labels = data['train_labels']
print(train.shape, train_labels.shape)
# 需要大約 4MB 的記憶體,由于使用強度值(uint8 資料)作為特征,因此最好先將資料轉換為 np.uint8,然后再保存,這樣只需要1MB,然后在加載時再轉換回np.float32,
np.savez('images/knn_data_npuint8.npz', train=train.astype(np.uint8), train_labels=train_labels.astype(np.uint8))
# 加載uint8的訓練資料
with np.load('images/knn_data_npuint8.npz') as data:
print(data.files)
train = data['train'].astype(np.float32)
train_labels = data['train_labels'].astype(np.float32)
print(train.shape, train_labels.shape)
2.2 字母OCR
# 構建英文字母OCR的應用程式
# 對英文字母進行OCR,但資料和特征集與手寫數字略有變化,OpenCV 沒有提供英文字母的影像,而是提供了一個資料檔案 letter-recognition.data,
# 共20000 行,每一行中第一列是一個字母表,這是標簽,接下來的 16 個數字是其不同的功能,這些功能是從 UCI 機器學習存盤庫中獲得的,您可以在此頁面中找到這些功能的詳細資訊,
# 有20000個樣本可用,因此取前10000個資料作為訓練樣本,剩下的10000個作為測驗樣本,OpenCV無法直接處理字母,因此先將字母更改為 ascii 字符,然后進行處理,
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 加載資料,并轉換字母為ASCII碼
data = np.loadtxt('images/letter-recognition.data', dtype='float32', delimiter=',',
converters={0: lambda ch: ord(ch) - ord('A')})
# 拆分資料為倆份,訓練資料,測驗資料各10000
train, test = np.vsplit(data, 2)
# 拆分訓練資料集為特征及分類
responses, trainData = np.hsplit(train, [1])
labels, testData = np.hsplit(test, [1])
# 初始化KNN,訓練模型,度量其準確性
knn = cv2.ml.KNearest_create()
knn.train(trainData, cv2.ml.ROW_SAMPLE, responses)
ret, result, neighbours, dist = knn.findNearest(testData, k=5)
print("result: ", result, result.shape)
print("neighbours: ", neighbours)
print("distance: ", dist)
correct = np.count_nonzero(result == labels)
accuracy = correct * 100.0 / 10000
# 得到了93.06%的準確度,如果要提高準確性,可以在每個級別中迭代添加錯誤資料,
print('OCR alphabet accuracy: ', accuracy)
參考
- https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.html#knn-opencv
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/292450.html
標籤:其他
上一篇:語音識別 平常筆記
