Reputation: 57
I am currently plotting ellipses in a white background as well as X and Y axis with opencv like this:
Mat image = Mat::zeros(size,size, CV_8UC3);
image.setTo(Scalar(255,255,255)); /* White background */
/* Draw Axis */
line(image,
Point(originX, 0), /*Point 1*/
Point(originX, size), /*Point 2*/
Scalar(colorAxis.B,colorAxis.G,colorAxis.R), /*Color*/
1, /*Thickness*/
8); /*lineType*/
line(image,
Point(0, originY), /*Point 1*/
Point(size, originY), /*Point 2*/
Scalar(colorAxis.B,colorAxis.G,colorAxis.R), /*Color*/
1, /*Thickness*/
8);
for(i=0; i<numEllipses; i++)
{
ellipse(image,
Point(originX + dataEllipse[k].center[0]*ppu, originY - dataEllipse[k].center[1]*ppu),
Size(dataEllipse[k].axis[0]*ppu, dataEllipse[k].axis[1]*ppu),
-dataEllipse[k].angle,
0,
360,
Scalar(colorEllipse.B, colorEllipse.G, colorEllipse.R),
-1,
CV_FILLED);
}
imshow("Result", image);
waitKey(1);
The this is that there are an N number of ellipses and they overlap. Plus there is a weight value that corresponds to a color (from blue to red). I would like to use this weight value to use it as an alpha parameter as well.
For what I've seen it is possible to use an addWeigth function but it is between two images and I would like to do it with the ellipses. Is there any way to do it or I would have to have one image per ellipse and use addWeigth with image0 and image1, then (image0 and image1) and image2 and so on?
Thanks for the help.
Upvotes: 2
Views: 1125
Reputation: 57
I tested your code with just two filled ellipses, one red and one blue with sizes (1,2) and (2,1) with 0.8 weight for the red and 0.2 for the blue one. Therefore, I should (or I want to) end with the red ellipse @ 0.8 and the blue one @ 0.2. And where they overlap it should be a mix between red and blue, right? Plus if I understood correctly your code, the first ellipse will be plotted completely but when the second one is plotted, the parts that only overlap between them will be shown. Am I right? I got your code and I ended up with this:
cv::Mat background = cv::Mat(size,size, CV_8UC3, cv::Scalar(255,255,255));
int color[nEll][3] = {{255,0,0},{0,0,255}}, y,x, s[nEll][2]={{2,1},{1,2}};
float weights[nEll] = {0.8, 0.2};
for(i=0; i<nEll; i++)
{
Mat temporaryEllipse = Mat::zeros(size,size, CV_8UC3);
Mat temporaryMask = Mat::zeros(size,size,CV_8UC1);
// draw ellipse to temporary
ellipse(temporaryEllipse,
Point(originX + 0.5*ppu, originY - 0.5*ppu),
Size(s[i][0]*ppu, s[i][1]*ppu),
0,//angle
0,
360,
Scalar(color[i][0], color[i][1], color[i][2]),
-1,
CV_FILLED);
// draw same ellipse to mask
ellipse(temporaryMask,
Point(originX + 0.5*ppu, originY - 0.5*ppu),
Size(s[i][0]*ppu, s[i][1]*ppu),
0,//angle
0,
360,
Scalar(color[i][0], color[i][1], color[i][2]),
-1,
CV_FILLED);
for(y=0; y<temporaryEllipse.rows; ++y)
{
for(int x=0; x<temporaryEllipse.cols; ++x)
{
// only blend pixel that belong to the ellipse
if(temporaryMask.at<unsigned char>(y,x))
{
cv::Vec3b ellipsePixel = temporaryEllipse.at<cv::Vec3b>(y,x);
cv::Vec3b backgroundPixel = background.at<cv::Vec3b>(y,x);
cv::Vec3b blendedPixel = weights[i]*ellipsePixel + (1-weights[i])*backgroundPixel;
// update result
background.at<cv::Vec3b>(y,x) = blendedPixel;
}
}
}
}
cv::imshow("input", background);
But I got just the last ellipse shown with weight=1.
Thank you very much for your help.
Upvotes: -1
Reputation: 20160
Here's a simple sample program which uses temporary ellipse images for drawing transparent ellipses.
Note that weight = 1 means that the ellipse isn't transparent but solid, so nothing "under" that ellipse is visible anymore. And the order of drawing does make a difference!
int main()
{
//cv::Mat input = cv::imread("../inputData/Lenna.png");
cv::Mat background = cv::Mat(512,512, CV_8UC3, cv::Scalar(255,255,255));
std::vector<cv::Point2f> centers;
std::vector<cv::Scalar> colors;
std::vector<cv::Size> axes;
std::vector<float> angles;
std::vector<float> weights;
// make sure that there are same number of entries in each vector.
centers.push_back(cv::Point2f(255, 255));
centers.push_back(cv::Point2f(275, 255));
centers.push_back(cv::Point2f(255, 275));
centers.push_back(cv::Point2f(275, 275));
centers.push_back(cv::Point2f(255, 225));
centers.push_back(cv::Point2f(225, 225));
colors.push_back(cv::Scalar(255,0,0));
colors.push_back(cv::Scalar(0,255,0));
colors.push_back(cv::Scalar(0,0,255));
colors.push_back(cv::Scalar(0,0,0));
colors.push_back(cv::Scalar(0,0,0));
colors.push_back(cv::Scalar(0,255,0));
axes.push_back(cv::Size(128,128));
axes.push_back(cv::Size(128,128));
axes.push_back(cv::Size(128,128));
axes.push_back(cv::Size(128,128));
axes.push_back(cv::Size(128,128));
axes.push_back(cv::Size(128,128));
angles.push_back(0);
angles.push_back(0);
angles.push_back(0);
angles.push_back(0);
angles.push_back(0);
angles.push_back(0);
// weight 0 means completely transparent = invible. weight 1 means completely solid = will overwrite everything else
weights.push_back(0.5f); // half transparent
weights.push_back(0.5f);
weights.push_back(0.5f);
weights.push_back(1.0f); // solid
weights.push_back(0.3f); // quite transparent
weights.push_back(0.3f); // quite transparent
// ORDER DOES MATTER!
// printing a transparent ellipse over a solid ellipse will make the transparent ellipse partly visible, but printing the solid ellipse over anything will make only the solid ellipse visible
// you could however sort ellipses before printing so that more solid ones are more in the background for example
int thickness = 5;
for(unsigned int i=0; i<centers.size(); ++i)
{
cv::Mat temporaryEllipse = cv::Mat::zeros(background.rows, background.cols, background.type()); // same size and type as background;
cv::Mat temporaryMask = cv::Mat::zeros(background.rows, background.cols, CV_8UC1); // empty single channel 8bit mask
// draw ellipse to temporary
cv::ellipse(temporaryEllipse, centers[i], axes[i], angles[i], 0, 360, colors[i], thickness);
// draw same ellipse to mask
cv::ellipse(temporaryMask, centers[i], axes[i], angles[i], 0, 360, 255, thickness);
for(int y=0; y<temporaryEllipse.rows; ++y)
for(int x=0; x<temporaryEllipse.cols; ++x)
{
// only blend pixel that belong to the ellipse!
if(temporaryMask.at<unsigned char>(y,x))
{
cv::Vec3b ellipsePixel = temporaryEllipse.at<cv::Vec3b>(y,x);
cv::Vec3b backgroundPixel = background.at<cv::Vec3b>(y,x);
float weight = weights[i];
cv::Vec3b blendedPixel = weight*ellipsePixel + (1-weight)*backgroundPixel;
// update result
background.at<cv::Vec3b>(y,x) = blendedPixel;
}
}
}
cv::imshow("input", background);
cv::imwrite("../outputData/TransparentEllipses.png", background);
cv::waitKey(0);
return 0;
}
and here drawn with a thickness of 15
Upvotes: 1