在OpenCV中寻找轮廓?

18
当您从图像中检索轮廓时,每个斑点应该得到两个轮廓——一个内部轮廓和一个外部轮廓。考虑下面的圆——由于圆是一条宽度大于1像素的线,因此您应该能够在图像中找到两个轮廓——一个来自圆的内部,一个来自圆的外部。
使用OpenCV,我想检索内部轮廓。然而,当我使用findContours()时,似乎只得到了外部轮廓。如何使用OpenCV检索斑点的内部轮廓?
我正在使用C++ API,而不是C,因此只建议使用使用C++ API的函数(即findContours()而不是cvFindContours())。
谢谢。

enter image description here


嗯,我没有什么独特的代码。我只是从相机中检索到一个Mat。我在它上面运行Canny边缘检测器,然后使用findContours()找到轮廓。所有找到的轮廓都存储在vector<vector<Point>>中。基本上这就是我所拥有的,所以没有必要发布实际的代码 - 它只是传统的轮廓查找过程。 - fdh
我稍微使用过轮廓,但我只对外部轮廓感兴趣。我尝试着用'drawContours()'给轮廓上色,但需要一种层次结构。我使用的'drawContours()'示例没有给内部轮廓上色。我的意思是,您可能需要使用'findContours()'中的层次数组来对它们进行排序。(我不发表答案的原因是,我对这种层次结构的了解有限,我不想在这个问题上让您困惑。我已经对它们进行了一些测试,如果您需要,我可以解释一下我的理解。) - Sonaten
谢谢回答。 如果可能的话,我会很感激您能解释一下您对层次结构的理解。谢谢。 - fdh
可以使用存储轮廓的CvSeq*结构中的h_next和v_next指针访问外部和内部边界轮廓,这些轮廓是由findContours()函数组织的。这里有一本关于如何组织它的书籍链接(我通常只处理外部轮廓,因此没有任何可发布的工作代码):http://books.google.co.in/books?id=seAgiOfu2EIC&lpg=PA243&dq=Learning%20OpenCV%20findcontours&pg=PA237#v=onepage&q&f=false - AruniRC
我正在使用C++ API而不是C,因此我没有使用CvSeq。我正在使用vector<vector<Point>>。 - fdh
3个回答

34
我运行了您的图像代码,返回了内轮廓和外轮廓。
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

int main(int argc, const char * argv[]) {

    cv::Mat image= cv::imread("../../so8449378.jpg");
    if (!image.data) {
        std::cout << "Image file not found\n";
        return 1;
    }

    //Prepare the image for findContours
    cv::cvtColor(image, image, CV_BGR2GRAY);
    cv::threshold(image, image, 128, 255, CV_THRESH_BINARY);

    //Find the contours. Use the contourOutput Mat so the original image doesn't get overwritten
    std::vector<std::vector<cv::Point> > contours;
    cv::Mat contourOutput = image.clone();
    cv::findContours( contourOutput, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE );

    //Draw the contours
    cv::Mat contourImage(image.size(), CV_8UC3, cv::Scalar(0,0,0));
    cv::Scalar colors[3];
    colors[0] = cv::Scalar(255, 0, 0);
    colors[1] = cv::Scalar(0, 255, 0);
    colors[2] = cv::Scalar(0, 0, 255);
    for (size_t idx = 0; idx < contours.size(); idx++) {
        cv::drawContours(contourImage, contours, idx, colors[idx % 3]);
    }

    cv::imshow("Input Image", image);
    cvMoveWindow("Input Image", 0, 0);
    cv::imshow("Contours", contourImage);
    cvMoveWindow("Contours", 200, 0);
    cv::waitKey(0);

    return 0;
}

这是它发现的轮廓: findContour result image

谢谢。您是否知道如何仅访问内部轮廓?就像孔的边界一样? - fdh
2
如果您将模式设置为CV_RETR_TREE而不是CV_RETR_LIST,则会得到轮廓的分层树形结构,因此内部轮廓将位于外部轮廓下方。它不区分内部和外部轮廓,因此如果圆圈内有一个圆圈,则这两个轮廓都将位于外圆的内部轮廓下方。OpenCV findContour教程使用CV_RETR_TREE - SSteve

3

我认为Farhad所问的是从原始图像中裁剪轮廓。

要做到这一点,您需要按照上述说明找到轮廓,然后使用掩码获取原始图像内部,然后将结果裁剪成与轮廓相同大小的图像。


0

findcontours函数会将所有轮廓存储在不同的向量中,在给定的代码中,所有轮廓都被绘制出来了,你只需要绘制所对应的内部轮廓,idx是指示哪个轮廓被绘制的变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接