Python,OpenCV使用KNN来构建手写数字及字母识别OCR

Posted 程序媛一枚~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python,OpenCV使用KNN来构建手写数字及字母识别OCR相关的知识,希望对你有一定的参考价值。

Python,OpenCV使用KNN来构建手写数字及字母识别OCR

这篇博客将介绍如何借助OpenCV提供的手写数字及字母数据集,来构建训练KNN模型,以进行手写数字及字母的识别。
并分别达到手写数字 91% 的精确度,字母93%的精确度。

提升模型精确度的方法有1)增加训练数据集以及 2)增加错误的数据集;

OCR 即 Optical Character Recognition 光学字符识别,表示在图像上进行文本等的识别;

1. 原理

1.1 手写数字识别

OpenCV提供了手写数字数据集:digits.png 共包括5000个手写数字(0~10),每个数字500个。

  1. 加载数据集 digits.png(得到5000个数据集,10个标签(0~9)
  2. 拆分为训练数据集、测试数据集(各2500个,10个标签)
  3. 用训练数据集+标签 训练KNN模型
  4. 用测试数据集+标签 进行KNN模型准确度的验证;
  5. 存储训练数据集+标签,通过使用 np.savez(‘images/knn_data.npz’, train=train, train_labels=train_labels)进行保存。

1.2 字母识别

OpenCV提供了字母数据集:letter-recognition.data ,共包括 20000行,20000个字母数据集,每行第一列是字母标签,接下来的16个数字是从 UCI 机器学习存储库中获得的字母对应的特征;

  1. 加载数据集 (20000个)
  2. 拆分为训练数据集、测试数据集(前10000个作为训练数据,后10000个作为测试数据)
  3. 用训练数据集+标签 训练KNN模型
  4. 用测试数据集+标签 进行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)

参考

以上是关于Python,OpenCV使用KNN来构建手写数字及字母识别OCR的主要内容,如果未能解决你的问题,请参考以下文章

opencv实现KNN手写数字的识别

基于OpenCV的KNN算法实现手写数字识别

基于OpenCV的KNN算法实现手写数字识别

Python,OpenCV基于支持向量机SVM的手写数字OCR

[3] python:使用KNN识别手写数字

python实现KNN,识别手写数字