使用 OpenCV 绘制透明的椭圆

问题描述 投票:0回答:2

我目前正在使用 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 等等?

感谢您的帮助。

c++ opencv transparency transparent rgba
2个回答
0
投票

这是一个简单的示例程序,它使用临时椭圆图像来绘制透明椭圆。

请注意,权重 = 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;
}

enter image description here

这里绘制的厚度为15

enter image description here


0
投票

我只用两个实心椭圆测试了你的代码,一个红色,一个蓝色,尺寸为 (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。

非常感谢您的帮助。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.