Search code examples
c++opencvc++11blending

cv::detail::MultiBandBlender strange white streaks at the end of the photo


I'm working with OpenCV 3.4.8 with C++11 and I'm trying to blend images together. In this example I have 2 images (thiers mask shown in the screen belowe). I have georeference, so I can easy calculate corners of this images in the final image. The data outside the masks are black.

Masks of the images before blending

My code looks like something like that:

std::vector<cv::UMat> inputImages;
std::vector<cv::UMat> masks;
std::vector<cv::Point> corners;
std::vector<cv::Size> imgSizes;

/*
here is code where I load images, create thier masks 
(like in the screen above) and calculate corners.
*/

cv::Ptr<cv::detail::SeamFinder> seamFinder = new cv::detail::DpSeamFinder();
seamFinder->find(inputImages, corners, masks);

cv::Ptr<cv::detail::Blender> blender = new cv::detail:: MultiBandBlender(false);
blender->prepare(corners, imgSizes);
for(size_t i = 0; i < inputImages.size(); i++)
{
    blender->feed(inputImages[i], masks[i], corners[i]);
}

cv::UMat blendedImg, outMask;
blender->blend(blendedImg, outMask);

Seam line of the images

SeamFinder gives me result like in the screen above. Finded seam lines looks good and Im very satisied form them. But the other problem occurs in the next step. The MultiBandBlender is making strange white streaks when the seam line goes on the end of the data. This is an example:

Images after blending

When I don't use blender, but just use masks to cut the oryginal images and just add (cv::add()) images together with additional alpha channel (made from masks) I get very good results without any holes and strange colors, but I need to have more smoothed transition :/

Can anyone help me? When I create MultiBand Blender with smaller num_bands the white streaks are smaller, and with the num_bands = 0 the results looks like with just adding images. I looked at feed() and blend() methods in the MultiBandBlender and I think that it is connected with Gaussian or Laplacian pyramid and the final restoring images from Laplacian pyramid in the blend() method.

EDIT1: When Gaussian and Laplacian pyramids are created the copyMakeBorder(), which prevents the MultiBandBlender from making this white streaks when images are fully filled with the data. So in my case I think that I need to create my blender almost the same like MultiBandBlender, but copyMakeBorder() method in the feed() method change to the something that will "extend" my image inside the mask, like @AlexanderKondratskiy suggested. Now I don't know how to achive correct "extend" similar to BORDER_REFLECT or BORDER_REFLECT_101.


Solution

  • I suspect your input images contain white pixels outside those masks. The white banding occurs around the areas where the seam follows the mask exactly. For Laplacian for example, pixels outside the mask do influence the final result, as each layer of a pyramid is essentially some blurring kernel on the image.

    If you have some kind of good data outside the mask, keep it. If you do not, I suggest "extending" your image beyond the mask to maintain a smooth transition.

    Edit:

    Here's two things you could try, unless someone with more experience with OpenCV comes along.

    1. To prove/disprove my hypothesis, fill the black region with just the average or median color within the mask. This should make the transition to the outside region less sharp, and hopefully reduce the artefacts. If that does not happen, my answer is wrong.

    2. In terms of what is probably a good generalization of "BORDER_REFLECT" when the edge is arbitrary, you could try something like this:

      • Find the centroid c of the mask polygon
      • For each pixel p outside the mask, think of the line between it and c
      • Calculate point p' along this line that is the same distance inside the mask area, as p is from the mask edge. (i.e. you're reflecting along the mask edge)
      • Linearly interpolate the color of from the neighbors of p' (as it's position may not fall exactly in the middle of a pixel). That's the color of pixel p