opencv中的轮廓选择

Contour selection in opencv

我有源图片

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

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

我使用红色提取了斑点。但我想只提取那些内部没有绿色的,或者至少只给那些内部没有其他轮廓的内部边界。还是要做?

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

EDIT-2 我按照 Derman 的方法,得到了 80% 的结果。查看另一张源图片及其遮罩

现在根据 Derman 的输入,我得到了这个

代码清楚地识别标记为 1 和 3(绿色和红色)的轮廓,基于它们有或没有子轮廓的事实。但是轮廓 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 就是上面显示的 red/green 等高线图像。

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

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));

然后利用hierarchy判断那个轮廓有没有parent、child等。hierarchy的一般结构是这样的:

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

previousnext等高线是与输入等高线属于同一级别的等高线。如果输入轮廓有 child,那么它会给你 child 标签,否则,它的值将是 -1,这与 parents 的情况类似。

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

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

希望对您有所帮助!