【问题标题】:Disconnected contours after adaptive threshold自适应阈值后断开的轮廓
【发布时间】:2013-08-15 20:25:52
【问题描述】:

我想使用来自 OpenCV 的 findContours() 自适应地设置此图像的阈值以找到外边界。我使用自适应阈值的原因通常是:全局阈值,即使使用 Otsu 的方法,也不能充分补偿图像不同部分之间的亮度差异。

不幸的是,自适应阈值处理会在某些具有粗网格线的交叉点处产生破损。这是因为,对于交叉点处的像素,粗网格线占据了太多周围区域,以至于局部阈值高于交叉点处像素的(仅中等暗)值。令人惊讶的是,即使对于较大的阈值窗口,这种效果在某种程度上仍然存在。

当然,这使得自适应阈值无法用于在这些类型的图像中寻找轮廓。然而,在提出连接边方面,它仍然比其他算法(如 Canny)要好得多。

通过手动填充图像中的所有一像素和二像素间隙,我已经能够在自适应阈值处理后重新连接边缘(实际上,我在按比例缩小的图像上设置阈值以节省运行时间;间隙更大上面的全尺寸图像)。这是我使用的 OpenCV 代码(为 Android 绑定编写的)。 0 为黑色,-1 为白色。

private void fillGaps(Mat image) {

    int size = image.rows() * image.cols();
    byte[] src = new byte[size], dst = new byte[size];
    image.get(0, 0, src);

    int c = image.cols();
    int start = 2 * c + 2;
    int end = size - start;
    for (int i = start; i < end; i++) {
        if (src[i+1] == -1 && src[i-1] == -1 || src[i+c] == -1 && src[i-c] ==-1){
            // 1-pixel gap
            dst[i] = -1;
        } else if (src[i+1] == 0 && src[i+2  ] == -1 && src[i-1] == -1) {
            // 2-pixel horizontal gap
            dst[i] = -1; dst[i+1] = -1;
        } else if (src[i+c] == 0 && src[i+2*c] == -1 && src[i-c] == -1) { 
            // 2-pixel vertical gap
            dst[i] = -1; dst[i+c] = -1;
        }
    }

    image.put(0, 0, dst);
}

以下是填空前后的缩小图:

虽然这在这里工作得很好,但它是一种粗略的技术,不能填补所有的空白,有时还会将网格与其他附近的轮廓连接起来。

在自适应阈值后避免轮廓断开的可靠方法是什么?

【问题讨论】:

标签: opencv image-processing edge-detection threshold adaptive-threshold


【解决方案1】:

您采用的自适应阈值方法没问题,但下一步您应该进行一些形态学操作:腐蚀、膨胀、打开、关闭。 对于您的特定案例关闭操作将是合适的。
还有 Open-CV 内置方法 cvDilate 和 cvErode。结构元素的形状无关紧要,但要保持较小的尺寸。

我看到了您填补空白的实施。在那里你没有考虑对角线元素。最好在每个像素周围设置一个 3x3 或 5x5 的窗口并比较每个元素,然后再决定结果。

counter=0;
for (int k=i-radius; k<=i+radius; k++)
{
  for (int l=j-radius; l<=j+radius; l++)
  {
    if (src[k][l] == -1)
    counter++;
  }
}

if (counter > 0)
  dest[k][l] = -1;
else
  dest[k][l] = 0;

这是我用于扩张(或填补空白)的示例代码。半径可以是 1 (3x3) 或 2(5x5)。

【讨论】:

  • 你说得对:用小窗口(3x3 矩形)关闭是最好的选择。我故意不考虑对角线元素,因为我假设了垂直和水平网格,但是关闭足够小心,也可以包含对角线。
  • 抱歉,圆形窗口实际上效果更好。我用Imgproc.morphologyEx(image, image, Imgproc.MORPH_CLOSE, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(3,3)));
  • 是的,圆形窗口提供了更好的边界,因为计算这样一个窗口的复杂性增加了(手动实现),我没有使用它...稍后会尝试这个。
【解决方案2】:

在adaptiveThreshold之后尝试扩张图像。

【讨论】:

    猜你喜欢
    • 2021-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-23
    • 1970-01-01
    • 2018-04-04
    • 2014-04-03
    • 1970-01-01
    相关资源
    最近更新 更多