3

我正在编写一个 Android 应用程序来从图片中提取数独谜题。对于 9x9 数独网格中的每个单元格,我需要确定它是否包含数字 1 到 9 之一或是否为空白。以下是我的算法的大致思路:

  • 自适应阈值之谜
  • 扩张以减少要考虑的轮廓数量
  • 找到拼图的轮廓并将其变形为正方形
  • 将正方形分成 81 个相等的单元格;寻找至少有 20% 白色像素的单元格
  • 找到最靠近这些单元格中心的白色斑点并得到它的边界矩形
  • 对边界矩形内的图像部分使用字符识别(k-nearest neighbours/Tesseract/etc.)

虽然我可以使用简单的填充来移除数独谜题的粗外边界,但内部网格线并不连续,即使在膨胀之后也是如此,并且不能那么容易地移除。为了说明,这里是去除外部网格线后的示例数独:

在此处输入图像描述

问题:有时,一个单元格中有足够的网格线,超过 20% 的像素是白色的,所以我误认为该单元格中有一个数字。以下是此类单元格的示例:

在此处输入图像描述

我考虑过使图像变形以降低内部网格线的可见性。我可以使用霍夫变换或这篇文章中描述的方法来找到网格线作为展开的前奏。但是,我没有看到展开变形的任何其他显着好处,并且完全删除网格线应该既安全又容易。

或者,我可以修改我的预处理,以便内部网格线保持不变。目前我的预处理是:

    Imgproc.GaussianBlur(mat, mat, new Size(11,11), 0);
    Imgproc.adaptiveThreshold(mat, matBW, 255, 
        Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 5, 2);
    Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_CROSS, new Size(3, 3));
    Imgproc.dilate(matBW, matBW, kernel);

高斯模糊对于在阈值化之前减少噪声是必要的。膨胀是为了确保外部网格线已连接,但不足以重新连接内部线。

我怎样才能始终如一地删除内部网格线,而不影响图像的其余部分?

非常感谢。

4

1 回答 1

2

如果您不想进行适当的 unwarp,则可能值得使用较小的单元格进行 digit_present 测试。

假设左上角的单元格具有坐标 (x1,y1,x2,y1)==(0,0,10,10)。您可以将新单元格定义为 (x1+k,y1+k,x2-k,y2-k), k=min(x2-x1,y2-y1)/4

另一种可能有效的策略是在测试前使用腐蚀,具体取决于网格线与数字的粗细。

最后,您可以将所有单元格提供给您的分类器,并使用其置信度索引(如果有);如果分类器置信度太低,则可能不是数字。

如果所有这些方法都失败了,为了进行填充,无论如何你都必须获得网格线的翘曲,所以你不妨进行反翘曲

于 2012-11-08T03:40:41.673 回答