按内部颜色过滤 OpenCV 轮廓

Filter OpenCV Contours by inside colors

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

创建轮廓列表的代码。我使用了 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;
}

如果您能提供任何想法或解决方案,我将不胜感激,非常感谢!

希望有一点很清楚,即在使用 THRESH_BINARY_INV.

查找轮廓时,图像中的对象应该是白色的,背景应该是黑色的

所以我们实际上是在尝试寻找白线而不是黑线。我在 python 工作时没有提供代码,但我会列出如何完成。

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

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

编辑

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

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

我已将模式更改为 RETR_CCOMP 并通过 hierarchy[contour index][3] 添加区域过滤 != - 1(意思是,没有parent),我的问题就解决了。 谢谢!