我正在 Android 平台上创建数独解决应用程序,但在处理图像时遇到了问题。我正在尝试使用 Sobel 过滤器使用 OpenCV 找到拼图的水平线,然后使用 Otsu 算法进行阈值处理:
Mat kernaly = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,2));
Mat dy = new Mat();
Mat close = new Mat();
Imgproc.Sobel(img, dy, CvType.CV_16S, 0, 2);
Core.convertScaleAbs(dy, dy);
Core.normalize(dy,dy,0,255,Core.NORM_MINMAX);
Imgproc.threshold(dy, close, 0, 255, Imgproc.THRESH_BINARY|Imgproc.THRESH_OTSU);
Imgproc.morphologyEx(close, close, Imgproc.MORPH_DILATE, kernaly);
这个方法其实对大多数图片都适用,例如:
但是,对于下面的图片,它失败了:
有人可以解释为什么结果差异如此之大,而上面的第二张图片只返回一行吗? 另外,我是否应该改用其他方法,例如 Canny 或 Hough 线?
提前致谢!
编辑: 根据 marol 的建议,我尝试在不扭曲图像的情况下尽可能多地移除黑色边框。这是将上述相同过程应用于这些重新处理的图像时的结果。
图 1:
图 2:
如您所见,结果更好,因为已检测到大多数线条。然而,它仍然不够好。可以通过添加固定阈值来改进,但每个图像的阈值必须不同。
我可能会使用一种新方法,因为这种方法似乎不够稳健。任何提示将不胜感激。
最佳答案
问题可能是由于强度分布引起的。如果您查看 sobel 运算符后的直方图:
将其与成功检测到 otsu 的图像直方图进行比较:
您可以很容易地在第一个直方图中看到失败,因为计算的阈值向右移动而不是向左移动(即使左侧的主峰突出所有黑色像素)。在第二种情况下,分布并没有那么分为峰值和平坦其余部分,而不是我们有更多的白色像素“携带”计算阈值到右边的情况。
换句话说,你必须摆脱黑色像素的支配。换句话说,尝试缩放数独,使周围的黑色像素边框尽可能小。这将使分发更像第二种情况。
恕我直言,根据这些直方图,您可以说该方法非常敏感,因为图像中“黑色”和“白色”部分之间的差异,因此计算的阈值水平 对图像非常敏感。我不会依赖这种方法。一些固定的阈值水平呢?这在一般情况下可能听起来不太好,但在这里它可能更确定并且仍然正确。
关于opencv - Sobel 滤波图像上的 Otsu 阈值处理给出不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25202260/