4

I have these two images:

first and
enter image description here
I want to put first onto second. After searching on that forum I tried to do this in that way:

cv::Mat dst(std::max(background.rows, small->rows),std::max(background.cols, small->cols), CV_8UC4);
background.copyTo(dst);
small->copyTo(dst);
cv::imwrite(path_to_save.str(), dst);

Unfortunately, as a result I got only second image. I think that transparent pixels are treated as white pixels and overwrites pixels from first image.

How can I copy only non-transparent pixels?

VirtualUser
  • 215
  • 2
  • 9
  • I gave it a try yesterday with transparent background on person in `python` doesn't work. Alternative, I use [Bitwise Operations](https://docs.opencv.org/trunk/d0/d86/tutorial_py_image_arithmetics.html) and used a green background instead transparent to create the `mask` using this [OpenCV: setting all pixels of specific BGR value to another BGR value](https://stackoverflow.com/questions/11433604/opencv-setting-all-pixels-of-specific-bgr-value-to-another-bgr-value). You can try `dst = cv.addWeighted(img1,0.7,img2,0.3,0)` instead of `dst = cv.add(img1_bg,img2_fg)` at the end. – Santhosh Dhaipule Chandrakanth Sep 07 '19 at 13:32
  • copyTo ALWAYS overwrites. If you want to copy/overwrite only some parts of the image, use masks. If you want to blend images, use a linear combination of two pixels, like alpha x transparent-pixel + (1- alpha) x background-pixel, where alpha could be the values in your alpha channel scaled to 0..1. – Micka Sep 07 '19 at 15:33
  • opencv doesnt have much alpha channel functionality, because this is most often more about image editing or computer graphics than about computer vision. Probably there are better libraries fir this, even Qt might be better suited. – Micka Sep 07 '19 at 15:35

1 Answers1

2

I don't know any direct function from opencv but I wrote explicit approach to do that.

Assumption:

  • Your background is CV_8UC4. In use of that sample you can easily extend that approach to another versions.

Code

void merge_images(cv::Mat* background, cv::Mat* upcoming, int x, int y)
{
    auto handle_cv_8uc4 = [=](int i, int j)
            {

                if(upcoming->at<cv::Vec4b>(j, i)[3] > 10)//10 is only epsilon for trash hold, you can put also 0 or anything else.
                {
                    background->at<cv::Vec4b>(y+j, x+i) = upcoming->at<cv::Vec4b>(j, i);
                }
            };

    auto handle_cv_8uc3 = [=](int i, int j)
    {
        background->at<cv::Vec4b>(y+j, x+i)[0] = upcoming->at<cv::Vec3b>(j, i)[0];
        background->at<cv::Vec4b>(y+j, x+i)[1] = upcoming->at<cv::Vec3b>(j, i)[1];
        background->at<cv::Vec4b>(y+j, x+i)[2] = upcoming->at<cv::Vec3b>(j, i)[2];
        background->at<cv::Vec4b>(y+j, x+i)[3] = 255;
    };

    for(int i = 0; i < upcoming->cols; i++)
    {
        for(int j = 0; j < upcoming->rows; j++)
        {
            if(j + y >= background->rows)
            {
                break;
            }

            if(x + i >= background->cols)
            {
                return;
            }

            switch(upcoming->channels())
            {
                case 3:
                {
                    handle_cv_8uc3(i, j);
                    break;
                }

                case 4:
                {
                    handle_cv_8uc4(i, j);
                    break;
                }

                default:
                {
                    //maybe error?
                }
            }

        }
    }
}

I think this code explains itself. If something is unclear, feel free to ask. Now, if you want to use that code, let say that you have background and spr and you want to put spr to background:

cv::Mat dst(background.rows, background.cols, CV_8UC4);
merge_images(&dst, &background, 0, 0);
merge_images(&dst, &spr, 50, 50);

Explanation

cv::Mat dst(background.rows, background.cols, CV_8UC4);

prepare matrix with size of background (to avoid modifying original background)

merge_images(&dst, &background, 0, 0);

add background to your prepared copy

merge_images(&dst, &spr, 50, 50);

add image such its left corner will be at (50,50)

mvxxx
  • 188
  • 1
  • 7