Merge two Mat-Objects in OpenCV

asked 2015-02-28 08:41:38 -0600

Fly gravatar image

updated 2015-02-28 08:42:14 -0600

I wrote a little function in order to be able to "stick" the pixels of an image on top of another, but it somehow doesnt work: While the "shapes" of my "sticked" image is right, the colors are not.

enter image description here

The example flower is the first image, and as a second image I had a black trapezoid png. As you can see, there are multiple problems: 1. The colors are shown weirdly. Actually there are no colors, just greyscale, and some weird stripes as overlay. 2. Alpha values are not respected. The white part of the overlay image is transparent in the png.

Here is my code:

void mergeMats(Mat mat1, Mat mat2, int x, int y){
    //unsigned char * pixelPtr = (unsigned char *)mat2.data;
    //unsigned char * pixelPtr2 = (unsigned char *)mat1.data;
    //int cn = mat2.channels();
    //int cn2 = mat2.channels();
    //Scalar_<unsigned char> bgrPixel;

    for (int i = 0; i < mat2.cols; i++){
        for (int j = 0; j < mat2.rows; j++){
            if (x + i < mat1.cols && y + j < mat1.rows){

                Vec3b &intensity = mat1.at<Vec3b>(j+y, i+x);
                Vec3b intensity2 = mat2.at<Vec3b>(j, i);
                for (int k = 0; k < mat1.channels(); k++) {
                    intensity.val[k] = saturate_cast<uchar>(intensity2.val[k]);
                }
                //pixelPtr2[(i + x)*mat1.cols*cn2 + (j + y)*cn2 + 0] = pixelPtr[(i + x)*mat2.cols*cn + (j + y)*cn + 0];
                //pixelPtr2[(i + x)*mat1.cols*cn2 + (j + y)*cn2 + 1] = pixelPtr[(i + x)*mat2.cols*cn + (j + y)*cn + 1];
                //pixelPtr2[(i + x)*mat1.cols*cn2 + (j + y)*cn2 + 2] = pixelPtr[(i + x)*mat2.cols*cn + (j + y)*cn + 2];
            }
        }
    }
}

The commented code was another approach, but had the same results. So, here are my questions:

  1. How do I solve the 2 problems (1. the colors..., 2. alpha ...)

  2. How is the pixel-array of any Mat-Object actually, well, organized? I guess it would be easier for me to manipulate those arrays if I knew whats in them.

(I already asked this question on stackoverflow, but I guess it's better to ask it here.)

edit retag flag offensive close merge delete

Comments

1

if any of your images has alpha (CV_8UC4), you have to access it as Vec4b, not Vec3b. (this explains the diagonal stripes, you're 'one-off' again...)

but again, stop looping over pixels, that's horrible.

it could be a plain:

CV_Assert(mat1.type() == mat2.type())
mat2.copyTo( mat1( Rect(x,y,mat2.cols,mat2.rows) ) );
berak gravatar imageberak ( 2015-02-28 08:46:09 -0600 )edit

@berak Thanks for the answer, I'll try it out. What exactly is Mat.type()? And if it is different, can I somehow convert it to be, well, equal (That's why I'd have liked pixel-looping, to be able to control everything)? And what if I want, for Example, to draw on a frame? Then I'd need the pixel-changing, don't I (And if yes, how is the pixel-array organized? Would be cool to know.)? (Ok, I checked the types, thing is that the types of my two images ARE different, mainly probably because one image is a frame of a video while the other is a real image)

Fly gravatar imageFly ( 2015-02-28 08:57:20 -0600 )edit
1

"And if it is different ..."

if ( mat1.type() != CV_8UC4)
   cvtColor( mat1,mat1, COLOR_BGR2BGRA);
if ( mat2.type() != CV_8UC4)
   cvtColor( mat2,mat2, COLOR_BGR2BGRA);
berak gravatar imageberak ( 2015-02-28 09:21:01 -0600 )edit

@berak Thanks, I guess that will solve the problem. Still, it would be awesome to know what the pixel-array contains, just in case I'd have to perform some edits on it.

Fly gravatar imageFly ( 2015-02-28 11:19:55 -0600 )edit
1

Vec3b in the bgr case, Vec4b in the bgra one. if you have to access pixels, you will have to check the type() before, and choose the correct one (either with template functions, or with switch/case blocks)

berak gravatar imageberak ( 2015-02-28 11:52:46 -0600 )edit