Calculating the area of Bounding Box - c++

Hello StackOverflowers
I have created an application that Segments an image on the basis of a predefined color using inRange function. I then draw bounding box around the detected object.
My question here is how do I determine region properties such as: area, size, height and with, center point.
Here i placed a screen dump example.....
How should i approach to retrieve region properties of these bounding boxes or any other bounding boxes that get drown.......?
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(mBlur, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Approximate contours to polygons + get bounding rects and circles
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
vector<Point2f>center( contours.size() );
vector<float>radius( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) );
}
/// Draw polygonal contour + bonding rects
Mat drawing = Mat::zeros( range_out.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar(255,0,255);
drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
}
Regards

You can get the area by using the built in OpenCV function. There are other functions there too to get everything you need.

Just iterate over the 2D coordinates of the segmented shape (the thin pink line in your pictures, you can found this just checking which pixels are not black and looking into its coordinates) and store maximum and minimum X and Y found. Then, width of is maxX - minX and height is maxY - minY

void visualizeSegments(Mat& img, Mat& dst)
{
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
dst=Mat::zeros(img.size(), CV_8UC3);
for(int i = 0; i < contours.size(); i++)
{
//Moments mu = moments(contours[i], true );
//Point2f centroid(mu.m10/mu.m00,mu.m01/mu.m00);
//double area = fabs(contourArea(Mat(contours[i])));
//vector<Point> contours_poly;
//approxPolyDP(Mat(contours[i]), contours_poly, 3, true);
//Rect boundRect = boundingRect(Mat(contours_poly));
drawContours(dst, contours, i, Scalar(255,0,0), -1, 8, hierarchy);
}
}

As stated befor there are a set of usefull functions in OpenCV
1. double contourArea(InputArray contour, bool oriented=false ) : to comute the area
2. double arcLength(InputArray curve, bool closed) : to compute the perimeter
3. Moments moments(InputArray array, bool binaryImage=false ) : to compute the center of gravity
4. void HuMoments(const Moments& m, OutputArray hu) : if you want additional properties that is usefull for classification

Related

OpenCV detect darkened rectangle

I am trying to use OpenCV to isolate the translucent darkened rectangular region which has lots of text overlayed. These rectanglular regions can vay in size and location in the window. Is there a way to detect these darkened regions?
Maybe it would be easier to apply some diff operation and compare to the frame before the dark region overlay is shown?
This should give you all bounding boxes based on two images.
#include <cv.h>
#include <highgui.h>
using namespace cv;
Mat im = imread("original.jpg");
Mat im2 = imread("darkened.jpg");
Mat diff_im = im - im2;
Mat diff_im_binary;
threshold(diff_im, diff_im_binary, 30, 255, THRESH_BINARY);
findContours(diff_im_binary, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Approximate contours to polygons + get bounding rects and circles
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
vector<Point2f>center( contours.size() );
vector<float>radius( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) );
}

Draw Rect around result of canny edge

I want to draw Rect around detected canny edges. I have this image which is result of eye detection, morphological operations and canny edge.
I tried using contours to bound it by rect but result was not accurate.
How can I get some thing like this image?
I'm using this function to draw contours:
void find_contour(Mat image)
{
Mat src_mat, gray_mat, canny_mat;
Mat contour_mat;
Mat bounding_mat;
contour_mat = image.clone();
bounding_mat = image.clone();
cvtColor(image, gray_mat, CV_GRAY2BGR);
// apply canny edge detection
Canny(gray_mat, canny_mat, 30, 128, 3, false);
//3. Find & process the contours
//3.1 find contours on the edge image.
vector< vector< cv::Point> > contours;
findContours(canny_mat, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//3.2 draw contours & property value on the source image.
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
for (size_t i = 0; i< contours.size(); i++) // iterate through each contour.
{
double area = contourArea(contours[i]); // Find the area of contour
if (area > largest_area)
{
largest_area = area;
largest_contour_index = i; //Store the index of largest contour
bounding_rect = boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
}
}
drawContours(image, contours, largest_contour_index, Scalar(0, 255, 0), 2);
imshow("Bounding ", image);
}
in your code you aren't drawing the bounding rectangle at all. Try this:
void find_contour(Mat image)
{
Mat src_mat, gray_mat, canny_mat;
Mat contour_mat;
Mat bounding_mat;
contour_mat = image.clone();
bounding_mat = image.clone();
cvtColor(image, gray_mat, CV_GRAY2BGR);
// apply canny edge detection
Canny(gray_mat, canny_mat, 30, 128, 3, false);
//3. Find & process the contours
//3.1 find contours on the edge image.
vector< vector< cv::Point> > contours;
findContours(canny_mat, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//3.2 draw contours & property value on the source image.
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
for (size_t i = 0; i< contours.size(); i++) // iterate through each contour.
{
// draw rectangle around the contour:
cv::Rect boundingBox = boundingRect(contours[i]);
cv::rectangle(image, boundingBox, cv::Scalar(255,0,255)); // if you want read and "image" is color image, use cv::Scalar(0,0,255) instead
// you aren't using the largest contour at all? no need to compute it...
/*
double area = contourArea(contours[i]); // Find the area of contour
if (area > largest_area)
{
largest_area = area;
largest_contour_index = i; //Store the index of largest contour
bounding_rect = boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
}
*/
}
//drawContours(image, contours, largest_contour_index, Scalar(0, 255, 0), 2);
imshow("Bounding ", image);
}
You can do it like this also,
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
vector<RotatedRect> minRect( contours.size() );
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar(255, 255, 255);
cv::Rect boundingBox = cv::boundingRect(cv::Mat(contours[i]));
minRect[i] = minAreaRect(Mat(contours[i]));
drawContours( drawing, contours, i, color, 1, 8, hierarchy, 0, Point() );
}
for( int i = 0; i< contours.size(); i++ )
{
// rotated rectangle
Point2f rect_points[4]; minRect[i].points( rect_points );
for( int j = 0; j < 4; j++ )
line( drawing, rect_points[j], rect_points[(j+1)%4], Scalar(0,0,255), 1, 8 );
}

FindContour: Measure distance between contours

I would be very thankful to know further on post: Finding Minimum Distance between Contours
I am using FindContours and as required getting multiple contours.
The problem is that I want to find min distance between each adjacent pair,
e.g. between yellow contour and dark green, between dark green and cyan, between cyan and purple.
I understood the general method from above post.
But can anyone please tell me how can i select them one after another(automaticaly)?
void thresh_function(int, void*)
{
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using canny
Canny( roiImg, canny_output, threshold_value, threshold_value*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, 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() );//Scalar(255,255,255)
}
erode(drawing,drawing,erodeElement2);
erode(drawing,drawing,erodeElement1);
dilate(drawing,drawing,dilateElement);
/// Show in a window
//namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
resize(drawing, enlargeD0, Size(), 2, 2, CV_INTER_CUBIC);
done = 1;
imshow("Contours", enlargeD0);
}
vector<vector<Point> > all_contours;
...
findContours(... all_contours ... CV_CHAIN_APPROX_NONE ...);
...
// Remove small contours
int minSize = 20;
vector<vector<Point> > contours;
contours.reserve(all_contours.size());
for(int i=0; i<all_contours.size(); ++i)
{
if(all_contours[i].size() > minSize)
{
contours.push_back(all_contours[i]);
}
}
Mat1f dist(contours.size(), contours.size(), 0.f);
for(int i=0; i<contours.size()-1; ++i)
{
const vector<Point>& firstContour = contours[i];
for(int j=i+1; j<contours.size(); ++j)
{
const vector<Point>& secondContour = contours[j];
float d = compute_pairwise_distance(firstContour, secondContour); // You should implement this
dist(i,j) = d;
dist(j,i) = d; // distance from first to second is equal
// to distance from second to first
}
}
// Now dist contains the pairwise distances between i-th and j-th contours

remove bounding boxes inside bounding boxes for number recognition

I am trying a number recognition. However after contour finding. I get bounding boxes inside the main bounding box for numbers 0,6,8 ... as shown in figure. Please help me with this initial step of image processing.
I have tried using group rectangles but they are not working. Please check the code below. Thank you.
Image: http://tinypic.com/r/1twx05/5
int main()
{
Mat inimage, gray;
inimage = imread("sample.jpg");
cvtColor(inimage, gray, COLOR_BGR2GRAY);
GaussianBlur(gray, gray, Size(5,5), 0);
adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 11, 0);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( gray, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) );
}
//groupRectangles(boundRect, 1, 0.2);
Scalar color = Scalar(0,0,255);
for( int i = 0; i< contours.size(); i++ )
{
//drawContours( inimage, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
rectangle( inimage, boundRect[i].tl(), boundRect[i].br(), color, 1, 8, 0 );
}
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", inimage );
waitKey(0);
return 0;
}
try to use the flag: CV_RETR_EXTERNAL instead of CV_RETR_TREE
as stated in the docs it tells to take only outer contours.
Or follow the tree hierarchy to drop nested contours (read the docs for how-to)

Drawing Convexity Defects C++ OpenCV

From the code below, I am able to draw the biggest contour with the centroid marked as a small circle and the hull as a yellow line. How do I draw the convexity defects? Should I use the circle() function or the drawContours() function?
Mat bw;
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( bw, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
int s = getBiggestContour(contours);
Mat drawing = Mat::zeros( src.size(), CV_8UC3 ); //UC1
Point2f mc = getCentroidPoint(contours[s]);
drawContours( drawing, contours, s, Scalar(255,255,255), -1, 8, hierarchy, 0, Point() );
circle( drawing, mc, 4, Scalar(0,0,255), 1, 8, 0 );
vector<vector<Point> >hull( contours[s].size() );
convexHull( Mat(contours[s]), hull[s], false );
drawContours( drawing, hull, s, Scalar(0,255,255), 1, 8, vector<Vec4i>(), 0, Point() );
The code above works but there's only one contour to be used which is the biggest contour so I think using vector> for hull is too much. How do I simplify that?
The code below is from another stackoverflow question but it doesn't show how to use the defects variable in drawing the convexity defect onto the Mat image. How can this be achieved?
vector<vector<int> > hullsI(contours.size());
vector<vector<Point> > hullsP(contours.size());
vector<vector<Vec4i> > defects(contours.size());
for(int i = 0; i <contours.size(); ++i){
//find the hulls
convexHull(contours[i], hullsI[i], false, false);
convexHull(contours[i], hullsP[i], false, true);
//find the defects
if (contours[i].size() >3 ){
convexityDefects(contours[i], hullsI[i], defects[i]);
}
}
I do not want to use IplImage. I prefer Mat.
You can draw the result of a convex hull operation with 'cvDrawContours()', but you do need to set your parameters correct for that to be possible. I have an example but it uses 'cvConvexHull2()' and IplImages but it should work the same way for a Mat and the other convexHull operation:
IplImage* src; //the image where the contours are detected on
IplImage frm; //the image you want the results to be drawn on
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contours = NULL;
cvFindContours(src, storage, &contours, sizeof (CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
for (CvSeq* c = contours; c != NULL; c = c->h_next) {
CvSeq* dest = NULL;
CvMemStorage* hullStorage = cvCreateMemStorage(0);
dest = cvConvexHull2(c, hullStorage, CV_CLOCKWISE, 1);
cvDrawContours(frm, dest, cvScalarAll(255), cvScalarAll(255), 0, 2, 8);
cvReleaseMemStorage(&hullStorage);
}
cvReleaseMemStorage(&storage);