9

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

正如您所看到的,从一幅图像过渡到另一幅图像仍然可见。我如何获得消除此可见转换的完美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

+0

图像似乎被预乘背景源。你能否展示你目前使用的配方? – K3N

+0

@ K3N,我编辑并添加了一些代码。让我知道这是否有帮助。 – Metal

+2

你能提供3个独立的扭曲图像,以及重叠坐标吗?这将允许人们验证不同的方法。 – Miki

回答

8

这里是我会做一般的方式:

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; 
} 

基本上你计算从投资回报率的边界的距离,你的对象的中心和计算ALP哈这两个混合掩码值。因此,如果一个图像与边界距离较远,另一个图像与边界距离较小,则您更喜欢靠近图像中心的像素。对于扭曲图像的尺寸不相似的情况,将这些值标准化会更好。 但更好,更高效的是预先计算混合蒙版并翘曲它们。最好的办法就是了解光学系统的渐晕效果,并选择相同的混合蒙版(通常边框的值较低)。

从前面的代码,你会得到这些结果: ROI口罩:

enter image description here

enter image description here

混合口罩(就像一个印象,必须是浮点矩阵来代替):

enter image description here

enter image description here

图像拼接:

enter image description here

+0

嗨,你是如何获得口罩的。 'cv2.distanceTransform(img_1_mask,cv2.DIST_L1,3)'只是返回python中的原始掩码。 – Metal

+0

在显示之前您必须缩放它们,因为float值> = 1会显示为白色。试试'imshow(windowname,dt1/255)'或者某物。这样(不知道numpy/python语法,对不起) – Micka

+0

这是'cv2.imshow(windowname,img/255)',谢谢!此外,想知道是否有更快的方法来操纵所有像素,而不是迭代所有像素。有任何想法吗? – Metal

4

有2个明显的问题与您的图像:

  1. 边境地区的扭曲照明条件

    最有可能造成通过用于获取图像的光学器件。因此,为了弥补这一点,你应该只使用图像的一部分(从边界切掉几个像素。

    所以,当从边境切断20个像素,并混合到普通照明,我得到这个:

    border cut off

    正如你所看到的丑陋的边界缝距离现在只有照明的问题仍然存在(见子弹#2)。

  2. 图像采取在不同的照明条件下

    这里地下散射效果在使图像“不兼容”命中。您应该将它们归一化为一些均匀的照明,或者逐行处理混合结果,并且当检测到相干凹凸不平时,将其余的线条相乘,以便减少凹凸。

    bump

    所以该行的其余部分应通过不断i0/i1相乘。如果颠簸只发生在重叠值之间的边缘上,这些类型可以扫描它们或直接使用这些位置。要识别有效凹凸,它应该在整个图像高度的上一行和下一行中附近有邻居。

    你可以做到这一点也以同样的方式Y轴方向...

相关问题