首页 > 解决方案 > 通过内部颜色过滤 OpenCV 轮廓

问题描述

我在按颜色过滤某些轮廓时遇到问题。我想删除所有内部有黑色像素的轮廓,只保留带有白色像素的轮廓(见下图)。

创建轮廓列表的代码。我使用了 RETR_TREE 轮廓检索模式和 CHAIN_APPROX_SIMPLE 点选择来避免轮廓内的很多点。

cv::cvtColor(src_img, gray_img, cv::COLOR_BGR2GRAY);
cv::threshold(gray_img, bin_img, minRGB, maxRGB, cv::THRESH_BINARY_INV);

std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;

cv::findContours(bin_img, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

然后,使用这些轮廓,我构建了封闭路径并将它们显示在屏幕上。

输入图像:

输入图像

当前我的结果:

当前结果

我需要的。仅填充具有白色内容的轮廓。

在此处输入图像描述

我尝试将所有轮廓缩放到内部 1 个像素,并检查所有像素是否都等于暗,但它并没有像我预期的那样工作。请参阅下面的代码。

double scaleX = (double(src_img.cols) - 2) / double(src_img.cols);
double scaleY = (double(src_img.rows) - 2) / double(src_img.rows);

for (int i = 0; i < contours.size(); i++) {
    std::vector<cv::Point> contour = contours[i];

    cv::Moments M = cv::moments(contour);

    int cx = int(M.m10 / M.m00);
    int cy = int(M.m01 / M.m00);

    std::vector<cv::Point> scaledContour(contour.size());

    for (int j = 0; j < contour.size(); j++) {
        cv::Point point = contour[j];
        point = cv::Point(point.x - cx, point.y - cy);
        point = cv::Point(point.x * scaleX, point.y * scaleY);
        point = cv::Point(point.x + cx, point.y + cy);
        scaledContour[j] = point;
    }

    contours[i] = scaledContour;
}

如果您有任何想法或解决方案,我将非常感激,非常感谢!

标签: c++objective-copencvdrawingcontour

解决方案


希望有一点很清楚,当您使用THRESH_BINARY_INV.

所以我们本质上是在寻找白线而不是黑线。当我在 python 中工作时,我没有提供代码,但我会列出它是如何完成的。

  1. 创建一个输入图像大小的黑色数组。让我们称之为mask
  2. 找到轮廓后,用白色即 255 绘制它们mask,同时提供thickness=-1. 这意味着我们基本上是在填充轮廓。
  3. 现在我们需要删除轮廓的边界,所以剩下的唯一部分是轮廓内的部分。这可以通过再次在 上绘制轮廓来实现mask,这次使用厚度为 1 的黑色。
  4. bitwise_and在图像和蒙版之间执行。只有轮廓内有白色的区域会被留下。

现在你只需要看看输出是否完全是黑色的。如果不是,则意味着您不需要填充该轮廓,因为它里面包含一些东西。

编辑

哦,我没有意识到你的图像会有 600 个轮廓,是的,这需要很多时间,我不知道为什么我以前没有想过使用hierarchy

您可以使用RETR_TREE自身,层次结构值为[next, previous, first_child, parent]. 所以我们只需要检查 的值first_child=-1,这意味着里面没有轮廓,你可以填充它。


推荐阅读