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 );
}
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 have this image the vascular bundle
My work is to find the centroid of the blood vessels ,
I tried Image moments but I have this error message error
My code is here:
int main() {
cv::Mat img = imread("C:\\Users\\ASUS\\Desktop\\fond1.png ", CV_LOAD_IMAGE_COLOR);
Mat blue, green, red, step1, otsu, step11, green1, blue1;
Mat bgr[3]; //destination array
split(img, bgr);//split source
red.push_back(bgr[2]);
Moments mu = moments(red,true);
Point center;
center.x = mu.m10 / mu.m00;
center.y = mu.m01 / mu.m00;
circle(red, center, 2, Scalar(0, 0, 255));
imshow("Result",red);
Mat mask(red.size(), CV_8UC1, Scalar::all(0));
// Create Polygon from vertices
vector<Point> ROI_Vertices(3);
ROI_Vertices.push_back(Point(0,0 ));
ROI_Vertices.push_back(Point(center.x, center.y));
ROI_Vertices.push_back(Point(0,red.rows -1));
vector<Point> ROI_Poly;
approxPolyDP(ROI_Vertices, ROI_Poly, 1.0, true);
// Fill polygon white
fillConvexPoly(mask, &ROI_Poly[0], ROI_Poly.size(), 255, 8, 0);
Mat hide(red.size(), CV_8UC3);
red.copyTo(hide, mask);
imshow("mask", hide);
Mat blackhat,tophat,dst;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(6,6));
morphologyEx(hide, blackhat, MORPH_BLACKHAT, element);
imshow("step1", blackhat);
morphologyEx(blackhat, tophat, MORPH_TOPHAT, element);
imshow("step2", tophat);
cv::Mat r1 = cv::Mat::zeros(dst.rows, dst.cols, CV_8UC1);
tophat.copyTo(r1);
imshow("vessel", r1);
threshold(r1, dst, 9, 255, THRESH_BINARY);
// Find contours
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
///Get the moments
Mat canny_output;
// detect edges using canny
Canny(dst, canny_output, 50, 150, 3);
// find contours
findContours(canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
// get the moments
vector<Moments> mu(contours.size());
for (int i = 0; i<contours.size(); i++)
{
mu[i] = moments(contours[i], false);
}
// get the centroid of figures.
vector<Point2f> mc(contours.size());
for (int i = 0; i<contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
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 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
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