OpenCV使用KNN完成OCR手写体识别
作者:uncle_ll 发布时间:2022-02-17 12:16:21
目标
在本章中,将学习
使用kNN来构建基本的OCR应用程
使用OpenCV自带的数字和字母数据集
手写数字的OCR
目标是构建一个可以读取手写数字的应用程序。为此,需要一些 train_data
和test_data
。OpenCV git项目中有一个图片 digits.png
(opencv/samples/data/ 中),其中包含 5000 个手写数字(每个数字500个),每个数字都是尺寸大小为 20x20
的图像。
因此,第一步是将上面这张图像分割成 5000 (500*10)个不同的数字。对于每个数字,将其展平为 400 像素的一行,这就是训练集,即所有像素的强度值。这个是可以创建的最简单的特征集合。将每个数字的前 250个样本用作训练集train_data
,然后将 250 个样本用作 测试集test_data
。
import cv2
import numpy as np
img = cv2.imread('digits.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Now we split the image to 5000 cells, each 20x20 size
cells = [np.hsplit(row, 100) for row in np.vsplit(gray, 50)]
# Make it into a numpy array: its size will be (50, 100, 20, 20)
x = np.array(cells)
# Now we prepare the training data and test data
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)
# Create labels for train and test data
k = np.arange(10)
train_labels = np.repeat(k, 250)[:, np.newaxis]
test_labels = train_labels.copy()
# Initiate kNN, train it on the training data, then test it with the test data with k=1
knn = cv2.ml.KNearest_create()
knn.train(train, cv2.ml.ROW_SAMPLE, train_labels)
ret, result, neighbours, dist = knn.findNearest(test, k=5)
# Now we check the accuracy of classification
# For that, compare the result with test_labels and check which are wrong
matches = result==test_labels
correct = np.count_nonzero(matches)
accuracy = correct * 100.0/result.size
print( accuracy ) # 91.76
可以看到,上述构建了一个基础的数字手写体OCR应用程序已准备就绪。在这个特定的例子中的准确度是91.76%。
提高准确度方法:
一种提高准确性的选择是添加更多数据进行训练,尤其是错误的数据。
另外一种是更换更优的算法
本文中,每次启动应用程序时都找不到该训练数据,不如将其保存,以便下次直接从文件中读取此数据并开始分类。可以借助一些Numpy函数(例如np.savetxt
,np.savez
,np.load
等)来完成此操作。
# Save the data
np.savez('knn_dight_data.npz', train=train, train_labels=train_labels)
# Now load the data
whit np.load('knn_data.npz') as data:
print(data.files)
train = data['train']
train_labels = data['train_labels']
在windows系统下,大约需要大约 3.82 MB 的内存。由于仅使用强度值(uint8数据)作为特征,如果需要考虑内存的问题时候,可以先将数据转换为 np.uint8
,然后再将其保存。在这种情况下,仅占用 0.98MB 。然后在加载时,可以转换回 float32
。
train_uint8 = train.astype(np.uint8)
train_labels_uint8 = train_labels.astype(np.uint8)
np.savez('knn_dight_data_int8.npz', train=train_uint8, train_labels=train_labels_uint8)
也可以用来预测单个数字
# 取测试集中的一个元素
single_data = testData[0].reshape(-1, 400)
single_label = labels[0]
ret, result, neighbours, dist = knn.findNearest(data, k=5)
print(result) # [[0]]
print(label) # [[0.]]
print(result==label) # True
英文字母的OCR
接下来,对英语字母执行相同的操作,但是数据和特征集会稍有变化。OpenCV使用文件letter-recognition.data
( /data/samples/data/letter-recognition.data)代替图像 。如果打开它,将看到20000行,乍一看可能看起来像垃圾数字。
实际上,在每一行中,第一列是字母,这是标签。接下来的16个数字是它的不同特征,这些特征是从UCI机器学习存储库获得的。可以在此页面中找到这些功能的详细信息。
现有20000个样本,将前10000个数据作为训练样本,剩余的10000个作为测试样本。字母应该更改为ASCII字符,因为不能直接使用字母。
import numpy as np
import cv2
# Load the data and convert the letters to numbers
data = np.loadtxt('letter-recognition.data', dtype='float32', delimiter=',', converters={0: lambda ch: ord(ch)-ord('A')})
# Split the dataset in two, with 10000 samples each for training and test sets
train, test = np.vsplit(data, 2)
# Split trainData and testData into features and responses
responses, trainData = np.hsplit(train, [1])
labels, testData = np.hsplit(test, [1])
# Initiate the kNN, classify, measure accuracy
knn = cv2.ml.KNearest_create()
knn.train(trainData, cv2.ml.ROW_SAMPLE, responses)
ret, result, neighbours, dist = knn.findNearest(testData, k=5)
correct = np.count_nonzero(result==labels)
accuracy = correct * 100 / result.size
print(accuracy) # 93.06
它给我的准确性为 93.06% 。同样,如果要提高准确性,则可以迭代地在每个类别中添加错误数据。
附加资源
docs.opencv.org/4.5.5/d8/d4…
archive.ics.uci.edu/ml/datasets…
en.wikipedia.org/wiki/Optica…
来源:https://juejin.cn/post/7229687757848100925


猜你喜欢
- 本文实例讲述了django框架自定义用户表操作。分享给大家供大家参考,具体如下:django中已经给我生成默认的User表,其中的字段已经可
- 在Golang中,如何将一个结构体转成map? 本文介绍两种方法。第一种是是使用json包解析解码编码。第二种是使用反射,使用反射的效率比较
- 无参数函数先解释一下时间戳,所谓时间戳,即自1970年1月1日00:00:00所经历的秒数,然后就可以理解下面的函数了。下面代码默认from
- 1. 关闭mysql服务# service mysqld stop2. 检查是否有rpm包,如果没有用rpm安装过mysql,不应该有残留,
- Python2默认是不支持中文的,一般我们在程序的开头加上#-*-coding:utf-8-*-来解决这个问题,但是在我用open()方法打
- 尽管甲骨文收购Sun交易尚在等待最终结果,业界对开源数据库MySQL的未来命运也十分担忧,但Sun的开发者依然在继续努力研发该开源数据库。他
- 一、序列:序列是基类类型,序列扩展类型包括:字符串、元组和列表序列都可以进行的操作包括索引,切片,加,乘,检查成员。此外,Python已经内
- 1、运算概念的理解运算(Operation)是操作逻辑的抽象运算体现一种操作逻辑,在广义角度来说任何程序都是一种运算Python解释器通过保
- 前言A货:什么!你不会背圆周率(鄙夷的眼神) 3.1415926535 8979323846 26433... 桥哥:我会算呀 !
- 这篇文章主要介绍了Python监控服务器实用工具psutil使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习
- 本文实例讲述了python实现堆栈与队列的方法。分享给大家供大家参考。具体分析如下:1、python实现堆栈,可先将Stack类写入文件st
- 简介procedure analyse()函数是MySQL内置的对MySQL字段值进行统计分析后给出建议的字段类型。语法procesure
- 最近有Win10系统用户反映,由于自己的电脑安装有两个python软件,所以想要卸载掉其中一个,不过在卸载的时候却发现无法卸载,并且出现提示
- SQL Server 2008我们也能从中体验到很多新的特性,但是对于SQL Server 2008安装,还是用图来说话比较好。本文将从SQ
- 数据库事务隔离级别数据库事务的隔离级别有4个,由低到高依次为Read uncommitted:允许脏读。Read committed: 防止
- 通过观察执行计划,发现之前的执行计划在很多大表连接的部分使用了Hash Join,由于涉及的表中数据众多,因此查询优化器选择使用并行执行,速
- /* Cookie Library -- "Night of the Living Cookie" Version (2
- 一、Hive介绍hive: 由 Facebook 开源用于解决海量结构化日志的数据统计工具。Hive 是基于 Hadoop 的一个数据仓库工
- 搜索答案搜索不到,自己试了一把.首先生成一维数组a =np.array([1,2,3,4,5,6,7,8,9])>>> p
- 在学习和使用各种数据库的过程中,我们常常会遇到聚族索引、非聚族索引、组合索引的概念,这些索引对我们使用数据库,特别是查询的速度的