Category name:OpenCV应用

OCR using KNN learning with opencv(cpp version)

03/14/2014 / 13 Comments

我会说我本来写好了,然后忘了update吗?擦,都怪2048把我搞得意识模糊了。
先恭喜一下Steven,已经从burden变身大腿了。然后,替一哥惋惜一下吧。哎,我的大渔,我的备胎司机,都走远了。
OCR是Optical Character Recognition的简写,各种车牌识别,一些PDF2Word(这个是我瞎猜的)的应用都是用的这个技术,现在手头上的仪表读数识别项目也有用到这个,所以做了一些了解,现在就详细的给大家剖析一下OCR。
OCR一般包括预处理、字符分割和字符识别三部分。
先讲讲预处理,预处理包括阈值化(thresholding)、去噪(noise reduction)两部分。
何为阈值化,阈值化就是找出一个值th,把前景和背景分开。if(pix(x,y)>th)为前景,if(pix(x,y)<=th)为背景,或者反过来,if(pix(x,y) =th)为背景。何为前景,何为背景。前景就是我们care的(引用自Steven),背景就是我们不care的。在OCR中前景就是各种字符,背景就是其他的所有内容。OCR中常用的三种thresholding的方法是threshold adaptivethreshold otsu。threshold最简单,直接选取一个固定的值作为阈值来进行阈值化,这种方法最大的问题就是受光线影响较大。adaptivethreshold是一种局部的阈值化技术,一般是用来提取有多种前景,且前背景差异较大的,用来做边缘检测还不错,这种方法还有一个问题就是效率不咋地。otsu也叫大津法,是小日本发明的一种算法,很简单但是也很强大,otsu通过计算出前景和背景方差最大时的阈值来进行阈值分割,对光线和对比度的鲁棒性很好,所以一般都用这种方法来做阈值化。
去噪一般是去掉阈值化过后二值图像中的小噪点,然后对图像做一些边缘平滑处理等操作。一般都用到了腐蚀(erosion)和扩张(dilation),还有一些开操作闭操作什么的,其实也是腐蚀和扩张的组合而已。用通俗的话来讲,腐蚀就是让图像瘦一圈(去掉边缘像素),扩张就是让图像胖一圈(在边缘添加像素)。其中的原理如果想了解的话,请Google之。
字符分割技术:
字符分割技术介绍两种:
第一种叫做双向投影法,就是统计出一张图中相同x坐标和相同y坐标的像素点的个数,并投影在坐标轴上,如下图所示。我们可以看出来,在x方向的投影上,每个波峰的左边就是自负的左边界,波峰的右边就是字符的右边界。同理可以从y方向的投影中分析得出出字符的上下边界。这种方法适用于电子书中的字符分割,还有一种情况,当年李开复被微软告的时候,曾经向微软要过他以前的工作邮件,结果坑爹的微软把邮件全部转成了图片然后发给李开复的,这个时候,也可以来一发双向投影法(先用y方向投影提取出各行,然后对每行做x方向投影分割出单独的字符)。
projection
第二种其实我也忘了叫神马名字了,反正就是先用findContours找出图像中的所有轮廓,然后通过轮廓的size area height等来筛选出字符轮廓,然后再找出轮廓的boundingRect。
字符识别现在最主流的就是用ml做,ml中准确率比较高的一种是knn(k-Nearest Neighbor algorithm),另外一种是svm(Support Vector Machine)。knn的话opencv直接由实现,用起来很方便,而且效果也很不错(100% recognition accuracy)。svm据说效果更好,但是要在opencv里面用的话,还要去下一个台哥写的svm库,所以我也没试过,有兴趣的同学可以去下载下来试一下。
这一段只有做应用才会用到,同学们可以忽略这些。knn最主要的还是在模板的选取,根据我的经验来讲,选模板有点像玩我是卧底,如果你不是卧底的话,你说的话不一定要特别准确,但是一定要和卧底分开来,不然你就可能会被当成卧底。如下图所示,从左到右分别称为s1 s2 s3吧。如果我们把s2作为5的模板的话,显然是一个错误的选择,因为他和s3(6的模板)的区分度不是很大。如果我们遇到s1这样的输入,当然非常幸运,肯定会被识别成5,但是如果这个输入是和s2非常像的话,那么就很有可能被识别成6。描述的有点坑爹,我只能说,只有受过伤的人才明白其中的痛啊。
sample
有了这些就可以动手开始写代码了,程序的大致思路是这样:knn模板训练->输入图像预处理->字符分割->knn识别->输出结果。
模板链接:0123456789input
将模板下载到程序目录下,这边不知道为什么1和2的文件名不对,下载之后记得改一下。
记得在linker中加入core highgui imgproc ml等lib
代码:

如果要做文字和字母的识别原理也是一样,先这样吧,有空搞一点文字模板再更新进阶版吧。