** ~ Updated ~ **
Hi , I have a source file and i converted it to below picture , and i have a contour in my program
void find_contour(int, void*, Mat _mat)
{
Mat edge_detect_canny;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(_mat, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
Mat drawing = Mat::zeros(_mat.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, 1, Point());
}
IMshow(drawing, "draw-Res", 0);
imwrite("c:\\draw.bmp", drawing);
int cs = contours.size();
cout << cs << "contour.size" << endl;
}
that works fine but i want to add bounding box,find the bounding box for each contour to select all of my objects.
What should I do?
You can get the bounding box for each contour as:
Rect box = boundingRect(contours[i]);
and you can draw it as:
rectangle(drawing, box, color);
So simply add these two lines in the for loop:
Rect box = boundingRect(contours[i]);
rectangle(drawing, box, color);
Related
I have this code where I use Image Moments. I want to draw once a color per shape of the contour. Now if I have five triangles, all of it is drawing in different colors. All I want to do is a way to separate shapes each other, drawing them with the same color.
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(src, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
vector<Moments> mu(contours.size());
vector<Point2f> mc(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mu[i] = moments(Mat(contours[i]), false);
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
for (int i = 0; i < contours.size(); i++)
{
Scalar color(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(dst, contours, i, color, CV_16U, 8, hierarchy);
}
for (int i = 0; i < contours.size(); i++)
{
Scalar color(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(dst, contours, i, color, CV_16U, 8, hierarchy);
}
In the above code Scalar color(.....) defines the colour for each contour. Currently this is in the for loop, as such it creates a new colour for every contour.
Move the Scalar color(.....) out of the for loop and you will only have one colour assigned to the contours.
Scalar color(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
for (int i = 0; i < contours.size(); i++)
{
drawContours(dst, contours, i, color, CV_16U, 8, hierarchy);
}
I would suggest you create a scalar vector containing colors for each of the shape you want. total_shape corresponds to side of the shape you wish to color. For example if you would like to color shapes that includes octagon, then total_shape = 8 + 1. Store the colors to the vector shape_colors.
std::vector<Scalar> shape_colors;
for (int i = 0; i < total_shape; i++)
{
Scalar color(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
shape_colors.push_back(color);
}
Then when you want to color your contour, check out how many points each of your contour has. Based on the point number, select the color from the shape_color and voila, same color scheme for same shape.
However, depending on the angle of the shape, the contour result might return too many points. We need to simplify the contour to the simplest form as possible using approxPolyDP. Meaning we want a rectangle to contain only 4 points, a triangle 3 and a pentagon 5 points. The detailed explanation of this function is given by this link. By doing so, we will be able to determine the shape of contour by the total number of point it contains.
for (int i = 0; i < contours.size(); i++)
{
cv::Mat approx;
approxPolyDP(contours[i], approx, 30, true);
int n = approx.checkVector(2);
drawContours(dst, contours, i, shape_colors[n],25);
}
Here is the entire code:
void process()
{
cv::Mat src;
cv::Mat dst;
cv::RNG rng;
std::string image_path = "Picture1.png";
src = cv::imread(image_path,0);
dst = cv::imread(image_path);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
cv::threshold(src, src, 120, 255, cv::THRESH_BINARY);
findContours(src, contours, hierarchy,
CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
int total_shape = 10;
std::vector<Scalar> shape_colors;
for (int i = 0; i < total_shape; i++)
{
Scalar color(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
shape_colors.push_back(color);
}
for (int i = 0; i < contours.size(); i++)
{
cv::Mat approx;
approxPolyDP(contours[i], approx, 30, true);
int n = approx.checkVector(2);
drawContours(dst, contours, i, shape_colors[n],25);
}
cv::imshow("dst", dst);
cv::waitKey(0);
}
And here is the result :
I'm new to image processing and development.I have a triangle in black background. I want to save that triangle as a Mat object without black pixels[0]. In order to do I tried as below.
Set threshold
find contours
identify contour[0] as trangle // has 2 contours one is triangle other one is backpixels.
save the contour points
crop the image.
My code please find below.
Mat finalImage = imread("test.png, CV_LOAD_IMAGE_GRAYSCALE);
img.copyTo(finalImage, mask);
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Detect edges using canny
Canny(finalImage, canny_output, thresh, thresh * 2, 3);
/// Find contours
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); //find this method
/// Draw contours
Mat drawing = Mat::zeros(canny_output.size(), CV_8UC1);
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()); // find this method.
}
I have points of contour but by using points of contours i have no idea how to crop only the trangle in input image.
You can get the bounding Rect of the various contours at the same time you are re drawing the contours. So in Your for loop where you are iterating the contours, you may use cv::boundingRect() to get the bounding Rect of the respective contour as:
/// Draw contours
Mat drawing = Mat::zeros(canny_output.size(), CV_8UC1);
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()); // find this method.
cv::Rect boundingRect = cv::boundingRect(contours[i]);
}
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 );
}
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
I'm trying to detect pixels that have value higher than let say cvScalar(200,200,200).
And after that I want to draw a rectangle on all those pixel using cv::rectangle. Can anybody help me how to do this?
see this figure below to it exactly what I want to do.
![ image ] : http://technical-recipes.com/wp-content/uploads/2011/10/glove3.jpg
Here's how I solve your problem:
I found all needed pixels using inRange.
After this, I found all contours.
Then I constructed big contour from all these contours.
Finally, found boundingRect of this big contour and draw it.
Here's a c++ code:
Mat src = imread("image.jpg"), mask;
const Scalar minScalar = Scalar(200, 200, 200);
const Scalar maxScalar = Scalar(255, 255, 255);
inRange(src, minScalar, maxScalar, mask);
vector<vector<Point2i> > contours;
findContours(mask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
vector<Point2i> bigContour;
for (int i=0; i<contours.size(); i++)
{
for (int j=0; j<contours[i].size(); j++)
{
bigContour.push_back(contours[i][j]);
}
}
Rect rect = boundingRect(bigContour);
rectangle(src, rect, Scalar(255, 0, 255));
imshow("Image", src);
waitKey();