How to find points of drawcontour of a detected image? - c++

I want to find points of a contour which is draw on object after following operation like background subtraction , findcontour ,drawcontour.
My object is moving so that my contour is also not proper . and i want to find of maximum and minimum points on contour which is draw on object.
Can anyone tell me how to find?
My object is moving car and camera view is top.

vector<vector<Point>> allContours;
vector<Vec4i> hierarchy;
Mat _temp = image.clone();
findContours(_temp, allContours, RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
allContours is contour's vector.
you can access points of each contours.
============================================================================
all points of contous will be draw by below code.
vector<vector<Point>> allContours;
vector<Vec4i> hierarchy;
Mat _temp = imageGray.clone();
Mat ptDraw = Mat::zeros(image.rows,image.cols,CV_8UC3);
findContours(_temp, allContours, RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
for(int i=0;i<allContours.size();i++)
{
drawContours(image, allContours, i, Scalar(0,0,255), 2, 8, hierarchy, 0, Point() );
for(int j=0;j<allContours.at(i).size();j++)
{
Point pt = allContours.at(i).at(j);
circle(ptDraw,pt,1,Scalar(0,0,255),CV_FILLED);
}
}

Related

How to straighten curved line using OpenCV?

I have image with curved line like this :
I couldn't find a technique to straighten curved line using OpenCV. It is similar to this post Straightening a curved contour, but my question is specific to coding using opencv (in C++ is better).
So far, I'm only able to find the contour of the curved line.
int main()
{
Mat src; Mat src_gray;
src = imread("D:/2.jpg");
cvtColor(src, src_gray, COLOR_BGR2GRAY);
cv::blur(src_gray, src_gray, Size(1, 15));
Canny(src_gray, src_gray, 100, 200, 3);
/// Find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
RNG rng(12345);
findContours(src_gray, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
/// Draw contours
Mat drawing = Mat::zeros(src_gray.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
drawContours(drawing, contours, i, (255), 1, 8, hierarchy, 0, Point());
}
imshow("Result window", drawing);
imwrite("D:/C_Backup_Folder/Ivan_codes/VideoStitcher/result/2_res.jpg", drawing);
cv::waitKey();
return 0;
}
But I have no idea how to determine which line is curved and not, and how to straighten it. Is it possible? Any help would be appreciated.
Here is my suggestion:
Before everything, resize your image into a much bigger image (for example 5 times bigger). Then do what you did before, and get the contours. Find the right-most pixel of each contour, and then survey all pixel of that contour and count the horizontal distance of each pixels to the right-most pixel and make a shift for that row (entire row). This method makes a right shift to some rows and left shift to the others.
If you have multiple contours, calculate this shift value for every one of them in every single row and compute their "mean" value, and do the shift according to that mean value for each row.
At the end resize back your image. This is the simplest and fastest thing I could think of.

Get the location of a blob in OpenCV using C++

enter image description here
The image shown is the difference between two images. All I want to do is get the location of the white part. I want to do this because I want to be able to highlight the place where the difference is on the original image.
I am thinking about using clustering or blob detection or maybe just locating the brightest or whitest pixel in the image.
What method do you think would be the easiest? Is there another method I haven't though of?
Use the findContour method to find the closed contour in the image.
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( BinaryImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
And you can draw that contours using drawContours .
And the variable contours contains the coordinates making that particular contour. You can display it by the following command
for(double i=0; i<contours.size(); i++)
{
cout << contours[i];
drawContours( OutputImage, contours, i, Scalar(0,255,0), 2, 8, hierarchy, 0, Point() );
}

how to detect number of contours in between two lines or specified region of image

I am using OpenCV C++ to find the contours in a video. I want to count the no of contours present in video in a a specified region or in between two lines drawn in a video. For example a stream of contours are moving in a video and I want to count them when they reach to a specific region in a video. I will decrease the count as they leave the specific region in the video. I know some basic stuffs to find contour, calculate the area etc. But I am not getting any programming tips to count the no of contours within specified region. Please help me with the related topics and some tips on programming. (I do not want to use cvBlob.h library)
Basically I am counting the number of cars entered in that region. If car is entered I will increment the count and if it leaves the region then I will decrease the count.
You can approximate the contour you found to a polygon or circle:
for( int i = 0; i < contours.size(); i++ )
{ approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) )
}
after that use the line equation y=a and compare the coordinates of the corners of rectangle or the center+radius of the circle to determine if the contour passed the line.
1.Use a part of your Mat image.(If your ROI is rectangle)
Mat src; // suppose this is your source frame
Mat src_of_interest = src(Rect(Point(x1, y1), Point(x2, y2)));
// Do the rest of finding contour..
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(src_of_interest.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
//now you can do your job with contour vector.
int count = contours.size();
Mat dst = Mat::zeros(src.size(), CV_8UC3);
for(int i=0; i< count; i++)
{
drawContours(dst, contours, i, CV_RGB(255, 0, 0)); // draw contour in red
}
2. If your Region of Interest is not rectangle, try this approach:
vector<Point> contour_of_interest; // this contour is where you want to check
vector<vector<Point>> contours; // this is the contours you found
Mat dst = Mat::zeros(src.size(), CV_8U);
for(int i=0; i< count; i++)
{
drawContours(dst, contours, i, Scalar(255)); // set contour area to 255
}
Mat roi = Mat::zeros(src.size(), CV_8U);
vector<vector<Point>> coi_vector;
coi_vector.push_back(contour_of_interest);
drawContours(roi, coi_vector, 0, Scalar(255));
Mat and = dst & roi; // where 2 mats are both TRUE(not zero)
findContours(and.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
//now you can do your job with contour vector.
int count = contours.size();
3. If you want to count contours between 4 points, try this approach:
vector<Point> contour_of_interest; // this contour is the area where you want to check
Point p1(x1, y1);
Point p2(x1, y2);
Point p3(x2, y2);
Point p4(x2, y1);
contour_of_interest.push_back(p1);
contour_of_interest.push_back(p2);
contour_of_interest.push_back(p3);
contour_of_interest.push_back(p4);
vector<vector<Point>> coi_list;
coi_list.push_back(contour_of_interest);
Mat mask = Mat:zeros(src.size(), CV_8U);
drawContours(mask, coi_list, 0, Scalar(255));
Mat src; // suppose this is your source frame
Mat src_of_interest = src & mask; // remove any pixels outside mask area
// Do the rest of finding contour..
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(src_of_interest.clone(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
//now you can do your job with contour vector.
int count = contours.size();
Mat dst = Mat::zeros(src.size(), CV_8UC3);
for(int i=0; i< count; i++)
{
drawContours(dst, contours, i, CV_RGB(255, 0, 0)); // draw contour in red
}

Get coordinates of contours in OpenCV

Let's say that I have the following output image:
Basically, I have video stream and I want to get coordinates of rectangle only in the output image. Here's my C++ code:
while(1)
{
capture >> frame;
if(frame.empty())
break;
cv::cvtColor( frame, gray, CV_BGR2GRAY ); // Grayscale image
Canny( gray, canny_output, thresh, thresh * 2, 3 );
// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
// Draw contours
Mat drawing = Mat::zeros( canny_output.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, 2, 8, hierarchy, 0, Point() );
}
cv::imshow( "w", drawing );
waitKey(20); // waits to display frame
}
Thanks.
Look at the definition of the find contours function in the opencv documentation and see the parameters (link):
void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
Parameters: here
Look at contours, like Rafa said each contour is stored in a vector of points and each vector of points is stored in a vector, so, by walking in the outer vector and then walking in the inner vector you'll be finding the points you wish.
However, if you want to detect only the bigger contour you might want to use CV_RETR_EXTERNAL as the mode parameter, because it'll detect only most external contour (the big rectangle).
If you still wish to maintain the smaller contours then you might use the CV_RETR_TREE and work out with the hierarchy structure: Using hierarchy contours
Looking at the documentation, the OutputArrayOfArrays contours is the key.
contours – Detected contours. Each contour is stored as a vector of points.
so, you've got a vector< vector<Point> > contours. The vector<Point>(inside) is the coordinates of a contour, and every contour is stored in a vector.
So for instance, to know the 5-th vector, it's vector<Point> fifthcontour = contours.at(4);
and you have the coordinates in that vector.
You can access to those coordinates as:
for (int i = 0; i < fifthcontour.size(); i++) {
Point coordinate_i_ofcontour = fifthcontour[i];
cout << endl << "contour with coordinates: x = " << coordinate_i_ofcontour.x << " y = " << coordinate_i_ofcontour.y;
}

Search for contours within a contour / OpenCV c++

I am trying to track a custom circular marker in an image, and I need to check that a circle contains a minimum number of other circles/objects. My code for finding circles is below:
void findMarkerContours( int, void* )
{
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
vector<Point> approx;
cv::Mat dst = src.clone();
cv::Mat src_gray;
cv::cvtColor(src, src_gray, CV_BGR2GRAY);
//Reduce noise with a 3x3 kernel
blur( src_gray, src_gray, Size(3,3));
//Convert to binary using canny
cv::Mat bw;
cv::Canny(src_gray, bw, thresh, 3*thresh, 3);
imshow("bw", bw);
findContours(bw.clone(), contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
Mat drawing = Mat::zeros( bw.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) );
// contour
drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
//Approximate the contour with accuracy proportional to contour perimeter
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true) *0.02, true);
//Skip small or non-convex objects
if(fabs(cv::contourArea(contours[i])) < 100 || !cv::isContourConvex(approx))
continue;
if (approx.size() >= 8) //More than 6-8 vertices means its likely a circle
{
drawContours( dst, contours, i, Scalar(0,255,0), 2, 8);
}
imshow("Hopefully we should have circles! Yay!", dst);
}
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
}
As you can see the code to detect circles works quite well:
But now I need to filter out markers that I do not want. My marker is the bottom one. So once I have found a contour that is a circle, I want to check if there are other circular contours that exist within the region of the first circle and finally check the color of the smallest circle.
What method can I take to say if (circle contains 3+ smaller circles || smallest circle is [color] ) -> do stuff?
Take a look at the documentation for
findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
You'll see that there's an optional hierarchy output vector which should be handy for your problem.
hierarchy – Optional output vector, containing information about the image topology. It has as many elements as the number of contours.
For each i-th contour contours[i] , the elements hierarchy[i][0] ,
hiearchyi , hiearchyi , and hiearchyi are set to
0-based indices in contours of the next and previous contours at the
same hierarchical level, the first child contour and the parent
contour, respectively. If for the contour i there are no next,
previous, parent, or nested contours, the corresponding elements of
hierarchy[i] will be negative.
When calling findCountours using CV_RETR_TREE you'll be getting the full hierarchy of each contour that was found.
This doc explains the hierarchy format pretty well.
You are already searching for circles of a certain size
//Skip small or non-convex objects
if(fabs(cv::contourArea(contours[i])) < 100 || !cv::isContourConvex(approx))
continue;
So you can use that to look for smaller circles than the one youve got, instead of looking for < 100 look for contours.size
I imagine there is the same for color also...