Python 如何获得正确的alpha值以完美混合两幅图像?

Python 如何获得正确的alpha值以完美混合两幅图像?,python,opencv,image-processing,computer-vision,alphablending,Python,Opencv,Image Processing,Computer Vision,Alphablending,我一直在尝试混合两种图像。目前我采用的方法是,我获得两幅图像重叠区域的坐标,仅对于重叠区域,在添加之前,我使用硬编码的alpha值0.5进行混合。所以基本上我只是从两幅图像的重叠区域中取每个像素值的一半,然后将它们相加。这并没有给我一个完美的混合,因为alpha值被硬编码为0.5。以下是3幅图像混合的结果: 如您所见,从一个图像到另一个图像的过渡仍然可见。如何获得消除这种可见过渡的完美alpha值?或者根本就没有这样的事情,而我采取了错误的方法 以下是我目前进行混合的方式: for i in r

我一直在尝试混合两种图像。目前我采用的方法是,我获得两幅图像重叠区域的坐标,仅对于重叠区域,在添加之前,我使用硬编码的alpha值0.5进行混合。所以基本上我只是从两幅图像的重叠区域中取每个像素值的一半,然后将它们相加。这并没有给我一个完美的混合,因为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)

如果有人想给它一个镜头,这里有两个扭曲的图像,以及它们重叠区域的遮罩:

我通常会这样做:

int main(int argc, char* argv[])
{
    cv::Mat input1 = cv::imread("C:/StackOverflow/Input/pano1.jpg");
    cv::Mat input2 = cv::imread("C:/StackOverflow/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;
}
intmain(intargc,char*argv[])
{
cv::Mat input1=cv::imread(“C:/StackOverflow/Input/pano1.jpg”);
cv::Mat input2=cv::imread(“C:/StackOverflow/Input/pano2.jpg”);
//计算渐晕遮罩。这在扭曲之前容易得多,但我会尝试。。。
//如果您的ROI在图像中的大小和位置没有变化,则可以对其进行预计算,如果您可以确定每个图像的ROI,则可以对其进行预计算和对齐
//压缩伪影使情况变得更糟,我尝试提取图像中的所有非黑色区域。
cv::Mat mask1;
cv::inRange(输入1,cv::Vec3b(10,10,10),cv::Vec3b(255,255,255),mask1);
cv::Mat mask2;
cv::inRange(输入2,cv::Vec3b(10,10,10),cv::Vec3b(255,255,255),mask2);
//现在计算到ROI边界的距离:
cv::Mat dt1;
距离变换(mask1,dt1,cv_DIST_L1,3);
cv::Mat dt2;
距离变换(mask2,dt2,cv_DIST_L1,3);
//现在您可以直接使用距离值进行混合。如果距离值较小,则表示该值更差(您的渐晕在图像边界处变得更差)
cv::Mat mosaic=cv::Mat(input1.size(),input1.type(),cv::Scalar(0,0,0));
对于(int j=0;j
基本上,计算从ROI边界到对象中心的距离,并根据两个混合遮罩值计算alpha。因此,如果一个图像与边框的距离较高,而另一个图像与边框的距离较低,则您更喜欢靠近图像中心的像素。对于扭曲图像大小不相似的情况,最好规范化这些值。 但更好、更有效的方法是预计算混合遮罩并扭曲它们。最好是了解您的光学系统的渐晕,并选择相同的混合遮罩(通常边界值较低)

从前面的代码中,您将得到以下结果: ROI掩码:

混合遮罩(作为一种印象,必须是浮点矩阵):

图像拼接:


您的图像有两个明显的问题:

  • 边界区域的照明条件扭曲

    这很可能是由用于获取图像的光学元件引起的。所以,为了弥补这一缺陷,您应该只在图像的内部使用(从边框上切掉几个像素)

    因此,当从边界上切下20个像素并混合到公共照明时,我得到了以下结果:

    正如您所看到的,丑陋的边界接缝现在消失了,只有照明问题仍然存在(请参见bullet#2

  • 图像是在不同的照明条件下拍摄的

    在这里,次表面散射效应会使图像“不兼容”。您应该将它们规格化为一些均匀的照明,或者逐行对混合结果进行后处理,当检测到相干凹凸时,将该线条的其余部分乘以,以便减少凹凸

    因此,线的其余部分应乘以常量
    i0/i1
    。如果这些凹凸只能发生在重叠值之间的边上,那么您可以扫描它们或直接使用这些位置…为了识别有效凹凸,在整个图像高度上,上一行和下一行的附近应该有邻居

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


  • 源图像似乎与背景相乘。你能展示一下你目前使用的公式吗?@K3N,我已经编辑并添加了一些代码。如果有帮助,请告诉我。你能提供3个单独的扭曲图像以及重叠坐标吗?这将允许人们验证不同的方法。@Miki当然,这里有2个扭曲图像es及其重叠区域的掩码:也许你从我的回答中得到了一些启发:嘿,你是如何获得掩码的。
    cv2.distanceTransform(img_1_mask,cv2.DIST_L1,3)
    只返回python中的原始掩码。在显示它们之前,你必须缩放它们,因为浮点值>=1显示为白色。请尝试
    imshow(windowname,dt1/255)
    或类似的东西(不知道numpy/python语法,抱歉)它是
    cv2.imshow(windowname,img/255)
    ,谢谢!另外,我想知道是否有一种更快的方法来处理所有像素,而不是迭代所有像素。有什么想法吗?是的,你可以使用子矩阵来只迭代重叠的图像部分。使用你在问题中贴出的遮罩,计算边界框,并使用该ROI