Reputation: 59
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);
}
Upvotes: 0
Views: 1729
Reputation: 1839
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);
}
Upvotes: 1
Reputation: 11721
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);
}
Upvotes: 1