在 Numpy 中通过模糊蒙版合成图像

Compositing images by blurred mask in Numpy

我有两个图像和一个遮罩,所有尺寸都与 Numpy 数组相同:



期望的输出

我想以这样的方式合并它们,使输出如下所示:

当前代码

def merge(lena, rocket, mask):
    '''Mask init and cropping'''
    mask = np.zeros(lena.shape[:2], dtype='uint8')
    cv2.fillConvexPoly(mask, circle, 255) # might be polygon
    '''Bitwise operations'''
    lena = cv2.bitwise_or(lena, lena, mask=mask)
    mask_inv = cv2.bitwise_not(mask) # mask inverting
    rocket = cv2.bitwise_or(rocket, rocket, mask=mask_inv)
    output = cv2.bitwise_or(rocket, lena)

    return output

当前结果

这段代码给出了这个结果:

应用 cv2.GaussianBlur(mask, (51,51), 0) 以不同方式扭曲叠加图像的颜色。
其他 SO 问题与类似问题有关,但不能完全解决这种类型的模糊合成。

更新:这给出了与当前结果相同的结果

mask = np.zeros(lena.shape[:2], dtype='uint8')
mask = cv2.GaussianBlur(mask, (51,51), 0)
mask = mask[..., np.newaxis]
cv2.fillConvexPoly(mask, circle, 1)
output = mask * lena + (1 - mask) * rocket

临时解决方案

可能由于转换太多,这不是最优的,请指教

mask = np.zeros(generated.shape[:2])
polygon = np.array(polygon, np.int32) # 2d array of x,y coords
cv2.fillConvexPoly(mask, polygon, 1)
mask = cv2.GaussianBlur(mask, (51, 51), 0)
mask = mask.astype('float32')
mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
foreground = cv2.multiply(lena, mask, dtype=cv2.CV_8U)
background = cv2.multiply(rocket, (1 - mask), dtype=cv2.CV_8U)
output = cv2.add(foreground, background)

请告知如何模糊蒙版,将其与前景正确合并,然后叠加在背景图像上?

这是 Python/OpenCV 中的操作方法。你的第二种方法很接近。

  • 读取 3 个输入图像
  • 对圆应用线性(或高斯)模糊
  • 将圆拉伸到全动态范围(0 到 255)作为遮罩
  • 将掩码转换为在 0 到 1 范围内浮动的 3 个通道
  • 通过乘法对 image1 应用蒙版,对 image2 应用反转蒙版,并将乘积相加
  • 将结果转换为 8 位范围(0 到 255)裁剪以确保没有溢出或回绕
  • 保存结果


输入图像:

import cv2
import numpy as np

# Read images
image1 = cv2.imread('lena_wide.jpg')
image2 = cv2.imread('rocket.jpg')
circle = cv2.imread('white_circle.jpg', cv2.IMREAD_GRAYSCALE)

# linear blur mask
mask = cv2.blur(circle, (30,30))
# alternate using Gaussian blur
#mask = cv2.GaussianBlur(circle, (0,0), sigmaX=10, sigmaY=10)

# stretch mask to full dynamic range
mask = cv2.normalize(mask, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

# convert mask to float in range 0 to 1
maskf = (mask/255).astype(np.float64)
maskf = cv2.merge([maskf,maskf,maskf])

# apply mask to image1 and inverted  mask to image2
result = maskf*image1 + (1-maskf)*image2
result = result.clip(0,255).astype(np.uint8)


# save results
cv2.imwrite('white_circle_ramped.jpg', mask)
cv2.imwrite('lena_wide_rocked_composited.png', result)

# show results
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


倾斜遮罩图像:

结果:


添加:

这是主要使用 Numpy 的替代方法。

import cv2
import numpy as np

# Read images
image1 = cv2.imread('lena_wide.jpg')
image2 = cv2.imread('rocket.jpg')
circle = cv2.imread('white_circle2.jpg', cv2.IMREAD_GRAYSCALE)

# linear blur mask
mask = cv2.blur(circle, (30,30))
# alternate using Gaussian blur
#mask = cv2.GaussianBlur(circle, (0,0), sigmaX=10, sigmaY=10)

# stretch mask to full dynamic range
mask = cv2.normalize(mask, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

# convert mask to 3 channels
mask = cv2.merge([mask,mask,mask])

# apply mask to image1 and inverted  mask to image2
image1_masked = np.multiply(image1, mask/255).clip(0,255).astype(np.uint8)
image2_masked = np.multiply(image2, 1-mask/255).clip(0,255).astype(np.uint8)

# add the two masked images together
result = np.add(image1_masked, image2_masked)

# save results
cv2.imwrite('white_circle_ramped2.jpg', mask)
cv2.imwrite('lena_wide_rocked_composited2.png', result)

# show results
cv2.imshow("mask", mask)
cv2.imshow("image1_masked", image1_masked)
cv2.imshow("image2_masked", image2_masked)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


您需要在混合之前重新归一化蒙版:

def blend_merge(lena, rocket, mask):
    mask = cv2.GaussianBlur(mask, (51, 51), 0)
    mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
    mask = mask.astype('float32') / 255
    foreground = cv2.multiply(lena, mask, dtype=cv2.CV_8U)
    background = cv2.multiply(rocket, (1 - mask), dtype=cv2.CV_8U)
    output = cv2.add(foreground, background)
    return output

完整的工作示例是 here