Question

Please consider the MWE below. I have a matrix (output) that corresponds to a graphics output buffer and some layers, that should be put into that buffer in a specific order. The layers contain alpha information (last byte). If all layers have the alpha bytes of all pixels set to 0xFF, only the layer on top can be seen. If all have the alpha value set to 0, none can be seen. There can be an alpha value between 0 and 0xFF, so the corresponding pixel should be semi-transparent.

I tried to use addWeighted(), but this didn't help (see below): All images are visible no matter what value the alpha byte is set to.

Do you have any idea how this can be realized?

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;

void test(){
    namedWindow("window", WINDOW_AUTOSIZE);

    Mat output(Size(300, 300), CV_8UC4, Scalar(0));

    Mat m1(Size(300, 300), CV_8UC4, Scalar(0));
    Mat m2(Size(300, 300), CV_8UC4, Scalar(0));
    Mat m3(Size(300, 300), CV_8UC4, Scalar(0));

    circle(m1, Point(130, 130), 75, Scalar(0, 0, 0xFF, 0xFF), -1);
    circle(m2, Point(150, 150), 75, Scalar(0, 0xFF, 0, 0xFF), -1);
    rectangle(m3, Rect(100, 100, 60, 60), Scalar(0xFF, 0, 0, 0xFF), -1);
    rectangle(m3, Rect(115, 115, 30, 30), Scalar(0), -1);

    /*
     Output should look like
    [   m3   ] <-- top
    [   m2   ]
    [   m1   ] <-- bottom
    */

    //What I've tried so far (the final solution should work for more than 3 'layers')
    m1.copyTo(output);
    addWeighted(output, .5, m2, .5, 0, output);
    addWeighted(output, .5, m3, .5, 0, output);

    imshow("window", output);
    cvWaitKey(0);

    destroyAllWindows();
}
Was it helpful?

Solution

I'm not sure if this is the best way to do it, but this will maybe do the job.

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>

using namespace cv;

void addAlpha(Mat src, Mat input);

void test(){
    namedWindow("window", WINDOW_AUTOSIZE);

    Mat output(Size(300, 300), CV_8UC4, Scalar(0));

    Mat m1(Size(300, 300), CV_8UC4, Scalar(0));
    Mat m2(Size(300, 300), CV_8UC4, Scalar(0));
    Mat m3(Size(300, 300), CV_8UC4, Scalar(0));

    circle(m1, Point(130, 130), 75, Scalar(0, 0, 0xFF, 0xFF), -1);
    circle(m2, Point(150, 150), 75, Scalar(0, 0xFF, 0, 0xFF), -1);
    rectangle(m3, Rect(100, 100, 60, 60), Scalar(0xFF, 0, 0, 0xFF), -1);
    rectangle(m3, Rect(115, 115, 30, 30), Scalar(0), -1);


    m1.copyTo(output);

    addAlpha(output,m2);
    addAlpha(output,m3);

    imshow("window", output);
    cvWaitKey(0);

    destroyAllWindows();
}

void addAlpha(Mat src, Mat input){
    if(src.rows != input.rows || src.cols != input.cols){
        perror("Not same size");
    }
    for(int i = 0; i < src.rows; i++){
        for(int j = 0; j < src.cols; j++){
            src.at<cv::Vec4b>(i,j)[0] = src.at<cv::Vec4b>(i,j)[0] * (1 - input.at<cv::Vec4b>(i,j)[3]/255.0) + input.at<cv::Vec4b>(i,j)[0] * (input.at<cv::Vec4b>(i,j)[3]/255.0);
            src.at<cv::Vec4b>(i,j)[1] = src.at<cv::Vec4b>(i,j)[1] * (1 - input.at<cv::Vec4b>(i,j)[3]/255.0) + input.at<cv::Vec4b>(i,j)[1] * (input.at<cv::Vec4b>(i,j)[3]/255.0);
            src.at<cv::Vec4b>(i,j)[2] = src.at<cv::Vec4b>(i,j)[2] * (1 - input.at<cv::Vec4b>(i,j)[3]/255.0) + input.at<cv::Vec4b>(i,j)[2] * (input.at<cv::Vec4b>(i,j)[3]/255.0);
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top