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

Posted

技术标签:

【中文标题】从图像中解析字符以进行 OCR 的算法【英文标题】:Algorithm for parsing characters from an image for OCR 【发布时间】:2013-09-19 23:37:06 【问题描述】:

我正在研究 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 步的假设是否正确?

【问题讨论】:

【参考方案1】:

我知道的一种常用的数字分割方法是滑动窗口。 基本思想是在数字图像上滑动一些大小的窗口。

滑动窗口的每次移动都会产生一个图像(您只看到窗口覆盖的像素)。滑动窗口会变窄。现在可以训练分类器,将滑动窗口映射到 1 或 0,其中 1 表示滑动窗口以 2 位分割为中心,0 表示相反。

您需要一些训练数据来训练分类器。或者您可以尝试使用无监督学习。

编辑:这个视频很有用:https://www.youtube.com/watch?v=y6ga5DeVgSY

【讨论】:

您的意思是在图像上滑动 GUI 窗口吗? 文字不好解释。请看视频,它应该能更好地解释一切。我的意思是你在图像上滑动一个“虚拟”窗口,查看图像的不同区域,然后你可以做出决定(使用一些算法,比如监督学习)图像的这个特定区域是否包含“空间" 或在数字之间拆分。 你能链接另一个视频来描述这个方法吗?链接的视频不再在 Youtube 上。【参考方案2】:

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

对我来说,你的算法似乎有点不对劲,原因如下:

1 不是从底部的第一个像素开始的,因为在 1 的顶部仍然有指向左侧的小笔划。 2 将只有几个像素高,因为您要一直向上直到找到背景像素。 由于与上述相同的参数,3 将导致仅 1 像素乘 1 像素。 等等……

我会尝试使用一种递归算法,该算法尽可能地遵循前景色像素,而无需进入背景像素。当使用带有大字符的大图像时,这可能会导致堆栈溢出,因此最好在几个 for 循环中完成这个技巧,而不是使用递归函数。

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

【讨论】:

您对 1 .. 的看法是正确的,尽管这取决于字体。有些字体会在 1.. 下方显示一条线,但仍然很好。对于 2 和 3,如果我将算法更改为在 x 轴上读取直到遇到背景(例如从 5,30 到 15,30),然后开始向上读取直到背景(例如 15,30 到 15,20) ,这可能会解决 5、2 和 3 的问题。你怎么看? 我认为“阅读直到...”的整个想法是错误的。使用递归方法。查找所有相互连接的前景像素。 但在这种情况下,我如何分辨一个数字与另一个数字的区别?不是 12345 看起来是连在一起而不是分开的吗? 既然你说你假设至少有 1 个像素的间隙,它不应该。但是,在我的浏览器中,34 呈现为连接状态。如果这是一个问题,您可以尝试通过使用字符的平均纵横比(我猜它在 2:3 的某个位置)结合字符的 n 预期宽度来实现阈值。【参考方案3】:

我没有尝试编写 OCR 软件,但我们确实使用它,而且它(或可能)变得非常复杂。

您的图片来自哪里并不完全清楚;如果它是扫描图像,那么有几个复杂性。尤其是关于您的计划,即使数字之间存在间隙,它也可能不是垂直的(非常扫描的页面不太可能是完全笔直的)。其他因素包括“斑点”——由图像或扫描仪上的污垢等引起的随机点。如果您正在处理这种图像,您几乎肯定需要研究 图像处理 技术,该技术将许多不同的数学运算应用于整个像素阵列,以执行诸如纠偏(拉直图像)之类的操作,去斑(去除随机点);边缘增强(加强从浅到深的变化以增强线条)。

根据您对“背景”和“前景”颜色的使用,您可能是在尝试对屏幕上的图像进行“OCR”处理?如果是这样(某种“屏幕抓取”过程),并且您知道(或可以接受训练)正在解释的特定字符形状,那么滑动窗口的变体可能会有所帮助:您滑动已知图像' 5' 以不同的偏移量围绕图像:如果 '5' 的所有像素都与图像中的“前景”像素匹配,那么您就知道您找到了一个 '5'。重复其他数字。如上所述,这是我们所说的“虚拟”窗口。

【讨论】:

以上是关于从图像中解析字符以进行 OCR 的算法的主要内容,如果未能解决你的问题,请参考以下文章

技术解析: 手机车牌识别软件—移动端车牌识别/OCR算法

技术解析: 手机车牌识别软件—移动端车牌识别/OCR算法

技术解析: 手机车牌识别软件—移动端车牌识别/OCR算法

Java解析truetype字体以将每个字符提取为图像及其代码

来自身份证明文件检测和 ocr 的模糊文本

名片解析器。如何从名片识别文本中提取相关信息?