从图像中解析字符的OCR算法

3

我是一个OCR工程师,目前正在处理将每个字符从其他字符中分离的任务。例如,如果我有一张图片上写着以下文字:

12345678.90

我希望检测图像中每个数字开始和结束的 x 和 y 坐标,以便确定有多少数字需要处理,并解析出每个单独的数字/字符并进行处理。
我已经想出了一个简单的算法,并希望得到一些意见/评论,以改进它。
(在此应用程序中,我只需处理数字,但如果该算法也可以解析字母,那就更好了。)
1) 我将沿图像底部直线读取图像中的像素。例如,如果图像为 30x30,则从 0,30 到 30,30 开始读取。
2) 我将比较像素的颜色。已经确定了背景和前景颜色后,我将比较每个像素的颜色,以查看它是否在背景或前景中。
3) 如果是背景,则会忽略它。如果我遇到任何前景像素,那就表示数字的开始。在这种情况下,我会记录位置,然后开始向上读取像素。例如,如果在 5,30 检测到前景颜色,我会开始读取 5,29,5,28 等。
4) 我将向上读取像素(y 轴),直到遇到背景颜色的像素为止。这应该给我字符的高度。(我知道对于某些字符如 5,这会更加复杂,现在先忽略它们)。因此,我可以确定,例如,字符从 5,20 垂直到 5,30。
5) 然后我会回到水平开始检测字符的 x 轴(5,30)并继续水平读取以确定字符的宽度,例如 6,30、7,30 等。
6) 这是棘手的一步。我猜测,在以下字符之间每个字符之间:
12345678.90
有一个像素左右的背景色间隔。虽然我们可能看不到,但程序会逐像素水平地读取颜色,找到它。这将告诉它字符的水平结束位置。例如,它可能在 15, 30 检测到背景颜色像素。
7) 这就是算法,它应该给出每个字母开始和下一个字母开始的 x,y 坐标。在上面的示例中,字符将从 5,20 运行到 15,30,大小为 10x10。
是否可以改进此算法?我在第 6 步的假设中正确吗?
3个回答

2
常见的数字分割方法是滑动窗口。基本思路是在数字图像上滑动一个固定大小的窗口。每次滑动窗口都会产生一个新图像(只关注窗口内的像素)。滑动窗口会比较窄。现在可以训练分类器,将滑动窗口映射到1或0,其中1表示滑动窗口居中于2个数字之间的间隔,0则相反。需要一些训练数据来训练分类器,或者可以尝试使用无监督学习。编辑:这个视频可能会有用:https://www.youtube.com/watch?v=y6ga5DeVgSY

您是否字面意义上要在图像上滑动GUI窗口? - Ali
这很难用文字解释。请观看视频,它应该能更好地解释一切。我的意思是,你可以在图像上滑动一个“虚拟”窗口,查看图像的不同区域,并且你可以使用某些算法(如监督学习),决定这个图像的特定区域是否包含“空格”或数字之间的分隔符。 - kudkudak
请问您能否提供另一个视频来描述这个方法吗?之前链接的视频已经不在Youtube上了。 - steve

1
我没有尝试编写OCR软件,但我们确实使用它,而且它可能变得非常复杂。你的图像来源不是完全清楚的;如果它是一个扫描图像,那么有几个复杂因素。最重要的是,即使数字之间有间隙,它也可能不是垂直的(扫描的页面很少是完全直的)。其他因素包括“斑点”——由于图像或扫描仪上的污垢等原因引起的随机点。如果你正在处理这种类型的图像,你几乎肯定需要考虑应用许多不同的数学操作到整个像素数组的图像处理技术,以执行诸如去斜(将图像变直)、去斑(去除随机点)和增强边缘(加强从明到暗的变化以增强线条)等操作。

从您使用的“背景”和“前景”颜色来看,可能是您正在尝试从屏幕上“OCR”图像?如果是这样(一种“屏幕抓取”过程),并且您知道(或可以通过培训)被解释的特定字符形状,则滑动窗口的变体可能会有所帮助:您将已知的“5”的图像在不同的偏移量下滑动到图像周围:如果所有“5”的像素与图像中的“前景”像素匹配,则您知道找到了一个“5”。对其他数字重复此操作。与上述情况类似,我们谈论的是“虚拟”窗口。


1

免责声明:我以前从未编写过类似OCR的软件。

对我来说,您的算法似乎有些问题,原因如下:

  • 1没有从您在底部找到第一个像素的位置开始,因为您仍然有指向左侧的小笔画位于1的顶部。
  • 2只会很少几个像素高,因为您一直向上走,直到找到背景像素。
  • 3将只导致成为1像素乘1像素,由于与上述相同的参数。
  • 等等...

我会尝试使用递归算法,跟随前景色像素尽可能远地进行,而不进入背景像素。当使用具有大字符的大图像时,这可能会导致堆栈溢出,因此最好使用几个for循环来完成技巧,而不是使用递归函数。

如果您正在进行逐像素发现一个字符的过程,则可以使用该过程来创建有关字符外观的矢量信息。我认为这将是识别字符的很酷的起点。


你关于1的观点是正确的,尽管这取决于字体。有些字体会在1下面显示一条线,但是你说得很好。对于2和3,如果我将算法更改为沿x轴读取,直到遇到背景(例如从5,30到15,30),然后开始向上读取直到背景(例如15,30到15,20),那么可能会解决5、2和3的问题。你认为呢? - Ali
我认为“读取直到…”的整个想法是错误的。使用递归方法。找到所有相互连接的前景像素。 - Martijn Courteaux
但是在那种情况下,我该如何判断一个数字与另一个数字之间的分隔位置呢?12345不会全部连接在一起而不是单独的吗? - Ali
由于您说您假设至少有一个像素的间隙,所以不应该有问题。然而,在我的浏览器中,34被呈现为连接的。如果这是个问题,您可以尝试使用字符的平均宽高比(我猜它在2:3左右)来实现阈值和期望宽度的组合。 - Martijn Courteaux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接