我想自适应地对该图像进行阈值化,以使用findContours()
OpenCV 找到外边界。我使用自适应阈值的原因通常是:全局阈值,即使使用 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);
}
这是填充间隙之前和之后的缩小图像:
虽然这在这里工作得很好,但它是一种粗略的技术,不能填补所有的空白,有时还会将网格与其他附近的轮廓连接起来。
在自适应阈值之后避免断开轮廓的可靠方法是什么?