Opencv Contours Hierarchy - c++

I am trying to access the contour that is nested within another contour to run a few tests on it, such as an area test and to see if the bounding rectangle is about square. I figured out how to test if there is an internal contour, but I do not know how to access it.
Relevant code
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
DEBUG_SHOW("binary image", binary);
findContours(binary, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
vector<vector<Point> > polygons(contours.size());
for (size_t i = 0; i < contours.size(); i++) {
vector<Point> contour = contours[i];
double area = contourArea(contour);
if (area < 300) {
continue;
}
if(hierarchy[i][2] != -1){
//test internal contour
}

If I'm correct then you have a set of Points
Vector<point>
and then you have a collection of those sets
Vector<Vector<point>>
Now with that in mind. You iterate through the Vector(point) using
for (size_t i = 0; i < contours.size(); i++) {
& You are required to iterate through the vector within
You will need to:
for (size_t j=0; j = contours.at(i).size(); j++){
//Do Your Thang
i++;
}

Related

Subtract all contours from image except the one with the largest area

cv::Mat thr;
std::vector<std::vector<cv::Point> > contours;
std::vector<std::vector<cv::Vec4i> > hierarchy;
int largest_area = 0;
int largest_contour_index = 0;
cv::findContours( thr, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image
for( int i = 0; i < contours.size(); i++ ) // iterate through each contour.
{
double a = contourArea( contours[i], false ); // Find the area of contour
if(a > largest_area)
{
largest_area = a;
largest_contour_index = i; // Store the index of largest contour
}
}
What should I do after finding the index of the largest contour? How I can delete all the other contours with its inner areas?
Image is binary (cv::Mat thr). Just black background with white areas.
Thanks.
In your case, deleting contours with its inner areas is equal to fill them to black. This can be done by drawing the contour regions with black color:
for (size_t i=0; i<contours.size(); ++i) {
if (i != largest_contour_index) { // not the largest one
cv::drawContours(thr, contours, i, cv::Scalar(0,0,0), CV_FILLED);
}
}
After finding contours find index of biggest contour and draw that contour on Mat.
int indexOfBiggestContour = -1;
int sizeOfBiggestContour = 0;
for (int i = 0; i < contours.size(); i++)
{
if (contours[i].size() > sizeOfBiggestContour)
{
sizeOfBiggestContour = contours[i].size();
indexOfBiggestContour = i;
}
}
cv::Mat newImage;
drawContours(newImage, contours, indexOfBiggestContour, Scalar(255), CV_FILLED, 8, hierarchy);

Detect bounding box in OCR?

I have an image and I obtained a binary image of it. I would expect a rectangular bounding box, but i didn't get it. This is my code:
vector<vector<Point>> contours;
Vec4i hierarchy;
findContours(binary, contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
/*Mat drawing = Mat::zeros(binary.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawing, contours, i, color, 1, 8, hierarchy, 0, Point());
}
imshow("contours", drawing);*/
vector<Point> approx, approxRectangle;
Rect bounding_rect(0, 0, 0, 0);
double max_area = 0;
for (int i = 0; i < contours.size(); i++)// xet tung contour
{
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
if (approx.size() == 4 && isContourConvex(Mat(approx)))
{
Rect box = boundingRect(contours[i]);
if (bounding_rect.area() == 0){
bounding_rect = box;
approxRectangle = approx;
}
else{
if (bounding_rect.area() < box.area()){
bounding_rect = box;
approxRectangle = approx;
}
}
}
}`
This is my image:
You don't get the desired result, because you're looking for almost rectangular contours, but this won't work since the contours you're interested in is not rectanglar. You can see (in blue) the approximation of that contour (obtained on my binarized image):
This shows you that this is not a reliable constraint.
You can easily solve this, in this case, computing the bounding box for each contour, and keep the largest (in green):
Code:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace cv;
int main()
{
// Load image
Mat3b img = imread("path_to_image");
// Convert to grayscale
Mat1b binary;
cvtColor(img, binary, COLOR_BGR2GRAY);
// Binarize (remove anti-aliasing artifacts)
binary = binary > 200;
// Find contours
vector<vector<Point>> contours;
findContours(binary.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
// Compute the bounding boxes
vector<Rect> boxes;
for (int i = 0; i < contours.size(); ++i)
{
boxes.push_back(boundingRect(contours[i]));
}
// Find index of largest contours
int idx_largest_box = distance(boxes.begin(), max_element(boxes.begin(), boxes.end(), [](const Rect& lhs, const Rect& rhs) {
return lhs.area() < rhs.area();
}));
// Draw largest box
rectangle(img, boxes[idx_largest_box], Scalar(0,255,0));
imshow("Result", img);
waitKey();
return 0;
}

OpenCV how to draw a contour of 2 largest Object from webcam(tracking) in C++

Can someone help me to solve this problem? I need to draw contours from the 2 largest objects with same color but I always get error and this is my code.
void showconvex(Mat &thresh,Mat &frame)
{
int largest_index = 0;
int largest_contour = 0;
int second_largest_index = 0;
int second_largest_contour = 0;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
//find contours
findContours(thresh, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
/// Find the convex hull object for each contour
vector<vector<Point> >hull(contours.size());
vector<vector<int> >inthull(contours.size());
vector<vector<Vec4i> >defects(contours.size());
for (int i = 0; i < contours.size(); i++)
{
convexHull(Mat(contours[i]), hull[i], false);
convexHull(Mat(contours[i]),inthull[i], false);
if (inthull[i].size()>3)
convexityDefects(contours[i], inthull[i], defects[i]);
}
//find largest contour
for (int i = 0; i< contours.size(); i++) // iterate through each contour.
{
double a = contourArea(contours[i].size()); // Find the area of contour
if (a>largest_contour)
{
second_largest_contour = largest_contour;
second_largest_index = largest_index;
largest_contour = a;
largest_index = i;
}
else if(contours[i].size() > second_largest_contour)
{
second_largest_contour = contours[i].size();
second_largest_index = i;
}
}
drawContours(frame, contours, largest_index, CV_RGB(0,255,0), 2, 8, hierarchy);
drawContours(frame, contours, second_largest_index, CV_RGB(0,255,0), 2, 8, hierarchy);
}
After your cv::findContours() call catch the case when contours.size() is zero:
if ( contours.size() == 0 ) return;
Otherwise you are drawing contours of largest_index (equal to 0) and second_largest_index (also equal to 0) that do not exist.

How can I found the circles on image avoiding the internal circles?

How can I found the circles on image using the method minEnclosingCircle but avoid the internal circles?
I'm using the opencv with c++ to detect circles on a image. I was using the method HoughCircles but sometimes it lost some circles or it detected false circles.
Therefore I'm replacing it for the minEnclosingCircle. Now the algorithm is finding all circles, but in some cases it found circles inside other circles and I want avoid this.
The image 1 is a example of input and the image 2 is it output.
The code used to process those images is this:
Start of code:
vector < Circle > houghCircles(Mat thresholdImage, float minRadius, float maxRadiuss) {
vector < vector < Point > > contours;
vector < Vec4i > hierarchy;
findContours(thresholdImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
vector < vector < Point > > contours_poly(contours.size());
vector < Circle > circlesTMP(contours.size());
for (int i = 0; i < contours.size(); i++) {
Point2f detectedCenter;
float detectedRadius;
approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);
minEnclosingCircle((Mat) contours_poly[i], detectedCenter, detectedRadius);
if (minRadius != 0 && detectedRadius < minRadius) {
continue;
}
if (maxRadiuss != 0 && detectedRadius > maxRadiuss) {
continue;
}
sf::Circle _circle(detectedCenter, detectedRadius);
circlesTMP.push_back(_circle);
}
vector < Circle > circles;
for (int i = 0; i < circlesTMP.size(); i++) {
sf::Circle _circle = circlesTMP[i];
if (_circle.getRadius() > 0) {
circles.push_back(circlesTMP[i]);
}
}
cout << "Circles found: " << circles.size() << endl;
Mat drawing = Mat::zeros(thresholdImage.size(), CV_8UC3);
for (int i = 0; i < circles.size(); i++) {
sf::Circle _circle = circles[i];
Scalar color = Scalar(200, 187, 255);
circle(drawing, _circle.getCenter(), (int) _circle.getRadius(), color, 2, 8, 0);
}
imshow(drawing, "OpenCVUtil");
waitkey();
return circles;
}
you can check this link out and change your mode parameter and test your code:
http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours
check out the results you obtain for CV_RETR_EXTERNAL instead of CV_RETR_TREE as the mode.

How to filter small segments from image in OpenCV?

I am printing the Contours in the following way:
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours( mask, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_TC89_KCOS);
for ( size_t i=0; i<contours.size(); ++i )
{
cv::drawContours( img, contours, i, Scalar(200,0,0), 1, 8, hierarchy, 0, Point() );
cv::Rect brect = cv::boundingRect(contours[i]);
cv::rectangle(img, brect, Scalar(255,0,0));
}
Once I have a binnary image, I want to eliminate the smaller contours. Any suggestions on how to do so?
MY INPUT PICTURE:
WHAT I WANT TO ACHIEVE:
EDIT:
I am trying to get rid of the smaller segments. Any hints?
I've built a function that only prints points that belong to the bigger segments. It uses the pointPolygonTest, an awesome OpenCV function that can say if a point is inside, outside or at the bounds of a given contour. Check it out:
// Gets only the biggest segments
Mat Morphology::threshSegments(Mat &src, double threshSize) {
// FindContours:
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Mat srcBuffer, output;
src.copyTo(srcBuffer);
findContours(srcBuffer, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_TC89_KCOS);
vector<vector<Point> > allSegments;
// For each segment:
for (size_t i = 0; i < contours.size(); ++i) {
cv::drawContours(srcBuffer, contours, i, Scalar(200, 0, 0), 1, 8, hierarchy, 0, Point());
cv::Rect brect = cv::boundingRect(contours[i]);
cv::rectangle(srcBuffer, brect, Scalar(255, 0, 0));
int result;
vector<Point> segment;
for (unsigned int row = brect.y; row < brect.y + brect.height; ++row) {
for (unsigned int col = brect.x; col < brect.x + brect.width; ++col) {
result = pointPolygonTest(contours[i], Point(col, row), false);
if (result == 1 || result == 0) {
segment.push_back(Point(col, row));
}
}
}
allSegments.push_back(segment);
}
output = Mat::zeros(src.size(), CV_8U);
int totalSize = output.rows*output.cols;
for (int segmentCount = 0; segmentCount < allSegments.size(); ++segmentCount) {
vector<Point> segment = allSegments[segmentCount];
if(segment.size() > totalSize*threshSize){
for (int idx = 0; idx < segment.size(); ++idx) {
output.at<uchar>(segment[idx].y, segment[idx].x) = 255;
}
}
}
return output;
}
I would suggest using morphological opening to get rid of the smaller blobs, followed by a morphological hole filling.