好吧,我决定在我的问题上锻炼自己来解决上面的问题。我想要的是在OpenCV中使用KNearest或SVM特征实现一个简单的OCR。下面是我做了什么以及怎么做的。(它只是为了学习如何使用KNearest来实现简单的OCR目的)。
我的第一个问题是关于字母识别的。OpenCV样本附带的数据文件。我想知道那份文件里有什么。
它包含了一封信,以及这封信的16个特征。
这个特种部队帮我找到了它。这16个特征在论文“使用荷兰风格自适应分类器的字母识别”中进行了解释。
(虽然最后我看不懂其中的一些特点)
2)因为我知道,如果不了解所有这些特征,很难做到这个方法。我试了一些其他的试卷,但对初学者来说都有点难。
所以我决定把所有像素值作为我的特征。(我不担心精度或性能,我只是想让它工作,至少以最低的精度)
我将下图作为我的训练数据:
(我知道训练数据量比较少。但是,因为所有的字母都是相同的字体和大小,我决定试试这个)。
为了准备训练所需的数据,我在OpenCV中编写了一小段代码。它做以下事情:
It loads the image.
Selects the digits (obviously by contour finding and applying constraints on area and height of letters to avoid false detections).
Draws the bounding rectangle around one letter and wait for key press manually. This time we press the digit key ourselves corresponding to the letter in the box.
Once the corresponding digit key is pressed, it resizes this box to 10x10 and saves all 100 pixel values in an array (here, samples) and corresponding manually entered digit in another array(here, responses).
Then save both the arrays in separate .txt files.
在数字手工分类的最后,训练数据(train.png)中的所有数字都是我们自己手工标注的,图像如下所示:
下面是我用于上述目的的代码(当然,不那么干净):
import sys
import numpy as np
import cv2
im = cv2.imread('pitrain.png')
im3 = im.copy()
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(5,5),0)
thresh = cv2.adaptiveThreshold(blur,255,1,1,11,2)
################# Now finding Contours ###################
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
samples = np.empty((0,100))
responses = []
keys = [i for i in range(48,58)]
for cnt in contours:
if cv2.contourArea(cnt)>50:
[x,y,w,h] = cv2.boundingRect(cnt)
if h>28:
cv2.rectangle(im,(x,y),(x+w,y+h),(0,0,255),2)
roi = thresh[y:y+h,x:x+w]
roismall = cv2.resize(roi,(10,10))
cv2.imshow('norm',im)
key = cv2.waitKey(0)
if key == 27: # (escape to quit)
sys.exit()
elif key in keys:
responses.append(int(chr(key)))
sample = roismall.reshape((1,100))
samples = np.append(samples,sample,0)
responses = np.array(responses,np.float32)
responses = responses.reshape((responses.size,1))
print "training complete"
np.savetxt('generalsamples.data',samples)
np.savetxt('generalresponses.data',responses)
现在我们进入训练和测试部分。
对于测试部分,我使用了下面的图像,它具有与训练阶段相同的字母类型。
对于培训,我们的做法如下:
加载我们之前已经保存的.txt文件
创建一个我们正在使用的分类器的实例(在本例中是KNearest)
然后我们使用KNearest。训练函数用于训练数据
出于测试目的,我们采取如下措施:
我们加载用于测试的图像
对图像进行处理,使用轮廓法提取每个数字
为其绘制一个边界框,然后将其大小调整为10x10,并将其像素值存储在前面所做的数组中。
然后使用kneare .find_nearest()函数查找与给定值最近的项。(如果幸运的话,它能识别正确的数字。)
我在下面的代码中包含了最后两个步骤(训练和测试):
import cv2
import numpy as np
####### training part ###############
samples = np.loadtxt('generalsamples.data',np.float32)
responses = np.loadtxt('generalresponses.data',np.float32)
responses = responses.reshape((responses.size,1))
model = cv2.KNearest()
model.train(samples,responses)
############################# testing part #########################
im = cv2.imread('pi.png')
out = np.zeros(im.shape,np.uint8)
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray,255,1,1,11,2)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
if cv2.contourArea(cnt)>50:
[x,y,w,h] = cv2.boundingRect(cnt)
if h>28:
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
roi = thresh[y:y+h,x:x+w]
roismall = cv2.resize(roi,(10,10))
roismall = roismall.reshape((1,100))
roismall = np.float32(roismall)
retval, results, neigh_resp, dists = model.find_nearest(roismall, k = 1)
string = str(int((results[0][0])))
cv2.putText(out,string,(x,y+h),0,1,(0,255,0))
cv2.imshow('im',im)
cv2.imshow('out',out)
cv2.waitKey(0)
它是有效的,下面是我得到的结果:
在这里,它的准确率是100%。我认为这是因为所有的数字都是相同的类型和大小。
但无论如何,这对初学者来说是一个很好的开始(我希望如此)。