使用OpenCV

时间:2015-08-31 15:23:40

标签: opencv transparency transparent rgba

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

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

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

请注意,weight = 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

答案 1 :(得分: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);

但是我得到的最后一个椭圆显示为weight = 1。

非常感谢你的帮助。