Copy an Cv::Mat Inside a Roi of Another One

Copy an cv::Mat inside a ROI of another one

OpenCV 2.4:

src.copyTo(dst(Rect(left, top, src.cols, src.rows)));

OpenCV 2.x:

Mat dst_roi = dst(Rect(left, top, src.cols, src.rows));
src.copyTo(dst_roi);

Need to copy one image to another image ROI

This is to confirm that @ypnos educated guess was right (nice call, btw).


Take a look at this code, that performs the same operations as yours:

#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main()
{
Mat4b m4b(50, 50, Vec4b(0, 255, 0, 255)); // blue image, 4 channels
Mat3b m3b(100, 100, Vec3b(255, 0, 0)); // green image, 3 channels

cout << "After init:" << endl;
cout << "m4b channels: " << m4b.channels() << endl;
cout << "m3b channels: " << m3b.channels() << endl << endl;

Rect roi(0, 0, 50, 50); // roi

// Create a new header for the data inside the roi in m3b
// No data copied, just a new header.
// So destRoi has same number of channels of m3b
Mat destRoi = m3b(roi);

cout << "After roi:" << endl;
cout << "m4b channels : " << m4b.channels() << endl;
cout << "m3b channels : " << m3b.channels() << endl;
cout << "destRoi channels: " << destRoi.channels() << endl << endl;

// destination type != source type
// destRoi is newly created with the destination type
// destRoi doesn't point anymore to the data in m3b and has 4 channels now
m4b.copyTo(destRoi);

cout << "After copyTo:" << endl;
cout << "m4b channels : " << m4b.channels() << endl;
cout << "m3b channels : " << m3b.channels() << endl;
cout << "destRoi channels: " << destRoi.channels() << endl << endl;

return 0;
}

Output:

After init:
m4b channels: 4
m3b channels: 3

After roi:
m4b channels : 4
m3b channels : 3
destRoi channels: 3

After copyTo:
m4b channels : 4
m3b channels : 3
destRoi channels: 4

Solution

Use both matrices with same number of channels, either by:

  1. Load both images as 3 channels matrices CV_8UC3. In fact the images you posted are both 3 channels

  2. use cvtColor to convert to the same number of channels, before performing roi and copy operations.

How to copy a rectangular area of a Mat a new Mat of the same size?

create a new image and copy the subimage to roi

cv:: Mat img = cv::imread(...);
cv::Rect roi(x,y,w,h);

cv::Mat subimage= img(roi); // embedded
cv::Mat subimageCopied = subimage.clone(); // copied

cv::Mat newImage=cv::Mat::zeros(img.size(), img.type);

img(roi).copyTo(newImage(roi)); // this line is what you want.

If you have access to the original image, but are not allowed to use its siute information, you can use .copyTo with a mask, but then you have to use the size information to create the mask...

Add a cv::Mat inside a cv::Mat at a specific position

Thanks you @Christoph Rackwitz, with your link I have found the solution.
I convert the python code of Try2Code ( enter link description here )

The final code is here :

void RenderImage::overlayImage(cv::Mat& back, const cv::Mat& front, std::size_t posX, std::size_t posY) {
cv::Mat gray, mask, mask_inv, back_bg, front_bg, result;

cv::Size fsize { front.size() };

cv::cvtColor(front, gray, cv::COLOR_BGR2GRAY);

cv::threshold(gray, mask, 0, 255, cv::THRESH_BINARY);
cv::bitwise_not(mask, mask_inv);

cv::Mat roi { back(cv::Range(posX, posX + fsize.width), cv::Range(posY, fsize.height)) };

cv::bitwise_and(roi, roi, back_bg, mask_inv);
cv::bitwise_and(front, front, front_bg, mask);

cv::add(back_bg, front_bg, result);

cv::addWeighted(roi, 0.1, result, 0.9, 0.0, result);

result.copyTo(back(cv::Rect(posX, posY, fsize.width, fsize.height)));
}

cv::Mat RenderImage::getImage() {
cv::Mat chess = backgroundChess.clone();

overlayImage(chess, piecesChess[0], 128, 0); //The method to merge two images
cv::imshow("Display Image", chess);

cv::waitKey(0);

return chess;
}


Related Topics



Leave a reply



Submit