我目前正在使用 opencv 在白色背景中绘制椭圆以及 X 和 Y 轴,如下所示:
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);
这是有N个椭圆并且它们重叠。另外,还有一个与颜色(从蓝色到红色)相对应的权重值。我想使用这个权重值来将其用作 alpha 参数。
就我所见,可以使用 addWeigth 函数,但它位于两个图像之间,我想用省略号来实现。有什么方法可以做到这一点,或者我必须每个椭圆有一个图像并使用 addWeigth 与 image0 和 image1,然后(image0 和 image1)和 image2 等等?
感谢您的帮助。
这是一个简单的示例程序,它使用临时椭圆图像来绘制透明椭圆。
请注意,权重 = 1 意味着椭圆不是透明的而是实心的,因此椭圆“下方”的任何内容都不再可见。而且绘图的顺序确实有所不同!
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;
}
这里绘制的厚度为15
我只用两个实心椭圆测试了你的代码,一个红色,一个蓝色,尺寸为 (1,2) 和 (2,1),红色的权重为 0.8,蓝色的权重为 0.2。因此,我应该(或者我想)以红色椭圆 @ 0.8 和蓝色椭圆 @ 0.2 结束。它们重叠的地方应该是红色和蓝色的混合,对吧?另外,如果我正确理解了您的代码,第一个椭圆将被完全绘制,但是当绘制第二个椭圆时,将显示仅在它们之间重叠的部分。我说得对吗? 我收到了你的代码,最后得到了这个:
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);
但我只得到了最后一个椭圆,其权重=1。
非常感谢您的帮助。