findContour hierarchy in OpenCV - c++

I am trying to make sense of the hierarchy in the findContour function in OpenCV. I am using RETR_CCOMP to hopefully find the parent contours and whether or not they have 'children'. My find contour hierarchy vector seems to suggest there are far more parent contours then are visible in the output which makes it more difficult to use.
Is it possible to get around this problem?.
Here's my code:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src;
Mat src_gray;
Mat src_edges;
int main(int argc, char** argv)
{
src = imread("image.jpg", CV_LOAD_IMAGE_UNCHANGED);
cvtColor(src, src_gray, CV_BGR2GRAY);
blur(src_gray, src_gray, Size(3, 3));
Canny(src_gray, src_edges, 200, 120);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(src_edges, contours, hierarchy, RETR_CCOMP, CV_CHAIN_APPROX_TC89_L1, Point(0, 0));
for (auto vec : hierarchy)
std::cout << vec << std::endl; // just to have a look at the hierarchy vector
int count = 0;
for (int i = 0; i < 5; i++){
if (hierarchy[i][3] != 0){
count++;
}
}
cout << "number of labels = " << count << endl;
Mat drawing = Mat::zeros(src_gray.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(rand() & 255, rand() & 255, rand() & 255);;
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
imshow("Contours", drawing);
namedWindow("Original Image", CV_WINDOW_AUTOSIZE);
imshow("Original Image", src);
waitKey(0);
return(0);
}
Here an example image:

Related

Find largest contours OpenCV

I have used canny edge detection and I have found the contours on an image I am trying to process.
I want to find the five largest contours and then see whether or not there are contours within the five biggest contours in the image.
Is this possible? I am new to OpenCV.
You can find the N largest contours checking their length. You should take care to pass to findContours the parameter CHAIN_APPROX_NONE for this to work properly.
You can then check inside each mask if there are other contours.
Image:
N = 5 largest contours, with inner contours for each one.
Code:
#include <opencv2\opencv.hpp>
#include <vector>
#include <numeric>
using namespace cv;
using namespace std;
int main()
{
Mat3b img = imread("path_to_image");
Mat1b gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
Mat1b edges;
Canny(gray, edges, 200, 50);
vector<vector<Point>> contours;
findContours(edges.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
vector<int> indices(contours.size());
iota(indices.begin(), indices.end(), 0);
sort(indices.begin(), indices.end(), [&contours](int lhs, int rhs) {
return contours[lhs].size() > contours[rhs].size();
});
int N = 5; // set number of largest contours
N = min(N, int(contours.size()));
Mat3b res = img.clone();
// Draw N largest contours
for (int i = 0; i < N; ++i)
{
Scalar color(rand() & 255, rand() & 255, rand() & 255);
Vec3b otherColor(color[2], color[0], color[1]);
drawContours(res, contours, indices[i], color, CV_FILLED);
// Create a mask for the contour
Mat1b res_mask(img.rows, img.cols, uchar(0));
drawContours(res_mask, contours, indices[i], Scalar(255), CV_FILLED);
// AND with edges
res_mask &= edges;
// remove larger contours
drawContours(res_mask, contours, indices[i], Scalar(0), 2);
for (int r = 0; r < img.rows; ++r)
{
for (int c = 0; c < img.cols; ++c)
{
if (res_mask(r, c))
{
res(r,c) = otherColor;
}
}
}
}
imshow("Image", img);
imshow("N largest contours", res);
waitKey();
return 0;
}

How to find coordinate points of images using findcontours methods in opencv

Here I did coding for finding the edge and their all coordinate points of the image but I need only two or three coordinate point of each quadrant in image.
using namespace cv;
using namespace std;
Mat src;
Mat src_gray;
int thresh = 172;
int max_thresh = 255;
RNG rng(12345);
void thresh_callback(int, void* );
int main( int argc, char** argv ){
src = imread("Led50.jpg",1);
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src );
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);}
void thresh_callback(int, void* ){
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
for(unsigned int i=0;i<contours.size();i++){
for(unsigned int j=0;j<contours[i].size();j++)
{
cout << "Point(x,y)=" << contours[i][j].x << "," << contours[i][j].y << endl;
}}}
Source file:
Result and i get all the coordinate point:
And I need only marked coordinate point but not in exact position as well as each quadrant atleast have two points:
The above code is based on the canny and findcontours, I need few coordinates from images.
#include "highgui.hpp"
#include "imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, char** argv ){
Mat src_gray;
src_gray = imread("EXnc1.jpg",0);
blur( src_gray, src_gray, Size(3,3) );
Mat bwimg = src_gray > 127;
vector<vector<Point> > contours;
findContours( bwimg, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE );
for(unsigned int i=0;i<contours.size();i++){
approxPolyDP(Mat(contours[i]), contours[i], 10, true);
if(i > 0)
{
cout << "Outer contour points \n";
}
else cout << "Inner contour points \n";
for(unsigned int j=0;j<contours[i].size();j++)
{
cout << "Point(x,y)=" << contours[i][j].x << "," << contours[i][j].y << endl;
circle( src_gray, contours[i][j], 3, Scalar(0, 0, 255), FILLED, LINE_AA );
}
imshow( "Result", src_gray );
waitKey(0);
}
return(0);}
output :
Inner contour points
Point(x,y)=343,148
Point(x,y)=419,160
Point(x,y)=461,208
Point(x,y)=457,276
Point(x,y)=403,322
Point(x,y)=322,322
Point(x,y)=269,262
Point(x,y)=279,190
Outer contour points
Point(x,y)=371,133
Point(x,y)=289,159
Point(x,y)=251,224
Point(x,y)=271,298
Point(x,y)=351,341
Point(x,y)=436,320
Point(x,y)=481,247
Point(x,y)=456,172

Open cv finding convex hull

The following code in OpenCV is for me to detect a yellow color ball and draw its convex hull.The code although doesnt give any compilation errors,gives the following error in the output window.
I used the largest area function to avoid smaller unwanted contours.
The error is
Assertion failed <0 <= contourIdx && contourIdx< last> in cv::drawContours ,file C:Buildsmasters..(some path),line 2299****
#include <opencv\cv.h>
#include <opencv2\highgui\highgui.hpp>
#include<opencv\cvaux.h>
#include<opencv\cxcore.h>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
#include<conio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
int main(){
Mat img, frame, img2, img3;
double maxarea = 0;
int lrgctridx; //largest contour index
VideoCapture cam(0);
while (true){
cam.read(frame);
cvtColor(frame, img, CV_BGR2HSV);
//thresholding
inRange(img, Scalar(0, 143, 86), Scalar(39, 255, 241), img2);
//finding contours
vector<vector<Point>> Contours;
vector<Vec4i> hier;
//morphological transformations
erode(img2, img2, getStructuringElement(MORPH_RECT, Size(3, 3)));
erode(img2, img2, getStructuringElement(MORPH_RECT, Size(3, 3)));
dilate(img2, img2, getStructuringElement(MORPH_RECT, Size(8, 8)));
dilate(img2, img2, getStructuringElement(MORPH_RECT, Size(8, 8)));
//finding the contours required
findContours(img2, Contours, hier, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, Point(0, 0));
//finding the contour of largest area and storing its index
for (int i = 0; i < Contours.size(); i++)
{
double a=contourArea(Contours[i]);
if (a> maxarea)
{
maxarea = a;
lrgctridx=i;
}
}
//convex hulls
vector<vector<Point> >hull(Contours.size());
for (int i = 0; i < Contours.size(); i++)
{
convexHull(Contours[i], hull[i], false);
}
//REQUIRED contour is detected,then draw a convex hull
if (maxarea!=0)
drawContours(frame, hull, lrgctridx, Scalar(255, 255, 255), 1, 8, vector<Vec4i>(), 0, Point());
imshow("output", frame);
char key = waitKey(33);
if (key == 27) break;
}
}
Any help would be much appreciated.Thaanks in advance!
You should reset lrgctridx at every iteration.
Say you find a countour at time "t", and you set lrgctridx = 1;. At time "t+1" you don't find any contours, so Contours and hull size will be 0, but you're trying to access position 1.
Just put lrgctridx = 0 before the for loop. Same for maxarea.
lrgctridx = 0;
maxarea = 0;
for (int i = 0; i < Contours.size(); i++)
{
....
Now your condition to draw contours is ok, but you'd better replace it with
if(!Contours.empty()) {
drawContours(...);
....

Detect number of objects using number of canny contours Opencv

I try to count the number of hearts in the following image by using a canny edge detection algorithm and contours.
But after the contours I have gotten image like this and it has contoured 4 instead of 3. What kind of method I have to follow to count any number of object different shapes of deck card pack. I only need number of symbols in the middle.
Here is my c++ code
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
using namespace std;
Mat src;
Mat dst;
Mat canny_output;
//this is function for loading the image
void loadImage(char* source){
Mat tmp;
/// Load source image and convert it to gray
src = imread( source, 1 );
/// Convert image to gray and blur it
cvtColor( src, tmp, CV_RGB2GRAY );
//blur( src_gray, src_gray, Size(3,3) );
bitwise_not( tmp, src);
}
void clearImage(){
int i,j;
int r = 10;
Mat clone;
src.copyTo(clone);
for(i = 0;i < src.rows;++i){
j = 0;
clone.at<Vec3b>(i,j) = Vec3b(0,0,0);
for(j = 0;j < src.cols;++j){
if(src.at<cv::Vec3b>(i,j) == cv::Vec3b(255,255,255)){
rectangle(
clone,
cv::Point(i-r, j),
cv::Point(i+r, j+r),
cv::Scalar(255, 255, 255)
);
}
}
}
}
void detectImages(){
int thresh = 100;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny( src, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
cout<<(hierarchy.size())<<endl;
}
//corpping and resizing the image
void corpResizeImage(){
int i,j;
Vec3b intensity;
intensity.val[0] = 0;
intensity.val[1] = 0;
intensity.val[2] = 0;
cv::Rect myROI(src.cols/6,0, 2*src.cols/3, src.rows);
Mat croppedImage = src(myROI);
Size size(300,600);
resize(croppedImage,src,size);//resize image
for(i = 0;i < src.rows;++i){
j = 0;
if((i < src.rows/25)||(i < (src.rows/25))){
for(j = 0;j < src.cols;++j){
src.at<Vec3b>(i,j)= intensity;
}
}
}
}
/** #function main */
int main( int argc, char ** argv )
{
loadImage("img/3h.png");
corpResizeImage();
detectImages();
/// Create Window
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, canny_output );
waitKey(0);
return(0);
}

OpenCV c++ assertion failed <i < 0> in cv::_InputArray::getMat

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/background_segm.hpp>
#include <iostream>
#include <windows.h>
using namespace cv;
using namespace std;
//initial min and max HSV filter values.
//these will be changed using trackbars
Mat src; Mat HSV; Mat roi; Mat range; Mat eroded; Mat gray;
int thresh = 100;
int max_thresh = 255;
/** #function main */
int main(int argc, char** argv)
{
createTrackbars();
VideoCapture cap(0); // open the default camera
if (!cap.isOpened()) // check if we succeeded
return -1;
namedWindow("background", 1);
int waitTime = 50;
int counter = 101;
int roiLeft = 20;
int roiTop = 50;
int roiRight = 200;
int roiBottom = 200;
Rect rRoi = Rect(roiLeft, roiTop, roiRight, roiBottom);
Mat background;
cap >> background;
background = background(rRoi);
//cvtColor(background, background, CV_BGR2HSV);
//imshow("background", background);
vector<vector<Point> > contours;
vector<vector < cv::Point >> hull(1);
vector<Vec4i> hierarchy;
vector<CvConvexityDefect> defects;
while (true)
{
cap >> src;
//Create the region of interest.
Mat iRoi = src.clone()(rRoi);
Mat iRoiSRC = src(rRoi);
//Draw a rectangle there.
rectangle(src, rRoi, Scalar(255, 128, 0), 1, 8, 0);
//imshow("roi", iRoi);
//Subtract the static background.
absdiff(iRoi, background, iRoi);
//imshow("diff", iRoi);
//Convert it to a GrayScale and threshold it.
cvtColor(iRoi, iRoi, CV_BGR2GRAY);
threshold(iRoi, gray, 15, 255, CV_THRESH_BINARY);
//Perform a closing.
Mat erodeElement = getStructuringElement(MORPH_ELLIPSE, Size(erodeSize, erodeSize));
Mat dilateElement = getStructuringElement(MORPH_ELLIPSE, Size(dilateSize, dilateSize));
for (int index = 0; index < loopAmount; index++)
{
erode(gray, gray, erodeElement);
dilate(gray, gray, dilateElement);
}
//imshow("range", gray);
//Find the contours.
findContours(gray, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
//Pick the biggest contour.
int biggestContourIndex = 0;
int largestArea = 0;
for (int i = 0; i < contours.size(); i++)
{
if (contours[i].size() > largestArea)
{
largestArea = contours[i].size();
biggestContourIndex = i;
}
}
vector<int> hullsI;
vector<Point> hullsP;
vector<Vec4i> defects;
//Find the convex hull.
if (contours.size() > 0)
{
convexHull(contours[biggestContourIndex], hullsI, true, true);
convexHull(contours[biggestContourIndex], hullsP, true, true);
}
//Find the convexity defects.
if (contours.size() > 0)
{
if (contours[biggestContourIndex].size() > 3)
{
convexityDefects(contours[biggestContourIndex], hullsI, defects);
}
}
//Draw the biggest contour and its convex hull.
Scalar colorOne = Scalar(255, 128, 0);
Scalar colorTwo = Scalar(0, 0, 255);
if (contours.size() > 0)
{
drawContours(iRoiSRC, contours, biggestContourIndex, colorOne, 2, 8, hierarchy, 0, Point());
drawContours(iRoiSRC, hullsP, 0, colorTwo, 1, 8, vector<Vec4i>(), 0, Point());
rectangle(iRoiSRC, boundingRect(contours[biggestContourIndex]), Scalar(0, 255, 0), 1, 8, 0);
}
imshow("src", src);
if (waitKey(waitTime) >= 0) break;
}
return(0);
}
There is a rectangle in the upper left of the screen, where my hand will be recognized once I hold it there.
The error that i get appears at the first drawContours. The full error which is given to me by the console is: OpenCV Error: Assertion failed <i <0> in cv::_InputArray::getMat, file C:\buildslave64\win64_amdoc1\2_4_PackSlave-win64-vc11-shared\opencv\modules\core\src\matrix.cpp, line 963
I've been extensively searching for a solution on multiple sites, including stackoverflow but none of the solution seem to be working.
Any help would be appreciated.
I use Visual studio 2013 with OpenCV-2.4.10
converting vector<CvConvexityDefect> defects; to a point seemed to do the trick