3

Recently, I'm interested in image processing using OpenCV, but I'm new to it.

I do some simple image processing on a lot of images, and finally I want to watermark each image with a logo which is a small png image.

There are a lot of codes which blend two images. Here is an example which I used to blend two images:

int main( int argc, char** argv )
{
        double alpha = 0.5; double beta; double input;
        Mat src1, src2, dst;

        // main image with real size.(Large)
        src1 = imread("a.jpg");

        // logo which will be used as a watermark.(small size)
        src2 = imread("logo.png");

        namedWindow("Linear Blend", 1);
        beta = ( 1.0 - alpha );

        addWeighted( src1, alpha, src2, beta, 0.0, dst);

        imshow( "Linear Blend", dst );

        waitKey(0);
        return 0;
}

Here, both images should be the same type and the same size, while my logo image is a small image which I want to blend to the main image in a corner (actually at an arbitrary point).

Can anyone help me to do that? (Maybe, one solution is to create a matrix from the logo which is the same size of the main image so every point outside of the logo should be zero and then finally blend two images which have equal size.)

my final code is like this:

int main( int argc, char** argv )
{
        double alpha = 0.5; double beta; double input;
        Mat src1, src2, src2_copy, dst;

        src1 = imread("a.jpg");
        src2 = imread("logo.png");


        resize(src2, src2_copy, src2.size() / 2, 0.5, 0.5);

        int x = 100;
        int y = 100;
        int w = src2_copy.size().width;
        int h = src2_copy.size().height;
        cv::Rect pos = cv::Rect(x, y, w, h);


        dst = src1.clone();

        namedWindow("Linear Blend", 1);
        beta = ( 1.0 - alpha );

        addWeighted(src1(pos), alpha, src2_copy, beta, 0.0, dst);

        imshow("Linear ", dst);


        waitKey(0);
        return 0;
}

Saeed
  • 159
  • 3
  • 13
  • In `addWeighted(src1(pos), alpha, src2_copy, beta, 0.0, dst)` you overwrite `dst` with the smaller, logo-size result. Change that to `addWeighted(dst(pos), alpha, src2_copy, beta, 0.0, dst(pos))`, and the final `dst` should be good. – HansHirse Sep 04 '19 at 11:31
  • @hanshire yes. it is worked correctly. thank you. :) – Saeed Sep 04 '19 at 12:15

1 Answers1

2

You can access a (rectangular) region of interest (ROI) inside a cv::Mat using a cv::Rect (see the documentation on the base class), which is described by x, y, width, and height. This is a widely used technique, which becomes handy in a lot of use cases!

So, now you just need to set up a proper ROI within your main image and blend your watermark there. Let's have a look at the following code snippet:

// Artificial main image
cv::Mat img = cv::Mat(300, 300, CV_8UC3, cv::Scalar(128, 128, 128));

// Artificial watermark
cv::Mat wtm = cv::Mat(25, 25, CV_8UC3, cv::Scalar(0, 0, 255));

// Position of watermark in main image
int x = 30;
int y = 35;
int w = wtm.size().width;
int h = wtm.size().height;
cv::Rect pos = cv::Rect(x, y, w, h);

// Blending
double alpha = 0.7;
double beta = (1.0 - alpha);
cv::addWeighted(img(pos), alpha, wtm, beta, 0.0, img(pos));

The artifical main image looks like this:

Main image

The artificial watermark image looks like this:

Watermark

And, the final result looks like this:

Result

As you can see, in

cv::addWeighted(img(pos), alpha, wtm, beta, 0.0, img(pos))

the ROI img(pos) is used as source and destination of the operation, so you have in-place blending. If you want to have a separate output image while preserving your main image untouched, maybe clone your main image in the beginning, i.e.

cv::Mat dst = img.clone()

and then do the blending with dst(pos) instead of img(pos).

Hope that helps!

HansHirse
  • 18,010
  • 10
  • 38
  • 67
  • @hanshire Just a question. finally in yخur code, we blend a part of main image with logo and both have equal size. but final output is not which i want. i want see first image as a result, which has a logo as a watermark. – Saeed Sep 04 '19 at 09:57
  • @Saeed Yes, I just figured that out - sorry. For a separate output image `dst`, you either have to create a copy beforehand, i.e. `cv::Mat dst = img.clone()` and then further work on `dst` instead of `img` OR you clone the contents of `img` after the blending to `dst`. – HansHirse Sep 04 '19 at 10:03
  • @hanshire Actually I want to have in-palce blending so i want to use source as destination. I mean, at the end, I want main image which have a small logo in a corner of it. currently, i see final image as the same size of logo. – Saeed Sep 04 '19 at 11:06
  • @Saeed Can't confirm. For me, `img` has still size `300 x 300`. Of course, `img(pos)` has size `25 x 25`, but you have to look at `img`! Apart from that, I can't think of any other pitfall. Maybe provide the code, you actually use right now. – HansHirse Sep 04 '19 at 11:12
  • @hanshire You are right. you used an artificial image and I read a real image instead. now i write my code which i run it. – Saeed Sep 04 '19 at 11:19