OpenCV 具有 copyTo 函数,可以将蒙版区域从一个 Mat 复制到另一个。
http://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html#a4331fa88593a9a9c14c0998574695ebb
Python 绑定(bind)中的 this 等价物是什么?我想用二进制掩码将图像的一个区域复制到另一个图像。
最佳答案
cv::Mat::copyTo
根据输出矩阵是否已初始化,做两件事之一。如果您的输出矩阵未初始化,则使用带有掩码的 copyTo
创建一个与输入类型相同的新输出矩阵,并且所有 channel 的所有值都设置为 0。一旦发生这种情况,由掩码定义的图像数据将被复制,矩阵的其余部分将设置为 0。如果您的输出矩阵已初始化并且已经包含内容,copyTo
从源复制掩码中定义的像素,并在目标中保留不属于掩码的像素。因此,由源图像中的掩码定义的像素替换被复制到输出中。
因为 OpenCV 现在使用 numpy
与库进行交互,所以执行这两种方法都非常容易。为了与这篇文章中看到的其他答案区分开来,第一种方法可以通过简单地以元素方式将掩码与图像相乘来完成。假设您的输入称为 img
并且您的二进制掩码称为 mask
我假设掩码是 2D,只需执行以下操作:
import numpy as np
import cv2
mask = ... # define mask here
img = cv2.imread(...) # Define input image here
# Create new image
new_image = img * (mask.astype(img.dtype))
虽然以上代码假定 img
和 mask
共享相同数量的 channel 。如果您使用彩色图像作为源和我已经假设的 2D 蒙版,它会变得很棘手。因此, channel 总数是 2 而不是 3,所以上面的语法会给你一个错误,因为两者之间的维度不再兼容。当您使用彩色图像时,您需要适应这一点。您可以通过向掩码添加单例三维来实现此目的,以便可以利用广播。
import numpy as np
import cv2
mask = ... # define mask here
img = cv2.imread(...) # Define input image here
# Create new image
# Case #1 - Other image is grayscale and source image is colour
if len(img.shape) == 3 and len(mask.shape) != 3:
new_image = img * (mask[:,:,None].astype(img.dtype))
# Case #2 - Both images are colour or grayscale
elif (len(img.shape) == 3 and len(mask.shape) == 3) or \
(len(img.shape) == 1 and len(mask.shape) == 1):
new_image = img * (mask.astype(img.dtype))
# Otherwise, we can't do this
else:
raise Exception("Incompatible input and mask dimensions")
对于第二种方法,假设我们有另一个名为 other_image
的图像,您希望将掩码定义的该图像中的内容复制回目标图像 img
。在这种情况下,您首先要做的是使用 numpy.where
确定掩码中非零的所有位置。 ,然后使用这些索引或切片到您的图像以及您要复制的位置。就像第一种方法一样,我们还必须注意两个图像之间的 channel 数:
import numpy as np
import cv2
mask = ... # define mask here
img = cv2.imread(...) # Define input image here
other_image = cv2.imread(...) # Define other image here
locs = np.where(mask != 0) # Get the non-zero mask locations
# Case #1 - Other image is grayscale and source image is colour
if len(img.shape) == 3 and len(other_image.shape) != 3:
img[locs[0], locs[1]] = other_image[locs[0], locs[1], None]
# Case #2 - Both images are colour or grayscale
elif (len(img.shape) == 3 and len(other_image.shape) == 3) or \
(len(img.shape) == 1 and len(other_image.shape) == 1):
img[locs[0], locs[1]] = other_image[locs[0], locs[1]]
# Otherwise, we can't do this
else:
raise Exception("Incompatible input and output dimensions")
下面是两种方法的运行示例。我将使用 Cameraman 图像,它是大多数图像处理算法中常见的标准测试图像。
我还人为地制作了图像颜色,即使它被可视化为灰度,但强度将被复制到所有 channel 。我还将定义一个掩码,它只是左上角的 100 x 100 子区域,因此我们将创建一个仅复制该子区域的输出图像:
import numpy as np
import cv2
# Define image
img = cv2.imread("cameraman.png")
# Define mask
mask = np.zeros(img.shape, dtype=np.bool)
mask[:100, :100] = True
当您使用第一种方法并且当我们显示结果时,我们得到:
我们可以看到我们创建了一个输出图像,其中左上角的 100 x 100 子区域包含我们的图像数据,其余像素设置为 0。这取决于设置为 True 的掩码位置
。对于第二种方法,我们将创建另一张随机图像,其大小与跨越所有 channel 的 [0, 255]
的输入图像相同。
# Define other image
other_image = (255*np.random.rand(*img.shape)).astype(np.uint8)
一旦我们用第二种方法运行完代码,我现在得到这张图片:
如您所见,图像的左上角已根据设置为 True
的 mask 位置进行了更新。
关于python - Python OpenCV 绑定(bind)中的 copyTo 是否等效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41572887/