按内部颜色过滤 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 工作时没有提供代码,但我会列出如何完成。
- 创建一个输入图像大小的黑色数组。我们称它为
mask
.
- 找到轮廓后,在
mask
上用白色绘制它们,即 255,同时提供 thickness=-1
。这意味着我们实际上是在填充轮廓。
- 现在我们需要移除轮廓的边界,所以唯一剩下的部分就是轮廓内部的部分。这可以通过再次在
mask
上绘制轮廓来实现,这次使用厚度为 1. 的黑色
- 在图像和蒙版之间执行
bitwise_and
。只留下轮廓内有白色的区域。
现在你只需要看输出是否全黑。如果不是,则意味着您不需要填充该轮廓,因为它内部包含一些东西。
编辑
哦,我没有意识到你的图像会有 600 个轮廓,是的,这会花费很多时间,我不知道为什么我之前没有想到使用 hierarchy
.
您可以使用 RETR_TREE
本身,层次结构值为 [next, previous, first_child, parent]
。所以我们只需要检查first_child=-1
的值,这意味着里面没有轮廓,你可以填充它。
我已将模式更改为 RETR_CCOMP 并通过 hierarchy[contour index][3] 添加区域过滤 != - 1(意思是,没有parent),我的问题就解决了。
谢谢!
我在按颜色过滤某些轮廓时遇到问题。我想删除所有内部有黑色像素的轮廓,只保留有白色像素的轮廓(见下图)。
创建轮廓列表的代码。我使用了 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 工作时没有提供代码,但我会列出如何完成。
- 创建一个输入图像大小的黑色数组。我们称它为
mask
. - 找到轮廓后,在
mask
上用白色绘制它们,即 255,同时提供thickness=-1
。这意味着我们实际上是在填充轮廓。 - 现在我们需要移除轮廓的边界,所以唯一剩下的部分就是轮廓内部的部分。这可以通过再次在
mask
上绘制轮廓来实现,这次使用厚度为 1. 的黑色
- 在图像和蒙版之间执行
bitwise_and
。只留下轮廓内有白色的区域。
现在你只需要看输出是否全黑。如果不是,则意味着您不需要填充该轮廓,因为它内部包含一些东西。
编辑
哦,我没有意识到你的图像会有 600 个轮廓,是的,这会花费很多时间,我不知道为什么我之前没有想到使用 hierarchy
.
您可以使用 RETR_TREE
本身,层次结构值为 [next, previous, first_child, parent]
。所以我们只需要检查first_child=-1
的值,这意味着里面没有轮廓,你可以填充它。
我已将模式更改为 RETR_CCOMP 并通过 hierarchy[contour index][3] 添加区域过滤 != - 1(意思是,没有parent),我的问题就解决了。 谢谢!