-2

I am attempting to copy an image to another image (place a logo in the bottom right side of an image). My code successfully copies the logo onto the room image but it does some weird stretching when I apply a mask.

// Overlay logo
// src = 3 channel image of a room
// logo = 3 channel image of a logo (most of the Mat is black except for the logo). 
//        logo is smaller than the room image
Mat res;
Mat thresh;
src.copyTo(res);
threshold(logo, thresh, 1, 255, CV_THRESH_BINARY);
Rect r(res.cols-logo.cols, res.rows-logo.rows, logo.cols, logo.rows);
logo.copyTo(res(r), thresh);

My result: enter image description here

Mask is: enter image description here

sazr
  • 24,984
  • 66
  • 194
  • 362
  • 1
    I've posted an answer for the same question in Python [HERE](https://stackoverflow.com/questions/51365126/combine-2-images-with-mask) did you have a look? – Jeru Luke Jul 18 '18 at 10:31
  • @JeruLuke I did, that answer is for Python using numpy so not directly convertible to c++. In c++, the I thought the `Mat::copyTo()` function would make things easier. – sazr Jul 18 '18 at 10:38
  • Is your logo a color image or a grayscale image ? – Sunreef Jul 18 '18 at 10:54
  • I am not getting what mask are you talking about, can you please attach sample input and expected output ? – ZdaR Jul 18 '18 at 11:01
  • if you use logo.copyTo(res, thresh); is res identical to the logo image? Are you sure that logo isn't BGRA? it looks like it is stretched which indicates a channel or row size problem – Micka Jul 18 '18 at 11:01

2 Answers2

2

Your logo seems to be a color image. Which means that your thresh image is also a color image. When you use it as a mask, it's going to be horizontally stretched because the extra channels are interpreted as more columns.

Try adding cvtColor(logo, grayLogo, CV_BGR2GRAY) before the threshold and use the grayLogo in the threshold.

Sunreef
  • 4,452
  • 21
  • 33
  • Good one, I didn't noticed that. – Kamil Szelag Jul 18 '18 at 11:07
  • @Sunreef thanks that was the problem. I always thought threshold only ever spat out single channel binary images not 3 channel binary (or grayscale?) images? – sazr Jul 18 '18 at 11:13
  • @JakeM If you give it a three channel image, it's going to apply the threshold operation on each channel independently. – Sunreef Jul 18 '18 at 11:15
1

Mask size and image size are not equal (thats why mask is streched). To solve this, you should create mask image and copy your threshed logo in good position. [EDIT]: According to sunreef's answer - three channels in mask could also be a source of your problem.

Code posted below worked for me.

cv::Mat t_roomImage = cv::imread("E:\\Workspace\\KS\\misc\\M4nKr.jpg");
cv::Mat t_logoImage = cv::imread("E:\\Workspace\\KS\\misc\\7sFbv.jpg",0);

cv::threshold(t_logoImage, t_logoImage, 10, 255, CV_THRESH_BINARY);
cv::Mat t_mask = cv::Mat::zeros(t_roomImage.size(), CV_8U);
cv::Rect t_rect = cv::Rect(t_mask.cols - t_logoImage.cols, t_mask.rows - 
t_logoImage.rows, t_logoImage.cols, t_logoImage.rows);
t_logoImage.copyTo(t_mask(t_rect));
t_roomImage.setTo(cv::Scalar(255, 0, 0), t_mask);

I used setTo, because I had no logo image. There you can use copyTo instead.

Results:

Mask Result

Kamil Szelag
  • 708
  • 3
  • 12