我正在编写一个 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);
高斯模糊对于在阈值化之前减少噪声是必要的。膨胀是为了确保外部网格线已连接,但不足以重新连接内部线。
我怎样才能始终如一地删除内部网格线,而不影响图像的其余部分?
非常感谢。