使用 kNN 对手写数字 OCR

使用 kNN 对手写数字 OCR

目标
  • 要根据我们掌握的 kNN 知识创建一个基本的 OCR 程序
  • 使用 OpenCV 自带的手写数字和字母数据测试我们的程序

手写数字的 OCR
  我们的目的是创建一个可以对手写数字进行识别的程序。为了达到这个目的我们需要训练数据和测试数据。OpenCV 安装包中有一副图片(/samples/python2/data/digits.png), 其中有 5000 个手写数字(每个数字重复 500遍)。每个数字是一个 20x20 的小图。所以第一步就是将这个图像分割成 5000个不同的数字。我们在将拆分后的每一个数字的图像重排成一行含有 400 个像素点的新图像。这个就是我们的特征集,所有像素的灰度值。这是我们能创建的最简单的特征集。我们使用每个数字的前 250 个样本做训练数据,剩余的250 个做测试数据。让我们先准备一下:

# -*- coding: utf-8 -*-
"""
Created on Tue Jan 28 20:20:47 2014
@author: duan
"""
import numpy as np
import cv2
from matplotlib import pyplot as plt
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. It size will be (50,100,20,20)
x = np.array(cells)
# Now we prepare train_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 the data, then test it with test data for k=1
knn = cv2.KNearest()
knn.train(train,train_labels)
ret,result,neighbours,dist = knn.find_nearest(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

现在最基本的 OCR 程序已经准备好了,这个示例中我们得到的准确率为91%。改善准确度的一个办法是提供更多的训练数据,尤其是判断错误的那些数字。为了避免每次运行程序都要准备和训练分类器,我们最好把它保留,这样在下次运行是时,只需要从文件中读取这些数据开始进行分类就可以了。Numpy 函数 np.savetxt,np.load 等可以帮助我们搞定这些。

np.savez('knn_data.npz',train=train, train_labels=train_labels)
# Now load the data
with np.load('knn_data.npz') as data:
print data.files
train = data['train']
train_labels = data['train_labels']

在我的系统中,占用的空间大概为 4.4M。由于我们现在使用灰度值(unint8)作为特征,在保存之前最好先把这些数据装换成 np.uint8 格式,这样就只需要占用 1.1M 的空间。在加载数据时再转会到 float32。
  
英文字母的 OCR
  接下来我们来做英文字母的 OCR。和上面做法一样,但是数据和特征集有一些不同。现在 OpenCV 给出的不是图片了,而是一个数据文件(/samples/cpp/letter-recognition.data)。如果打开它的话,你会发现它有 20000 行,第一样看上去就像是垃圾。实际上每一行的第一列是我们的一个字母标记。接下来的 16 个数字是它的不同特征。这些特征来源于UCI Machine Learning Repository。你可以在此页找到更多相关信息。
  有 20000 个样本可以使用,我们取前 10000 个作为训练样本,剩下的10000 个作为测试样本。我们应在先把字母表转换成 asc 码,因为我们不正直接处理字母。

# -*- coding: utf-8 -*-
"""
Created on Tue Jan 28 20:21:32 2014
@author: duan
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Load the data, converters convert the letter to a number
data= np.loadtxt('letter-recognition.data', dtype= 'float32', delimiter = ',',
converters= {
    
    0: lambda ch: ord(ch)-ord('A')})
# split the data to two, 10000 each for train and test
train, test = np.vsplit(data,2)
# split trainData and testData to features and responses
responses, trainData = np.hsplit(train,[1])
labels, testData = np.hsplit(test,[1])
# Initiate the kNN, classify, measure accuracy.
knn = cv2.KNearest()
knn.train(trainData, responses)
ret, result, neighbours, dist = knn.find_nearest(testData, k=5)
correct = np.count_nonzero(result == labels)
accuracy = correct*100.0/10000
print accuracy

准确率达到了 93.22%。同样你可以通过增加训练样本的数量来提高准确率。

猜你喜欢

转载自blog.csdn.net/yyyyyya_/article/details/125926900