【python】OpenCV—Paste Mask

本文介绍了如何使用OpenCV库中的函数,如`cv2.bitwise_not`、`cv2.bitwise_and`和`cv2.add`,对两张图片进行操作,提取A图的mask区域,并将其粘贴到B图上。步骤包括创建mask、反转mask、应用掩模进行选择性融合以及获取mask的边界框。
摘要由CSDN通过智能技术生成

在这里插入图片描述

学习来自【OpenCv】利用roi 掩模 将一张图片添加到另一张上

任务描述:提取图片A的 mask 区域,并粘贴到图片B上

1、代码实现

A 图

请添加图片描述

A 图的 mask 标签

请添加图片描述
B 图

请添加图片描述
结果
在这里插入图片描述

下面看看代码流程

import cv2
import numpy as np
from os.path import join
from os import listdir

rootpath = "/home/bryant/datasets/"

img1 = cv2.imread(join(rootpath, "images", "00000.jpg"))   # A 图
img2 = cv2.imread(join(rootpath, "matting", "00000.jpg"))  # A 图 mask
img3 = cv2.imread("animal_world_70223.jpg")  # B 图

h, w, c = img1.shape
img1 = cv2.resize(img1, (w//2, h//2))
img2 = cv2.resize(img2, (w//2, h//2))
img3 = cv2.resize(img3, (w//2, h//2))

img2not = cv2.bitwise_not(img2)

img2_gray = cv2.cvtColor(img2not, cv2.COLOR_BGR2GRAY)
ret, mat = cv2.threshold(img2_gray, 170, 255, cv2.THRESH_BINARY)
cv2.imshow("1", mat)  # 图 1 mask 黑白颠倒

fg1 = cv2.bitwise_and(img3, img3, mask=mat)
cv2.imshow("2", fg1)  # 图 2,仅输出 mask 非零区域的与

mat2 = cv2.bitwise_not(mat)
cv2.imshow('3', mat2) # 图 3,mask 黑白颠倒回来
fg2 = cv2.bitwise_and(img1, img1, mask=mat2)
cv2.imshow('4', fg2)  # 图 4,仅输出 mask 非零区域的与


dst = cv2.add(fg1, fg2)  # 图 2 图 4 结合
cv2.imshow('dst', dst)


cv2.waitKey(0)
cv2.destroyAllWindows()

2、结果展示

图 1

在这里插入图片描述
图 2
在这里插入图片描述
图 3
在这里插入图片描述
图 4
在这里插入图片描述
结果
在这里插入图片描述

3、另辟蹊径

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Original image, which is the background 
background = cv2.imread('background.jpg')
background = cv2.cvtColor(background, cv2.COLOR_BGR2RGB)

# Image of the object
img = cv2.imread('apple.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# Image the object's mask
mask = cv2.imread('apple_mask.jpg')
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2RGB)

print("Background shape:", background.shape)
print("Image shape:", img.shape)
print("Mask shape:", img.shape)
"""
Background shape: (2160, 3840, 3)
Image shape: (1080, 1920, 3)
Mask shape: (1080, 1920, 3)
"""

plt.figure(figsize=(16, 16))
plt.title("Background", fontsize=18)
plt.axis("off")
plt.imshow(background)

fig, ax = plt.subplots(1, 2, figsize=(16, 7))
ax[0].imshow(img)
ax[0].set_title('Apple', fontsize=18)
ax[0].axis("off")

ax[1].imshow(mask)
ax[1].set_title('Apple Mask', fontsize=18)
ax[1].axis("off")
plt.show()


def remove_obj_background(img_path, mask_path):
    '''
    Function returns:
    - image of the object with removed background in CV2 RGB format (numpy array with dimensions (width, height, 3))
    - boolean mask of the object (numpy array with dimensions (width, height))
    '''
    img = cv2.imread(img_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    mask = cv2.imread(mask_path)
    #mask = cv2.bitwise_not(mask)  # object black, background white
    mask = cv2.cvtColor(mask, cv2.COLOR_BGR2RGB)  # (1080, 1920, 3)

    # Boolean mask is a numpy array with two dimensions: width and height.
    # On the original mask, object area is filled with white color, background area is filled with black color.
    # On the boolean mask, object area is filled with True, background area is filled with False.
    # mask_boolean = mask[:, :, 0] == 0
    mask_boolean = (mask[:,:,0] == 255) # (1080, 1920) #
    img_with_removed_background = img * np.stack([mask_boolean, mask_boolean, mask_boolean], axis=2) # (1080, 1920, 3)

    return img_with_removed_background, mask_boolean


img_with_removed_background, mask_boolean = remove_obj_background('apple.jpg', 'apple_mask.jpg')
print("Shape of the image of the object:", img_with_removed_background.shape)
print("Shape of the boolean mask:", mask_boolean.shape)
print("\n")
# Image with removed background shape: (860, 1151, 3)
# Boolean mask shape: (860, 1151)

fig, ax = plt.subplots(1, 2, figsize=(16, 7))
ax[0].imshow(img_with_removed_background)
ax[0].set_title('Object with removed background', fontsize=18)
ax[0].axis("off")
ax[1].imshow(mask_boolean)
ax[1].set_title('Boolean mask', fontsize=18)
ax[1].axis("off")
plt.show()


def add_obj(background, img, mask, x, y):
    '''
    Arguments:
    background - background image in CV2 RGB format
    img - image of object in CV2 RGB format
    mask - mask of object in CV2 RGB format
    x, y - coordinates of the center of the object image
    0 < x < width of background
    0 < y < height of background

    Function returns background with added object in CV2 RGB format

    CV2 RGB format is a numpy array with dimensions width x height x 3
    '''

    bg = background.copy()
    h_bg, w_bg = bg.shape[0], bg.shape[1]
    h, w = img.shape[0], img.shape[1]

    # Calculating coordinates of the top left corner of the object image
    x = x - int(w/2)
    y = y - int(h/2)
    mask_boolean = mask[:, :, 0] == 255
    # mask_boolean = mask[:,:,0] == 0
    mask_rgb_boolean = np.stack([mask_boolean, mask_boolean, mask_boolean], axis=2)

    if x >= 0 and y >= 0:
        h_part = h - max(0, y+h-h_bg)  # h_part - part of the image which overlaps background along y-axis
        w_part = w - max(0, x+w-w_bg)  # w_part - part of the image which overlaps background along x-axis
        bg[y:y+h_part, x:x+w_part, :] = bg[y:y+h_part, x:x+w_part, :] * ~mask_rgb_boolean[0:h_part, 0:w_part, :] \
                                        + (img * mask_rgb_boolean)[0:h_part, 0:w_part, :]

    elif x < 0 and y < 0:
        h_part = h + y
        w_part = w + x
        bg[0:0+h_part, 0:0+w_part, :] = bg[0:0+h_part, 0:0+w_part, :] * ~mask_rgb_boolean[h-h_part:h, w-w_part:w, :] \
                                        + (img * mask_rgb_boolean)[h-h_part:h, w-w_part:w, :]

    elif x < 0 and y >= 0:
        h_part = h - max(0, y+h-h_bg)
        w_part = w + x
        bg[y:y+h_part, 0:0+w_part, :] = bg[y:y+h_part, 0:0+w_part, :] * ~mask_rgb_boolean[0:h_part, w-w_part:w, :] \
                                        + (img * mask_rgb_boolean)[0:h_part, w-w_part:w, :]

    elif x >= 0 and y < 0:
        h_part = h + y
        w_part = w - max(0, x+w-w_bg)
        bg[0:0+h_part, x:x+w_part, :] = bg[0:0+h_part, x:x+w_part, :] * ~mask_rgb_boolean[h-h_part:h, 0:w_part, :] \
                                        + (img * mask_rgb_boolean)[h-h_part:h, 0:w_part, :]

    return bg


composition_1 = add_obj(background, img, mask, 160, 120)
plt.figure(figsize=(15,15))
plt.imshow(composition_1)
plt.axis("off")
plt.show()


composition_2 = add_obj(composition_1, img, mask, 3700, 140)
plt.figure(figsize=(15,15))
plt.imshow(composition_2)
plt.axis("off")
plt.show()


composition_3 = add_obj(composition_2, img, mask, 1800, 1100)
plt.figure(figsize=(15,15))
plt.imshow(composition_3)
plt.axis("off")
plt.show()


composition_4 = add_obj(composition_3, img, mask, 180, 2000)
plt.figure(figsize=(15,15))
plt.imshow(composition_4)
plt.axis("off")
plt.show()


composition_5 = add_obj(composition_4, img, mask, 3700, 2070)
plt.figure(figsize=(15,15))
plt.imshow(composition_5)
plt.axis("off")
plt.show()

composition_6 = add_obj(composition_5, img, mask, 1860, 90)
plt.figure(figsize=(15,15))
plt.imshow(composition_6)
plt.axis("off")
plt.show()

composition_7 = add_obj(composition_6, img, mask, 3785, 1065)
plt.figure(figsize=(15,15))
plt.imshow(composition_7)
plt.axis("off")
plt.show()

composition_8 = add_obj(composition_7, img, mask, 1900, 2025)
plt.figure(figsize=(15,15))
plt.imshow(composition_8)
plt.axis("off")
plt.show()

composition_9 = add_obj(composition_8, img, mask, 35, 920)
plt.figure(figsize=(15,15))
plt.imshow(composition_9)
plt.axis("off")
plt.show()

输入图片

apple.jpg
在这里插入图片描述
apple_mask.jpg
在这里插入图片描述

background.jpg

在这里插入图片描述

输出结果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、涉及到的库

cv2.bitwise_not

官方英文文档
在这里插入图片描述

cv2.bitwise_not 是 OpenCV 图像处理库中的一个函数,用于对图像的每个像素值进行取反操作。以下是对 cv2.bitwise_not 函数的中文解释和参数说明:

一、函数原型:

dst = cv2.bitwise_not(src[, dst[, mask]])

二、参数说明:

src:输入图像,可以是灰度图像或彩色图像。

dst:输出图像,与 src 图像具有相同的大小和类型。通常可以省略此参数,函数会自动返回结果。

mask:可选操作掩码,一个8位单通道数组,用于指定要更改的输出数组的元素。如果指定了掩码,则只有掩码中对应位置为255(非零)的像素才会进行取反操作。

三、功能描述:

cv2.bitwise_not 函数会对输入图像 src 中的每个像素值进行取反操作。对于灰度图像,取反操作是将像素值从0~255的范围映射到其对应的相反值(即 255 - pixel_value)。对于彩色图像,会分别对图像中的每个颜色通道(B、G、R)进行取反操作。

四、应用场景:

图像增强:通过取反操作,可以改变图像的亮度和对比度,从而增强图像中的某些特征或细节。

图像处理:在某些特定的图像处理任务中,取反操作可以作为预处理步骤,用于简化后续处理过程或突出图像中的某些信息。

五、示例代码:

python
import cv2  
  
# 读取图像  
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)  # 读取为灰度图像  
  
# 对图像进行取反操作  
not_img = cv2.bitwise_not(img)  
  
# 显示原图像和取反后的图像  
cv2.imshow('Original Image', img)  
cv2.imshow('Bitwise NOT Image', not_img)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

请注意,cv2.bitwise_not 函数只要求输入一张图像,不需要两张图像深度、像素行列必须一致等条件。

cv2.bitwise_and

官方英文文档
在这里插入图片描述

mask,图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0


cv2.bitwise_and 是 OpenCV 库中的一个函数,用于对两个图像进行按位与(bitwise AND)操作。以下是关于 cv2.bitwise_and 的中文说明:

一、函数原型:

dst = cv2.bitwise_and(src1, src2[, dst[, mask]])

二、参数说明:

src1:第一幅输入图像。

src2:第二幅输入图像,其大小和类型应与 src1 相同。

dst:输出图像,与输入图像具有相同的尺寸和数据类型。这是一个可选参数,如果没有提供,则会自动创建一个新的输出图像。

mask:一个可选的8位单通道数组,用于指定哪些像素进行按位与操作。如果指定了掩码,则只有掩码中对应位置为255(非零)的像素才会进行按位与操作。

三、功能描述:

cv2.bitwise_and 函数会对输入的两个图像(src1 和 src2)的每个对应像素值进行按位与操作。具体来说,它会将两个图像在相同位置上的像素值视为二进制数,并对这些二进制数执行按位与运算。按位与操作的特点是,只有当两个二进制数的对应位都为1时,结果的该位才为1,否则为0

在图像处理中,cv2.bitwise_and 常用于掩码操作、图像融合等场景。例如,可以使用一个二值掩码图像来指定哪些像素应该保留在输出图像中,哪些像素应该被丢弃。

四、示例代码:

以下是一个简单的示例,展示如何使用 cv2.bitwise_and 函数对两个图像进行按位与操作:

python
import cv2  
  
# 读取两个图像  
img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)  
img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)  
  
# 确保两个图像具有相同的大小  
if img1.shape != img2.shape:  
    print("Images do not have the same size. Resizing...")  
    # 在此可以添加代码来调整图像大小  
  
# 执行按位与操作  
result = cv2.bitwise_and(img1, img2)  
  
# 显示结果图像  
cv2.imshow('Bitwise AND Result', result)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

注意:在实际应用中,如果两个图像的大小或数据类型不匹配,你可能需要首先进行相应的预处理步骤,例如调整图像大小或转换数据类型。

cv2.add

官方英文文档
在这里插入图片描述


cv2.add 是 OpenCV 库中的一个函数,用于对两个图像或图像与标量进行加法运算。以下是关于 cv2.add 的中文说明:

一、函数原型:

dst = cv2.add(src1, src2[, dst[, mask[, dtype]]])

二、参数说明:

src1:第一个输入数组或图像。

src2:第二个输入数组或图像,或者是一个标量(即单一的数值)。如果 src2 是标量,那么它会与 src1 中的所有像素进行相加。

dst:输出数组或图像,与输入图像具有相同的尺寸和通道数。如果指定了 dst,则结果会保存在 dst 中;否则,会创建一个新的数组或图像。

mask:可选参数,8位单通道的灰度图像,用于指定要更改的输出图像数组的元素。即,只有 mask 对应位置元素不为0的像素才会进行加法运算,否则该位置像素的所有通道分量都设置为0。

dtype:可选参数,输出图像数组的深度(即图像单个像素值的位数)。如果没有指定,则默认与输入图像相同。

三、功能描述:

cv2.add 函数对两个图像或图像与标量进行加法运算。对于两个图像,它们必须具有相同的大小和通道数。对于图像与标量的加法,标量会与图像中的每个像素值进行相加。

加法运算的结果会考虑数据类型和可能的溢出。例如,如果图像是8位无符号整型,那么结果会限制在0到255之间。如果结果超过255,它会被截断为255

四、注意事项:

当使用 cv2.add 进行图像加法时,需要确保两个输入图像具有相同的大小和通道数。

如果可能的话,为了避免图像失真,建议在进行图像加法运算时将数据类型转换为更高的位数,如16位有符号整型或浮点型。

五、示例代码:

以下是一个简单的示例,展示如何使用 cv2.add 函数对两个图像进行加法运算:

import cv2  
  
# 读取两个图像  
img1 = cv2.imread('image1.jpg')  
img2 = cv2.imread('image2.jpg')  
  
# 确保两个图像具有相同的大小  
if img1.shape != img2.shape:  
    print("Images do not have the same size. Resizing...")  
    # 在此可以添加代码来调整图像大小  
  
# 使用 cv2.add 进行图像加法运算  
result = cv2.add(img1, img2)  
  
# 显示结果图像  
cv2.imshow('Image Addition Result', result)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

注意:以上示例假设两个图像是彩色图像,并且已经加载为 NumPy 数组。如果图像是灰度图像,或者你需要对图像进行其他类型的预处理,你可能需要相应地修改代码。

附录——获取 mask 的边界框

请添加图片描述

mask = cv2.imread("mask.jpg")
gray = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
_, new_mask = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
non_zero_indices = np.nonzero(new_mask)
x_ind = non_zero_indices[1]
y_ind = non_zero_indices[0]
x_min, x_max = np.min(x_ind), np.max(x_ind)
y_min, y_max = np.min(y_ind), np.max(y_ind)
bbox = [x_min, x_max, y_min, y_max]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值