I have stored the area of all contours in a vector for first frame and now I want to compare area of each contour for second frame with first frame. If there area are same they put in a vector and if they are not same they put in another vector. how can I do it? Please help me.
Thanks in advance
// one frame at a time
void draw_ellipse(Mat &a,int count)
{
findContours( th1, contours, hierarchy, CV_RETR_TREE,
CV_CHAIN_APPROX_SIMPLE, Point(0,0) );
for(i=0;i<contours.size();i++)
{
area.push_back(contourArea(contours[i]));// area is a vector
}
for(j=1;j<=count;j++)
{
for(i=0;i<contours.size();i++)
{
if(area[i]>area[i+1]) // v1,v2,v3 are vectors
v1.push_back(contours[i]);
else if(area[i]<area[i+1])
v2.push_back(contours[i]);
else if(area[i]==area[i+1])
v3.push_back(contours[i]);
}
}
}
Now this function compares contours within same frame but I want that second frame's each contour compare with each contour of 1st frame then it should go in different vectors.
There are pre defined functions in OpenCV to match contours Opencv Contour Matching C++
Related
Few days back ive found a code which is sorting a contours inside vector by using their areas.But i could not understand the code very well especially in comparator function. Why does the contour 1&2 are convert into Mat in the contourArea parameter? Can anyone explain me the whole code in step by step. Your explanation will be usefull for my learning process
// comparison function object
bool compareContourAreas ( std::vector<cv::Point> contour1, std::vector<cv::Point> contour2 )
{
double i = fabs( contourArea(cv::Mat(contour1)) );
double j = fabs( contourArea(cv::Mat(contour2)) );
return ( i < j );
}
[...]
// find contours
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours( binary_image, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE,
cv::Point(0, 0) );
// sort contours
std::sort(contours.begin(), contours.end(), compareContourAreas);
// grab contours
std::vector<cv::Point> biggestContour = contours[contours.size()-1];
std::vector<cv::Point> smallestContour = contours[0];
Your input image is binary, so it only exists of 0 and 1. When you use cv::findContours it searches for points with the value '1' and are touching other 1's, this makes a contour. Then puts all contours in std::vectorstd::vector<cv::Point> contours.
When you would take a grid and draw the points of one contour in it, you will get a 2D array of points, this basically is a one-channel cv::Mat.
In 'compareContourAreas' you take two contours out of your vector 'contours' and compare the absolute sum of all of the points in the contour. To add all the points you use contourArea, which needs a cv::Mat as input, so you first need to convert your contour-vector of points to a cv::Mat.
Then with the sort function you sort all the contours from small to big.
I've got a vector of 2D points and I need to find all the contours formed by these points. Unfortunately, cv::findContours can't handle an array of points, it requires a binary image.
So the question is there any workaround to get contours of points? Maybe it is possible to form a binary image using the points and then use this image in cv::findContours function?
Please advise here.
If you know the size of image, you can create a binary image of zeros and fill all the 2D points with value 255. Then use cv::findContours to find all the contours in binary image.
Following code snippet may help you:
// If pts is your array of float points and r,c are number of rows and columns of image
//calculate total number of points in array
int n = sizeof(pts) / sizeof(*pts);
//if points are stored in vector, then use n = pts.size()
//create binary image
cv::Mat image = cv::Mat::zeros(Size(c, r), CV_8UC1);
//fill all the points with value 255
for (int i = 0; i < n; i++) {
image.at<uchar>(p[i]) = 255;
}
//find all contours in binary image and save in contours variale
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(image, contours, hierarchy, RETR_LIST, CHAIN_APPROX_NONE);
The program I'm working right now is almost done but I'm not very satisfy with the result. By using Canny algorithm, I managed to get a very clear of the object's contour but the program has some problem to recognize the contour and draw the contour with a red line. The program:
void setwindowSettings(){
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
createTrackbar("LowerC", "Contours", &lowerC, 255, NULL);
createTrackbar("UpperC", "Contours", &upperC, 255, NULL);
}
void wait(void)
{
long t=30000000;
while(t--);
}
int main(void)
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat frame,foreground,image;
double pt1, pt2, area;
Rect rect;
int i;
vector<vector<Point> > contours;
vector<vector<Point> > largest_contours;
namedWindow("Capture", CV_WINDOW_AUTOSIZE);
setwindowSettings();
while(1){
cap >> frame; // get a new frame from camera
if( frame.empty() )
break;
image=frame.clone();
cvtColor(image,foreground,CV_BGR2GRAY);
GaussianBlur(foreground,foreground,Size(9,11),0,0);
Canny(foreground,foreground,lowerC,upperC,3);
findContours(foreground,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
if(contours.empty())
continue;
double largest_area = 0;
for( i= 0; i < contours.size(); i++){ // get the largest contour
area = fabs(contourArea(contours[i]));
if(area >= largest_area){
largest_area = area;
largest_contours.clear();
largest_contours.push_back(contours[i]);
}
}
if(largest_area>=3000){ // draw the largest contour if exceeded minimum largest area
drawContours(image,largest_contours,-1,Scalar(0,0,255),2);
printf("area = %.f\n",largest_area);
}
wait();
imshow( "Capture",image );
imshow("Contours",foreground);
if(waitKey(30) >= 0) break;
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}
Program summary:
Get images from camera
Noise filtration (Convert to gray → blur → Canny)
Find contours
Find the largest contour and its area in the image aka the object
Draw a red line around the object and print out the largest area
Rinse and repeat
And the results:
Rarely I got what I want; Contour detected, red line drawn (GOOD ONE):
...and usually I got this; No contour detected, not red line (BAD ONE):
The chances to get the GOOD ONE are about 1/20 which is not very good. Also, the line of the object's contour in Contours screen will blink when the red line appears around the object (see the GOOD ONE picture).
I'm using one of my object (A small black square box) for this question but please note that the main objective of this object detection program is to detect the object regardless of its shape or its color.
So my questions are:
Why I still get the BAD ONES despite the contour is as clear as day?
Can anyone share a better idea on how to improve the contour detection? (i.e better blur algorithm)
How to avoid the contour's line from blinking when the red line is drawn around the object?
EDIT: I just discovered that contour's line blinking is not because of the red line drawn around it (either with drawContoursor line function) but it happens after the largest contour is detected by findContours function and calculated as the largest contour.
For question about no. 3 click HERE. VIDEO HERE, CLICK IT!!!
Thanks in advance.
PS: I'm using OpenCV 2.4.3 on Ms Visual C++ 2010 Exp.
Since you are using the fact of largest contour so I presume you are trying to detect the largest object appearing in the field of view of the camera.I wonder why the window light/bright light source at top right doesn't create any contour(may be due to blurring). You can store the background image and subtract it from the image where the object appears. This way you can derive the object.You can apply a contour finding in the difference image.absdiff(frame_now,frame_backgrnd,diff) where diff is the difference image.
If the object is in motion and you want to detect you can use optical flow combined with largest contour to detect the object.
Try doing you process without the blurring function and then detect the largest contourArea.
For plotting the points try this
for(int i = 1;i<(int)largest_contours[0].size();i++)
line(image,largest_contours[0][i-1],largest_contours[0][i],cv::Scalar(0,0,255),2,8,0);
I'm trying to locate some regions of a frame, the frame is in Ycbcr color space. and I have to select those regions based on their Y values.
so I wrote this code:
Mat frame. ychannel;
VideoCapture cap(1);
int key =0;
int maxV , minV;
Point max, min;
while(key != 27){
cap >> frame;
cvtColor(frame,yframe,CV_RGB_YCrCb); // converting to YCbCr color space
extractChannel(yframe, yframe, 0); // extracting the Y channel
cv::minMaxLoc(yframe,&minV,&maxV,&min,&max);
cv::threshold(outf,outf,(maxV-10),(maxV),CV_THRESH_TOZERO);
/**
Now I want to use :
cv::rectangle()
but I want to draw a rect around any pixel (see the picture bellow)that's higher than (maxV-10)
and that during the streaming
**/
key = waitKey(1);
}
I draw this picture hopping that it helps to understand what I what to do .
thanks for your help.
Once you have applied your threshold you will end up with a binary image containing a number of connected components, if you want to draw a rectangle around each component then you first need to detect those components.
The OpenCV function findContours does just that, pass it your binary image, and it will provide you with a vector of vectors of points which trace the boundary of each component in your image.
cv::Mat binaryImage;
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binaryImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE)
Then all you need to do is find the bounding rectangle of each of those sets of points and draw them to your output image.
for (int i=0; i<contours.size(); ++i)
{
cv::Rect r = cv::boundingRect(contours.at(i));
cv::rectangle(outputImage, r, CV_RGB(255,0,0));
}
You have to find the each of the connected components, and draw their bounding box.
I want to draw a box over a contour like this
I find contour with this code
vector < vector<Point> > contours;
findContours(Iat, contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
And how to draw a box with rectangle instruction
I don't know how to use vector < vector<Point> > contours Can someone describe this
Thanks is advanced.
You can use the boundingRect method:
Rect boundingRect(InputArray points)
Parameters: points – Input 2D point set, stored in std::vector or Mat.
The function calculates and returns the minimal up-right bounding rectangle for the specified point set.
With this you will be able to use your desired method.