使用 OpenCV 查找连通分量

Finding connected components using OpenCV

我正在尝试使用 python OpenCV 查找并分离边缘检测图像中的所有边缘。边缘可以是轮廓的形式,但它们不是必须的。我只想将所有连接的边缘像素组合在一起。所以从技术上讲,该算法在程序上可能听起来像这样:

  1. 对于每个边缘像素,找到一个相邻的(连接的)边缘像素并将其添加到图像的当前细分中,直到找不到为止。
  2. 然后移动到下一个未检查的边缘像素并开始新的细分并再次执行 1)。

我查看了 cv.findContours 但结果并不令人满意,可能是因为它是为轮廓(封闭的边缘)而不是自由端的轮廓设计的。以下是结果:

检测到原始边缘:

轮廓处理后:

我原以为这五个边会分别被分组到图像的自己的细分中,但显然 cv2.findContours 函数将其中的 2 个边进一步分解成我不想要的细分。

这是我用来保存这两张图片的代码:

    def contourForming(imgData):
      cv2.imshow('Edge', imgData)
      cv2.imwrite('EdgeOriginal.png', imgData)
      contours = cv2.findContours(imgData, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
      cv2.imshow('Contours', imgData)
      cv2.imwrite('AfterFindContour.png', imgData)
      cv2.waitKey(0)
      pass

但是,我的实施存在一些限制。我必须使用 Python 2.7 和 OpenCV2。除了这些,我不能使用任何其他修订版或语言。我这样说是因为我知道 OpenCV 2 有一个使用 C++ 的 connectedComponent 函数。我本可以使用它,但问题是,由于某些限制,我无法使用它。

那么,知道我应该如何解决这个问题吗?

使用findContours是正确的方法,你只是做错了。

仔细查看文档:

Note: Source image is modified by this function.

您的"After Contour Processing"图像实际上是findContours垃圾结果。因此,如果您希望原始图像在调用 findContours 后完好无损,通常的做法是将克隆图像传递给函数。

findContours 有意义的 结果在 contours 中。您需要使用 drawContours 绘制它们,通常是在新图像上。

这是我得到的结果:

使用以下 C++ 代码:

#include <opencv2/opencv.hpp>
using namespace cv;

int main(int argc, char** argv)
{
    // Load the grayscale image
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);

    // Prepare the result image, 3 channel, same size as img, all black
    Mat3b res(img.rows, img.cols, Vec3b(0,0,0));

    // Call findContours
    vector<vector<Point>> contours;
    findContours(img.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

    // Draw each contour with a random color
    for (int i = 0; i < contours.size(); ++i)
    {
        drawContours(res, contours, i, Scalar(rand() & 255, rand() & 255, rand() & 255));
    }

    // Show results
    imshow("Result", res);
    waitKey();

    return 0;
}

移植到 Python 应该相当容易(很抱歉,我不能给你 Python 代码,因为我无法测试它)。您还可以查看具体的 OpenCV - Python tutorial 以检查如何正确使用 findContoursdrawContours.