'how does copyTo in opencv c++ works?

I have gone through the below snippet and was wondering how copyTo() in opencv function work.

 // Make a copy
 Mat faceWithGlassesNaive1 = faceImage.clone();
 // Take the eye region from the image
 Mat roiFace =  faceWithGlassesNaive1(Range(150,250),Range(140,440));
 // Replace the eye region with the sunglass image
 glassBGR.copyTo(roiFace);

Does copyTo() work on copyByreference, so that any modifications done to roiface gets reflected in faceWithGlassesNaive1? Or Am i missing something ?. Need help .

  1. Below is the faceimage

faceimage

  1. Below is the glassBGR Image enter image description here

  2. Below is the output of glassBGR.copyTo(roiFace) from the above snippet enter image description here



Solution 1:[1]

From the docs:

Copies the matrix to another one.

The method copies the matrix data to another matrix. Before copying the data, the method invokes :

m.create(this->size(), this->type());

so that the destination matrix is reallocated if needed. While m.copyTo(m); works flawlessly, the function does not handle the case of a partial overlap between the source and the destination matrices.

So your data will be copied and changes won't reflect back to the original image. If you want to get rid of the white pixels in the copy you can provide a mask (the syntax might be different, doing this from memory):

Mat glassGray;
cvtColor(glassBGR, glassGray, COLOR_BGR2GRAY);
glassBGR.copyTo(roiFace, glassGray != 255);

Your actual problem is that roiFace is just an alias to the memory of faceWithGlassesNaive1. So changes applied to roiFace (for example, copying new data into it) will reflect back to faceWithGlassesNaive1. copyTo is not your problem in this case, but the creation of roiFace.

From Mat::operator()():

[...] Similarly to all of the above, the operators are O(1) operations, that is, no matrix data is copied.

Solution 2:[2]

copyTo function of opencv as the documentation says:

The method copies the matrix data to another matrix.

So you can not expect to achieve your task like that but you can simply achieve it as an approach like this:

The code:

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

using namespace std;
using namespace cv;

int main()
{

    Mat faceImage = imread("/ur/face/image/directory/elon.jpg");
    Mat glassBGR = imread("/ur/glass/image/directory/glass.png");

    resize(glassBGR,glassBGR,Size(300,100));
    // check each pixel of glass and if its white(255,255,255) then change it with face image pixels
    for(int i=0;i<glassBGR.cols;i++)
    {
        for(int j=0;j<glassBGR.rows;j++)
        {
            if(!(glassBGR.at<Vec3b>(j, i) == Vec3b(255,255,255)))
            {
                faceImage.at<Vec3b>(j+150,i+140) = glassBGR.at<Vec3b>(j, i);
            }
        }
    }
    
    imshow("result",faceImage);
    waitKey(0);        
}

Result:

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2