简体   繁体   English

Python OpenCV绑定中的copyTo等价物?

[英]Equivalent of copyTo in Python OpenCV bindings?

OpenCV has the copyTo function, which enables copying a masked area from one Mat to another. OpenCV具有copyTo功能,可以将遮罩区域从一个Mat复制到另一个Mat。

http://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html#a4331fa88593a9a9c14c0998574695ebb http://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html#a4331fa88593a9a9c14c0998574695ebb

What's the equivalent of this in the Python bindings? Python绑定中的等价物是什么? I'd like to copy an area of an image to another image, with a binary mask. 我想用二进制掩码将图像区域复制到另一个图像。

cv::Mat::copyTo does one of two things depending on whether the output matrix has been initialized. cv::Mat::copyTo根据输出矩阵是否已初始化而执行以下两种操作之一。 If your output matrix is not initialized, using copyTo with a mask creates a new output matrix that is the same type as the input and all of the values are set to 0 over all channels. 如果未初始化输出矩阵,则使用带掩码的copyTo会创建一个与输入类型相同的新输出矩阵,并且所有值都将在所有通道上设置为0。 Once that happens, the image data that is defined by the mask is copied over with the rest of the matrix being set to 0. If your output matrix is initialized and already consists of content, copyTo copies over the pixels that are defined in the mask from the source and leaves the pixels that were not part of the mask to be intact in the destination. 一旦发生这种情况,掩模定义的图像数据将被复制,矩阵的其余部分将被设置为0.如果输出矩阵初始化且已包含内容,则copyTo复制掩码中定义的像素来自源并使不属于掩码的像素在目标中保持完整。 Therefore, a replacement of pixels that are defined by the mask from the source image gets copied over to the output. 因此,从源图像中替换由掩模定义的像素将被复制到输出。

Because OpenCV now uses numpy to interface with the library, it's very easy to do either methods. 因为OpenCV现在使用numpy与库接口,所以很容易做到这两种方法。 To differentiate from the other answer seen in this post, the first method can be accomplished by simply multiplying the mask with the image in an element-wise fashion. 为了区别于本文中看到的另一个答案,第一种方法可以通过简单地将蒙版与图像以元素方式相乘来实现。 Assuming that your input is called img and your binary mask is called mask where I am assuming the mask is 2D, simply do the following: 假设您的输入被称为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))

The above code though assumes that both img and mask share the same number of channels. 上面的代码虽然假设imgmask共享相同数量的通道。 It gets tricky if you are using a colour image as the source and the mask 2D as I have already assumed. 如果您使用彩色图像作为源和我已经假设的掩模2D,那将变得棘手。 Therefore, the total number of channels is 2 and not 3 and so the above syntax will give you an error as the dimensions between the two are no longer compatible. 因此,通道总数为2而不是3,因此上述语法会给您一个错误,因为两者之间的尺寸不再兼容。 You'll need to accommodate for this when you are using colour images. 使用彩色图像时,您需要适应这一点。 You can do this by adding a singleton third dimension to the mask so that broadcasting can be taken advantage of. 您可以通过向蒙版添加单个第三维来执行此操作,以便可以利用广播。

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")

For the second approach, let's assume that we have another image called other_image where you want to copy the contents in this image defined by your mask back to the target image img . 对于第二种方法,我们假设我们有另一个名为other_image图像,您希望将掩模定义的此图像中的内容复制回目标图像img In this case, what you would do first is determine all of the locations in the mask that are non-zero using numpy.where , then use these to index or slice into your image as well as where you want to copy from. 在这种情况下,首先要做的是使用numpy.where确定掩码中非零的所有位置,然后使用这些位置索引或切片到图像以及要从中复制的位置。 We also have to be mindful of the number of channels between the two images just like with the first approach: 我们还必须注意两个图像之间的通道数量,就像第一种方法一样:

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")

Here's an example run for both approaches. 这是两种方法的示例运行。 I'm going to use the Cameraman image that's a standard test image seen in most image processing algorithms. 我将使用Cameraman图像,这是大多数图像处理算法中看到的标准测试图像。

在此输入图像描述

I've also artificially made the image colour, even though it's visualized as grayscale but the intensities will be copied over to all channels. 我还人工制作了图像颜色,即使它可视化为灰度,但强度将被复制到所有通道。 I am also going to define a mask that is simply the top left 100 x 100 subregion and so we will create an output image that only copies this subregion: 我还将定义一个掩码,它只是左上角的1​​00 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

When you use the first method and when we show the results, we get: 当您使用第一种方法时,当我们显示结果时,我们得到:

在此输入图像描述

We can see that we created an output image where the top left 100 x 100 subregion contains our image data with the rest of the pixels set equal to 0. This is subject to the mask locations that are set to True . 我们可以看到,我们创建了一个输出图像,其中左上角的1​​00 x 100子区域包含我们的图像数据,其余像素设置为0.这取决于设置为True的蒙版位置。 For the second approach, we will create the other image to be one that is random of the same size as the input image that spans from [0, 255] for all channels. 对于第二种方法,我们将创建另一个图像,该图像是与所有通道的[0, 255]跨越的输入图像相同大小的随机图像。

# Define other image
other_image = (255*np.random.rand(*img.shape)).astype(np.uint8)

Once we run through the code with the second approach, I get this image now: 一旦我们用第二种方法运行代码,我现在得到这个图像:

在此输入图像描述

As you can see, the top-left corner of the image has been updated as subject to the mask locations that are set to True . 如您所见,图像的左上角已更新为受设置为True的蒙版位置的约束。

请注意,如果这正是您想要的,但是对于使用Python中的掩码进行复制,我会使用cv2.bitwise_

new_image = cv2.bitwise_and(old_image,binary_mask)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM