I have a problem with filtering some contours by colors in it. I want to remove all contours, which has black pixels inside and keep only contours with white pixels (see pictures below).
Code to create a contours list. I've used a RETR_TREE contour retrieval mode with CHAIN_APPROX_SIMPLE points selection to avoid a lot of points inside contours.
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);
Then, using these contours, I've built closed paths and display them on the screen.
An input image:
Current my results:
What I need. Fill only contours, which has white content.
I've tried to scale all contours to 1 pixel inside and check if all the pixels equal to dark, but it doesn't work as I've expected. See the code below.
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;
}
I will be very grateful if you help with any ideas or solutions, thank you very much!
Hopefully, one thing is clear that the objects in the image should be white and the background black when finding contours that you have done by using THRESH_BINARY_INV
.
So we are essentially trying to find white lines and not black. I am not providing the code as I work in python but I'll list it out how it can be done.
mask
.mask
with white i.e. 255, while providing thickness=-1
. This means we are essentially filling the contour.mask
, this time with black with a thickness of 1.bitwise_and
between the image and mask. Only areas having white inside the contour will be left.Now you just need to see whether the output is completely black or not. If it is not that means you don't need to fill that contour as it contains something inside it.
EDIT
Ohh I didn't realize that your images would be having 600 contours, yes it will take a lot of time for that and I don't know why I didn't think of using hierarchy
before.
You can use RETR_TREE
itself and the hierarchy values are [next, previous, first_child, parent]
. So we just need to check if the value of first_child=-1
, that would mean there are no contours inside and you can fill it.