【问题标题】:Contour selection in opencvopencv中的轮廓选择
【发布时间】:2016-06-29 05:42:02
【问题描述】:

我有一个源图像

我已经应用了一个合适的阈值并得到了这个

现在我使用轮廓来找到内部的黑色斑点。我用绿色表示外边界,用红色表示内边界。这就是我得到的:-

我已经使用红色提取了斑点。但我只想提取那些里面没有绿色的东西,或者至少只给那些里面没有其他轮廓的东西提供内部边界。无论如何要这样做?

EDIT-1:- 我想找到绿色和红色像素的坐标,如果它们彼此非常接近,则将所有读取的像素转换为绿色。但是有人知道如何获取坐标吗?

EDIT-2 我按照 Derman 的方法得到了 80% 的结果。查看另一个源图片及其掩码

现在按照 Derman 的输入,我得到了这个

代码清楚地识别标记为 1 和 3(绿色和红色)的轮廓,基于它们具有或 dsnt 具有子轮廓的事实。但轮廓 2 显然与轮廓 1 相同,并且具有子轮廓,但仍被视为红色。我会把代码分享给你们,我知道它可能需要做一个小的修改,但它似乎躲过了我-

Mat binMask;    
Mat lung_src;   
vector<std::vector<cv::Point>> contours;
vector<cv::Vec4i> hierarchy;
int count = 0;

findContours(binMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));

for (int i = 0; i < contours.size(); i++)
{
    if (hierarchy[i][2] != -1) // means it has child contour
    {           
        if (count>1)// number of child countors,if its greater than 1 then green else red
        {
            drawContours(lung_src, contours, i, Scalar(0, 255, 0), 1, 8, hierarchy, 0, Point());                
        }
        else  // means it's count is 1 or less
        {
            drawContours(lung_src, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point());
        }
        count++;
    }           
    else  // means it doesn't have any child contour
    {
        drawContours(lung_src, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point());
    }
}
imshow("lung", lung_src);
imwrite("lung.tiff", lung_src);

lung_src 是上面显示的红色/绿色轮廓图像。

【问题讨论】:

    标签: c++ c opencv image-processing image-segmentation


    【解决方案1】:

    为了确定一个轮廓是否在另一个轮廓内,您可以使用轮廓的层次结构特征。例如,在您的情况下,您可能首先使用以下方法检测轮廓:

    cv::Mat inputImg = cv::imread("keVZc.png", CV_LOAD_IMAGE_GRAYSCALE);    
    cv::Mat binMask = cv::Mat::zeros(inputImg.size(), inputImg.type());
    cv::threshold(inputImg, binMask, 28, 255, CV_THRESH_BINARY);
    
    cv::Mat cannyOutput = cv::Mat::zeros(binMask.size(), binMask.type());
    cv::Canny(binMask, cannyOutput, 28, 28 * 2, 3);
    
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(cannyOutput, contours, hierarchy, CV_RETR_TREE,    CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
    

    然后,使用层次结构,你可以决定该轮廓是否有父、子等。层次结构的一般结构是这样的:

    [next contour, previous contour, child contour, parent contour]
    

    previousnext 轮廓与输入轮廓属于同一级别。如果输入轮廓有孩子,那么它会给你孩子标签,否则它的值为-1,这与父母的情况类似。

    因此,您可以像这样检查一个轮廓是否在另一个轮廓内:

    for(int i = 0; i < contours.size(); i++)
    {
        if(hierarchy[i][2] != -1) // means it has child contour
        { 
            // do something with it
        }
        else  // means it doesn't have any child contour
        {
           // do something with it
        }
    }
    

    为了比较两个轮廓是否彼此太近以过滤掉它们,您可以使用它们之间的距离测量(标准)。这样的事情会有所帮助:

    for(int i = 0; i < contours.size(); i++)
    {
        int prvIndx = hierarchy[i][0]; // coordinates of previous contour
        int nxtIndx = hierarchy[i][1]; // coordinates of next contour
    
        std::vector<cv::Point> prvPoint = contours[prvIndx];
        std::vector<cv::Point> nxtPoint = contours[nxtIndx];
    
        // calculate norm of these two points
        double distance = cv::norm(point1, point2);
    
        // use a threshold value to decide what to do
        if(double <= 40.0) // change the value according to your situation
        {
            // you decide what to do here
        }
    
    } 
    

    有关轮廓层次结构的更多信息,请查看以下参考资料:

    ref1: Finding contours in your image

    ref2: Contours hierarchy

    希望对你有帮助!

    【讨论】:

    • 在父部分,该值表示哪个轮廓是父级。例如,[-1, 2, -1, 7] 表示其父级是第 7 个轮廓。因此,您可以通过 contours[7] 之类的方式获取父级。
    • 感谢好友的帮助:D
    • 如果您认为我的回答有帮助,请不要忘记接受。
    • @Derman- 嘿,你能看看代码(来自 EDIT-2)吗?...我对此仍有一些疑问。
    • 我相信你应该仔细检查增加count值的部分,以及count++之前的if-else
    猜你喜欢
    • 2011-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-12
    • 1970-01-01
    • 2023-03-21
    • 2020-06-14
    • 1970-01-01
    相关资源
    最近更新 更多