Ask Your Question

Revision history [back]

Looking at this post: http://jepsonsblog.blogspot.be/2012/10/overlay-transparent-image-in-opencv.html

I noticed his following remark

This code only works if:

  • The background is in BGR colour space.
  • The foreground is in BGRA colour space.

The output image will always be of the same size as the background image, in BGR colour space. The position parameter determines how the foreground is placed on top of the background. A position of (100, -50) will move the foreground 100 pixels to the right and 50 pixels up.

SO I am guessing you cannot read both images as CV_LOAD_IMAGE_UNCHANGED, which would make both images of type BGRA.

Looking at this post: http://jepsonsblog.blogspot.be/2012/10/overlay-transparent-image-in-opencv.html

I noticed his following remarktaking Max5684 comment

// http://jepsonsblog.blogspot.be/2012/10/overlay-transparent-image-in-opencv.html
// https://gist.github.com/maximus5684/082f8939edb6aed7ba0a

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;

void overlayImage(Mat* src, Mat* overlay, const Point& location)
{
  for (int y = max(location.y, 0); y < src->rows; ++y)
  {
    int fY = y - location.y;

    if (fY >= overlay->rows)
      break;

    for (int x = max(location.x, 0); x < src->cols; ++x)
    {
      int fX = x - location.x;

      if (fX >= overlay->cols)
        break;

      double opacity = ((double)overlay->data[fY * overlay->step + fX * overlay->channels() + 3]) / 255;

      for (int c = 0; opacity > 0 && c < src->channels(); ++c)
      {
        unsigned char overlayPx = overlay->data[fY * overlay->step + fX * overlay->channels() + c];
        unsigned char srcPx = src->data[y * src->step + x * src->channels() + c];
        src->data[y * src->step + src->channels() * x + c] = srcPx * (1. - opacity) + overlayPx * opacity;
      }
    }
  }
}

int main( int argc, char** argv )
{
    Mat underlay = imread("14447300874345549.png",IMREAD_UNCHANGED);
    Mat overlay = imread("14447300692773615.png",IMREAD_UNCHANGED);
    Mat test = imread("1429209553641108.png",IMREAD_UNCHANGED);

    if( underlay.empty() || overlay.empty() || test.empty() )
    {
        cout << "Could not read input image files " << endl;
        return -1;
    }

    overlayImage( &underlay, &overlay, Point() );
    overlayImage( &test, &underlay, Point(120,180) );

    imwrite("result.png",test);
    imshow("result",test);
    waitKey();

    return 0;
}

Test Images :

image description

image description image description

Result Image:

image description

This code only works if:

  • The background is in BGR colour space.
  • The foreground is in BGRA colour space.

The output image will always be of the same size as the background image, in BGR colour space. image. The position parameter determines how the foreground is placed on top of the background. A position of (100, -50) will move the foreground 100 pixels to the right and 50 pixels up.

SO I am guessing you cannot read both images as CV_LOAD_IMAGE_UNCHANGED, which would make both images of type BGRA.

Looking at this post: http://jepsonsblog.blogspot.be/2012/10/overlay-transparent-image-in-opencv.html

taking Max5684 comment

// http://jepsonsblog.blogspot.be/2012/10/overlay-transparent-image-in-opencv.html
// https://gist.github.com/maximus5684/082f8939edb6aed7ba0a

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;

void overlayImage(Mat* src, Mat* overlay, const Point& location)
{
  for (int y = max(location.y, 0); y < src->rows; ++y)
  {
    int fY = y - location.y;

    if (fY >= overlay->rows)
      break;

    for (int x = max(location.x, 0); x < src->cols; ++x)
    {
      int fX = x - location.x;

      if (fX >= overlay->cols)
        break;

      double opacity = ((double)overlay->data[fY * overlay->step + fX * overlay->channels() + 3]) / 255;

      for (int c = 0; opacity > 0 && c < src->channels(); ++c)
      {
        unsigned char overlayPx = overlay->data[fY * overlay->step + fX * overlay->channels() + c];
        unsigned char srcPx = src->data[y * src->step + x * src->channels() + c];
        src->data[y * src->step + src->channels() * x + c] = srcPx * (1. - opacity) + overlayPx * opacity;
      }
    }
  }
}

int main( int argc, char** argv )
{
    Mat underlay = imread("14447300874345549.png",IMREAD_UNCHANGED);
    Mat overlay = imread("14447300692773615.png",IMREAD_UNCHANGED);
    Mat test = imread("1429209553641108.png",IMREAD_UNCHANGED);

    if( underlay.empty() || overlay.empty() || test.empty() )
    {
        cout << "Could not read input image files " << endl;
        return -1;
    }

    overlayImage( &underlay, &overlay, Point() );
);     
    overlayImage( &test, &underlay, Point(120,180) );

    imwrite("result.png",test);
    imshow("result",test);
imwrite("result1.png",underlay);   
    imwrite("result2.png",test);

    imshow("result1",underlay);
    imshow("result2",test);
    waitKey();

    return 0;
}

Test Images :

image description

image description image description

Result Image:Images:

image description image description

The output image will always be of the same size as the background image. The position parameter determines how the foreground is placed on top of the background. A position of (100, -50) will move the foreground 100 pixels to the right and 50 pixels up.

Looking at this post: http://jepsonsblog.blogspot.be/2012/10/overlay-transparent-image-in-opencv.html

taking Max5684 comment

// http://jepsonsblog.blogspot.be/2012/10/overlay-transparent-image-in-opencv.html
// https://gist.github.com/maximus5684/082f8939edb6aed7ba0a

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;

void overlayImage(Mat* src, Mat* overlay, const Point& location)
{
   for (int y = max(location.y, 0); y < src->rows; ++y)
   {
     int fY = y - location.y;

     if (fY >= overlay->rows)
       break;

     for (int x = max(location.x, 0); x < src->cols; ++x)
     {
       int fX = x - location.x;

       if (fX >= overlay->cols)
         break;

       double opacity = ((double)overlay->data[fY * overlay->step + fX * overlay->channels() + 3]) / 255;

       for (int c = 0; opacity > 0 && c < src->channels(); ++c)
       {
         unsigned char overlayPx = overlay->data[fY * overlay->step + fX * overlay->channels() + c];
         unsigned char srcPx = src->data[y * src->step + x * src->channels() + c];
         src->data[y * src->step + src->channels() * x + c] = srcPx * (1. - opacity) + overlayPx * opacity;
       }
     }
   }
}

int main( int argc, char** argv )
{
    Mat underlay = imread("14447300874345549.png",IMREAD_UNCHANGED);
    Mat overlay = imread("14447300692773615.png",IMREAD_UNCHANGED);
    Mat test = imread("1429209553641108.png",IMREAD_UNCHANGED);

    if( underlay.empty() || overlay.empty() || test.empty() )
    {
        cout << "Could not read input image files " << endl;
        return -1;
    }

    Mat rgba[4];
    split(underlay,rgba);
    imshow("alpha1.png",rgba[3]);
    imwrite("alpha1.png",rgba[3]);

    split(overlay,rgba);
    imshow("alpha2.png",rgba[3]);
    imwrite("alpha2.png",rgba[3]);

    overlayImage( &underlay, &overlay, Point() );     
);
    overlayImage( &test, &underlay, Point(120,180) );

    imwrite("result1.png",underlay);   
split(underlay,rgba);
    imshow("alpha3.png",rgba[3]);
    imwrite("alpha3.png",rgba[3]);

    imshow("result1",underlay);
    imwrite("result1.png",underlay);
    imshow("result2",test);
    imwrite("result2.png",test);

    imshow("result1",underlay);
    imshow("result2",test);
    waitKey();

    return 0;
}

Test Images :

image description

image description image description

Result Images:

image description image description

Alpha channels before:

image description image description

Alpha channel of result:

image description

The output image will always be of the same size as the background image. The position parameter determines how the foreground is placed on top of the background. A position of (100, -50) will move the foreground 100 pixels to the right and 50 pixels up.