如何获得正确的alpha值来完美融合两幅图像?

How to obtain the right alpha value to perfectly blend two images?

我一直在尝试混合两个图像。我目前采用的方法是,我获得了两个图像重叠区域的坐标,并且仅针对重叠区域,在添加它之前,我将其与 0.5 的硬编码 alpha 混合。所以基本上我只是从两个图像的重叠区域中取出每个像素值的一半,然后添加它们。这并没有给我一个完美的混合,因为 alpha 值被硬编码为 0.5。这是 3 张图像的混合结果:

如您所见,从一张图片到另一张图片的过渡仍然可见。我如何获得可以消除这种可见过渡的完美 alpha 值?还是根本就没有这样的东西,我走错了路?

这是我目前进行混合的方式:

for i in range(3):
            base_img_warp[overlap_coords[0], overlap_coords[1], i] = base_img_warp[overlap_coords[0], overlap_coords[1],i]*0.5
            next_img_warp[overlap_coords[0], overlap_coords[1], i] = next_img_warp[overlap_coords[0], overlap_coords[1],i]*0.5
final_img = cv2.add(base_img_warp, next_img_warp)

如果有人想试一试,这里有两个扭曲的图像,以及它们重叠区域的蒙版:http://imgur.com/a/9pOsQ

以下是我通常会采用的方式:

int main(int argc, char* argv[])
{
    cv::Mat input1 = cv::imread("C:/Whosebug/Input/pano1.jpg");
    cv::Mat input2 = cv::imread("C:/Whosebug/Input/pano2.jpg");

    // compute the vignetting masks. This is much easier before warping, but I will try...
    // it can be precomputed, if the size and position of your ROI in the image doesnt change and can be precomputed and aligned, if you can determine the ROI for every image
    // the compression artifacts make it a little bit worse here, I try to extract all the non-black regions in the images.
    cv::Mat mask1;
    cv::inRange(input1, cv::Vec3b(10, 10, 10), cv::Vec3b(255, 255, 255), mask1);
    cv::Mat mask2;
    cv::inRange(input2, cv::Vec3b(10, 10, 10), cv::Vec3b(255, 255, 255), mask2);


    // now compute the distance from the ROI border:
    cv::Mat dt1;
    cv::distanceTransform(mask1, dt1, CV_DIST_L1, 3);
    cv::Mat dt2;
    cv::distanceTransform(mask2, dt2, CV_DIST_L1, 3);

    // now you can use the distance values for blending directly. If the distance value is smaller this means that the value is worse (your vignetting becomes worse at the image border)
    cv::Mat mosaic = cv::Mat(input1.size(), input1.type(), cv::Scalar(0, 0, 0));
    for (int j = 0; j < mosaic.rows; ++j)
    for (int i = 0; i < mosaic.cols; ++i)
    {
        float a = dt1.at<float>(j, i);
        float b = dt2.at<float>(j, i);

        float alpha = a / (a + b); // distances are not between 0 and 1 but this value is. The "better" a is, compared to b, the higher is alpha.
        // actual blending: alpha*A + beta*B
        mosaic.at<cv::Vec3b>(j, i) = alpha*input1.at<cv::Vec3b>(j, i) + (1 - alpha)* input2.at<cv::Vec3b>(j, i);
    }

    cv::imshow("mosaic", mosaic);

    cv::waitKey(0);
    return 0;
}

基本上,您计算从 ROI 边界到对象中心的距离,并根据两个混合蒙版值计算 alpha。因此,如果一幅图像与边界的距离较远,而另一幅图像与边界的距离较近,则您更喜欢靠近图像中心的像素。对于变形图像大小不相似的情况,最好将这些值归一化。 但更好、更有效的方法是预先计算混合蒙版并对其进行变形。最好了解光学系统的暗角并选择相同的混合蒙版(通常边界值较低)。

从前面的代码中你会得到这些结果: ROI 掩码:

混合蒙版(作为印象,必须是浮点矩阵):

图像马赛克:

您的图片有 2 个明显的问题:

  1. 边界区域的光照条件扭曲

    这很可能是由用于获取图像的光学器件引起的。因此,为了补救你应该只使用图像的内部部分(从边框切掉几个像素。

    所以当从边界切掉 20 个像素并混合到普通照明时,我得到了这个:

    如您所见,丑陋的边框缝现在消失了,只有照明问题仍然存在(参见项目符号 #2)。

  2. 图片是在不同光照条件下拍摄的

    这里次表面散射效果影响了图像的制作 "not-compatible"。您应该将它们归一化为某种均匀的照明,或者 post 逐行处理混合结果,当检测到相干凹凸时,乘以其余的线条,这样凹凸就会减少。

    因此该行的其余部分应乘以常数 i0/i1。这些如果碰撞只能发生在重叠值之间的边缘,因此您可以扫描它们或直接使用这些位置......要识别有效的碰撞,它应该在整个图像高度的前一行和下一行附近有邻居。

    您也可以在 y 轴方向上以相同的方式执行此操作...