【问题标题】:Multi band blending makes seams brighter and more visible多波段混合使接缝更亮、更明显
【发布时间】:2021-06-02 06:56:17
【问题描述】:

我正在尝试使用多波段混合将两个预变形图像无缝拼接在一起。我有两个输入图像(已经变形)和一个蒙版。然而,当我应用 MBB 时,接缝周围的区域会发光,因此,它们变得更加明显,这与这里的目标相反。我完全不知道我做错了什么。

为了更好地解释问题,这里是图像和输出:

目标:

来源:

面具:

一旦我将源图像混合到目标中,这就是我得到的:

这是我的参考代码:

import cv2 as cv2
import numpy as np
import sys

def blend(A, B, m, canvas, num_levels=6):
    trimmer = cv2.bitwise_or(canvas, m) # to trim the blurry edges around the image after blending
    m[m == 255] = 1

    GA = A.copy()
    GB = B.copy()
    GM = m.copy()

    gpA = [GA]
    gpB = [GB]
    gpM = [GM]

    for i in range(num_levels):
        GA = cv2.pyrDown(GA)
        GB = cv2.pyrDown(GB)
        GM = cv2.pyrDown(GM)

        gpA.append(np.float32(GA))
        gpB.append(np.float32(GB))
        gpM.append(np.float32(GM))

    lpA = [gpA[num_levels - 1]]
    lpB = [gpB[num_levels - 1]]
    gpMr = [gpM[num_levels - 1]]

    for i in range(num_levels - 1, 0, -1):
        size = (gpA[i - 1].shape[1], gpA[i - 1].shape[0])

        LA = np.subtract(gpA[i - 1], cv2.pyrUp(gpA[i], dstsize=size))
        LB = np.subtract(gpB[i - 1], cv2.pyrUp(gpB[i], dstsize=size))

        lpA.append(LA)
        lpB.append(LB)

        gpMr.append(gpM[i - 1])

    LS = []
    for la, lb, gm in zip(lpA, lpB, gpMr):
        ls = la * gm + lb * (1.0 - gm)
        # ls = la + lb
        LS.append(ls)

    ls_ = LS[0]
    for i in range(1, num_levels):
        size = (LS[i].shape[1], LS[i].shape[0])
        ls_ = cv2.add(cv2.pyrUp(ls_, dstsize=size), np.float32(LS[i]))
        ls_[ls_ > 255] = 255; ls_[ls_ < 0] = 0
    
    ls_ = ls_.astype(np.uint8)

    cv2.imwrite("trimmer.jpg", trimmer)
    ls_ = cv2.bitwise_and(ls_, trimmer)

    return ls_

要传递给函数的画布(基本上是目标/马赛克的掩码):

源/新图像的掩码:

我也愿意探索无缝融合这两个图像的其他方法,以防 MBB 不是实现我目标的最合适方法。请帮忙。

【问题讨论】:

  • 看看线性交叉混合。这个想法是使用你已经拥有的蒙版和距离变换来根据到图像中心的距离进行混合:stackoverflow.com/questions/22315904/…
  • @Micka 嘿,我一直在尝试将您的方法应用于 python,因为我有一段时间无法运行 C++ 代码,请问是否有对应于边界的 python(掩码) 函数?
  • 由于链接问题中的白色背景图像,仅使用边框功能。在您的情况下,您应该使用整个图像,并且边框应该是图像边框。您甚至可以预先计算混合图像因子并将混合蒙版/因子扭曲到您的马赛克图像大小。
  • 您能否在问题中添加两个蒙版(给定马赛克和新图像 - 包括重叠区域)?
  • @Micka 完成,你要的面具是吗?

标签: python opencv image-processing computer-vision image-stitching


【解决方案1】:

这是一个 C++ 答案,但算法很简单。

int main()
{
    std::string folder = "C:/Development/Projects/UNDIST_FISHEYE/OpenCV4_Experiments_VS2017/";
    cv::Mat mosaic_img = cv::imread(folder + "mosaic_img.jpg");
    cv::Mat newImage_img = cv::imread(folder + "newImage_img.jpg");

    //cv::Mat mosaic_mask = cv::imread(folder + "mosaic_mask.jpg", cv::IMREAD_GRAYSCALE);
    cv::Mat mosaic_mask = cv::imread(folder + "mosaic_mask_2.jpg", cv::IMREAD_GRAYSCALE);
    mosaic_mask = mosaic_mask > 230; // threshold because of jpeg artifacts

    cv::Mat newImage_mask_raw = cv::imread(folder + "newImage_mask.jpg", cv::IMREAD_GRAYSCALE);
    newImage_mask_raw = newImage_mask_raw > 230;
    // newImage_mask_raw is a few pixels too small...
    cv::Mat newImage_mask = cv::Mat::zeros(mosaic_mask.size(), mosaic_mask.type());

    newImage_mask_raw.copyTo(newImage_mask(cv::Rect(0,0, newImage_mask_raw.cols, newImage_mask_raw.rows)));

    cv::Mat mosaic_blending = cv::Mat::zeros(mosaic_mask.size(), CV_32FC1);
    cv::distanceTransform(mosaic_mask, mosaic_blending, cv::DIST_L2, cv::DIST_MASK_PRECISE);
    cv::Mat newImage_blending = cv::Mat::zeros(mosaic_mask.size(), CV_32FC1);
    cv::distanceTransform(newImage_mask, newImage_blending, cv::DIST_L2, cv::DIST_MASK_PRECISE);

    cv::imshow("mosaic blending", mosaic_blending/255);
    cv::imshow("newImage blending", newImage_blending/255);

    cv::Mat newMosaic = mosaic_img.clone();
    // now compose the mosaic:
    // for each pixel: mosaic=(m1*p1 + m2*p2)/(m1+m2)
    for (int y = 0; y < newMosaic.rows; ++y)
    {
        for (int x = 0; x < newMosaic.cols; ++x)
        {
            // for efficiency: only process pixels where the new image hits the mosaic canvas
            if (newImage_blending.at<float>(y, x) == 0) continue;

            float m1 = newImage_blending.at<float>(y, x);
            float m2 = mosaic_blending.at<float>(y, x);
            float ma = m1 + m2;

            m1 = m1 / ma;
            m2 = m2 / ma;

            cv::Vec3f mosaicPixel = m1 * newImage_img.at<cv::Vec3b>(y, x) + m2 * mosaic_img.at<cv::Vec3b>(y, x);
            newMosaic.at<cv::Vec3b>(y, x) = mosaicPixel; // maybe cast or round here
        }

    
    }

    cv::imwrite("mask1.png", mosaic_mask);
    cv::imwrite("mask2.png", newImage_mask);
    cv::imwrite("mosaic.jpg", newMosaic);

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


    cv::waitKey(0);
}

一般的想法是测量从蒙版边界到内部的距离,并假设边界处的像素质量较低(更有可能导致接缝),因此这些像素的混合应该更强。

如果您在将蒙版变形到马赛克画布之前测量(甚至预先计算)该距离,这可能会更好。

使用这些面具时

我得到这个结果:

如您所见,仍然有一个接缝,但那是来自中间马赛克(输入图像之一),如果之前的拼接是用相同的混合执行的,它就不会出现。

然后使用这个掩码进行中间马赛克(告诉已经给定的接缝像素质量低)

我得到这个结果:

最好是使用前一个混合蒙版和新的图像混合蒙版的每像素最大值来组成马赛克混合蒙版。

【讨论】:

    猜你喜欢
    • 2019-02-18
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    相关资源
    最近更新 更多