OpenCV: add matrices containing alpha information 'on top of each other' using C++

StackOverflow https://stackoverflow.com/questions/23427712

  •  14-07-2023
  •  | 
  •  

Вопрос

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();
}
Это было полезно?

Решение

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);
        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top