【问题标题】:Filter OpenCV Contours by inside colors通过内部颜色过滤 OpenCV 轮廓
【发布时间】:2020-09-22 13:44:51
【问题描述】:

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

创建轮廓列表的代码。我使用了 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-c opencv drawing contour


【解决方案1】:

希望有一点很清楚,即在查找您使用 THRESH_BINARY_INV 完成的轮廓时,图像中的对象应该是白色的,而背景应该是黑色的。

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

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

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

编辑

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

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

【讨论】:

  • 谢谢,我试过了,我的图像需要 6 秒,超过 6000 个轮廓(绘制轮廓的操作大部分时间 - 5.2 秒)。也许可以通过 RETR_CCOMP 模式和层次对象来解决?你怎么看?
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2016-04-30
    相关资源
    最近更新 更多