3

我正在研究一个 OCR 算法,它给出了一个包含一些数字的图像。我希望它简单地检测每个图像,并将其与其他图像分开。

它适用于 0-9 的所有数字,除了数字 4,这给我带来了很多麻烦。

这是我的源图像:

源图像

这是解析它的一些数字的结果:

0 1 2 2 5 6 7 8 9 .

正如你所看到的,它们都被完美地解析了。唯一给我带来麻烦的是4。这是数字4的样子:

4

我遇到的问题是检测 4 的最左角,以便包括整个数字。这是我的算法在尝试检测每个字符的左边界时向下遍历的方式(蓝点表示算法采用的路径):

算法采用的路径

如果您在另一个选项卡中打开图像并放大,您可能会更好地看到它在做什么。

如您所见,它向下和向左移动,直到两次遇到背景。当它发生时,这意味着已经到达图像的最左侧边界。它适用于所有其他图像,除了 4,您可以看到它遇到背景两次并停止,但如果它继续向下再向下两个像素,那么它将遇到更多的 4 并会找到它真正的左-最边缘。

我不确定如何以不会破坏其他数字的方式做到这一点。这是我的实际代码以防万一:

    int misses = 0;
    int maxMisses = 2;
    while (y < image.getHeight() && x >= 0 )
    {
        markPixel(x, y);
        color = image.getRGB(x, y);
        if (! reader.isForeground(color))
            misses++;

        if (misses < maxMisses)
        {
            y++;
            x--;
            continue;
        }
        x++;
        break;
    }        
    if (x < 0)
        x = 0;
    return x;

编辑:我已经能够通过一直遍历图像而不是在遇到 2 个背景像素时停下来实现一些改进,当我遇到前景像素时存储每一步的 x 坐标,然后按升序对匹配进行排序并返回他们的最低结果。它工作得更好一些。新 4 图像:

新4

它还不完美。此外,9 看起来有点小:

新9

算法遍历的新路径:

新路径

更新代码:

    ArrayList<Integer> matches = new ArrayList<>();
    int yB = y;
    for (int i = 1; i <= 2; i++)
    {
        y = yB;
        while (y < image.getHeight() && x >= 0 )
        {
            markPixel(x, y);
            color = image.getRGB(x, y);
            if ( reader.isForeground(color))
                matches.add(x);

            y++;                
        }      
        x--;
    }

    Collections.sort(matches);
    return matches.get(0);

有人有什么想法可以从 4 中找出最后一个缺陷吗?

4

3 回答 3

1

为什么不沿着图像轮廓顺时针走,直到你一直回到(或足够接近)你遇到第一个黑点的位置?

一个简单的最小/最大跟踪变量对将在您遍历路径时自然地为数字图像提供矩形。这也可以独立于使用的字体,只要字符不包含多个岛(想想字母 i)并且不相互重叠/连接。

编辑:TC 提到填充字形的洪水。我认为这是一个绝妙的主意,甚至比我上面的方法还要好。

只需找到第一个黑色像素,然后以该像素为起点运行填充填充 - 如果实现将像素复制到单独的图像中,则它选择填充的每个像素甚至可以解决,如果字体字距调整使相邻字形具有重叠边界矩形(这可能需要两次通过来实现,第一次找到边界矩形,第二次实际复制像素)。

于 2013-09-20T15:43:17.877 回答
1

根据我的评论改编,这似乎是对您发布的算法进行最小修改的方法:

检查下一个像素时,不要同时向下和向左移动,而是单独检查它们。如果 lefter(?) 和 lower 像素都未命中,则只是未命中。这将有助于任何超过 45 度坡度的角度,如果您更改字体等,您可能会遇到这种情况。


然而,

如果你愿意改变你的算法,我认为其他答案最终可能会更强大。

  • 来自 Durandal 的回答:围绕数字绕一圈,跟踪最小 x/y 和最大 x/y。要获得左下角,它是min x, max y,假设原点在左上角。我看到你在这里遇到的唯一问题是岛(ij)或非常斜体的字体,字符可能在 x 方向上重叠。

  • 来自 user2399923 的评论:查找空列来划分字符也很有效。它不会受到岛屿的影响,但会受到上面提到的极端斜体情况的影响,因为在这种情况下可能没有列。

  • 来自blgt的回答:我认为洪水填充方法也很好,而且是标准。它需要适应岛屿,但不会受到斜体的影响,除非角色实际上是接触的。数字中是否存在“漏洞”(例如 )并不重要,8因为您只对淹没区域的最小/最大 x/y 值感兴趣。根据定义,这些点都不是洞。

于 2013-09-20T16:55:52.903 回答
1

做你描述的最简单的方法是填充图像。适用于分离任何不相交的字符(即,对于“i”、“j”等不能开箱即用,但适应它并不难)

你所描述的听起来更复杂。当已经有解决方案时,您不需要重新发明轮子。

链接-> http://en.wikipedia.org/wiki/Flood_fill

于 2013-09-20T16:00:17.367 回答