简体   繁体   English

OpenCV - 将蒙版应用于彩色图像

[英]OpenCV - Apply mask to a color image

How can I apply mask to a color image in latest python binding (cv2)?如何在最新的 python 绑定 (cv2) 中将蒙版应用于彩色图像? In previous python binding the simplest way was to use cv.Copy eg在以前的 python 绑定中,最简单的方法是使用cv.Copy例如

cv.Copy(dst, src, mask)

But this function is not available in cv2 binding.但是这个功能在 cv2 绑定中是不可用的。 Is there any workaround without using boilerplate code?有没有不使用样板代码的解决方法?

Here, you could use cv2.bitwise_and function if you already have the mask image.在这里,如果您已经拥有蒙版图像,则可以使用cv2.bitwise_and函数。

For check the below code:检查以下代码:

img = cv2.imread('lena.jpg')
mask = cv2.imread('mask.png',0)
res = cv2.bitwise_and(img,img,mask = mask)

The output will be as follows for a lena image, and for rectangular mask. lena 图像和矩形蒙版的输出如下。

在此处输入图片说明

Well, here is a solution if you want the background to be other than a solid black color.好吧,如果您希望背景不是纯黑色,这里有一个解决方案。 We only need to invert the mask and apply it in a background image of the same size and then combine both background and foreground.我们只需要反转遮罩并将其应用于相同大小的背景图像然后将背景和前景结合起来。 A pro of this solution is that the background could be anything (even other image).这个解决方案的一个优点是背景可以是任何东西(甚至是其他图像)。

This example is modified from Hough Circle Transform .这个例子是从Hough Circle Transform修改而来的。 First image is the OpenCV logo, second the original mask, third the background + foreground combined.第一张图片是 OpenCV 标志,第二张是原始蒙版,第三张是背景 + 前景的组合。

应用蒙版并获得自定义背景

# http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.html
import cv2
import numpy as np

# load the image
img = cv2.imread('E:\\FOTOS\\opencv\\opencv_logo.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# detect circles
gray = cv2.medianBlur(cv2.cvtColor(img, cv2.COLOR_RGB2GRAY), 5)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=50, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circles))

# draw mask
mask = np.full((img.shape[0], img.shape[1]), 0, dtype=np.uint8)  # mask is only 
for i in circles[0, :]:
    cv2.circle(mask, (i[0], i[1]), i[2], (255, 255, 255), -1)

# get first masked value (foreground)
fg = cv2.bitwise_or(img, img, mask=mask)

# get second masked value (background) mask must be inverted
mask = cv2.bitwise_not(mask)
background = np.full(img.shape, 255, dtype=np.uint8)
bk = cv2.bitwise_or(background, background, mask=mask)

# combine foreground+background
final = cv2.bitwise_or(fg, bk)

Note: It is better to use the opencv methods because they are optimized.注意:最好使用 opencv 方法,因为它们已优化。

import cv2 as cv

im_color = cv.imread("lena.png", cv.IMREAD_COLOR)
im_gray = cv.cvtColor(im_color, cv.COLOR_BGR2GRAY)

At this point you have a color and a gray image.在这一点上,你有一个彩色和一个灰色的图像。 We are dealing with 8-bit , uint8 images here.我们在这里处理8-bit uint8图像。 That means the images can have pixel values in the range of [0, 255] and the values have to be integers.这意味着图像可以具有[0, 255]范围内的像素值,并且这些值必须是整数。

左色右灰色

Let's do a binary thresholding operation.让我们做一个二元阈值操作。 It creates a black and white masked image.它创建一个黑白蒙版图像。 The black regions have value 0 and the white regions 255黑色区域的值为0 ,白色区域的值为255

_, mask = cv.threshold(im_gray, thresh=180, maxval=255, type=cv.THRESH_BINARY)
im_thresh_gray = cv.bitwise_and(im_gray, mask)

The mask can be seen below on the left.可以在左下方看到面具。 The image on it's right is the result of applying bitwise_and operation between the gray image and the mask.右边的图像是在灰度图像和掩码之间应用bitwise_and操作的结果。 What happened is, the spatial locations where the mask had a pixel value zero (black), became pixel value zero in the result image.发生的事情是,掩码具有像素值零(黑色)的空间位置在结果图像中变成了像素值零。 The locations where the mask had pixel value 255 (white), the resulting image retained it's original gray value.蒙版像素值为 255(白色)的位置,生成的图像保留了原始灰度值。

左掩码,右按位_and_with_mask

To apply this mask to our original color image, we need to convert the mask into a 3 channel image as the original color image is a 3 channel image.要将这个蒙版应用到我们的原始彩色图像上,我们需要将蒙版转换为 3 通道图像,因为原始彩色图像是一个 3 通道图像。

mask3 = cv.cvtColor(mask, cv.COLOR_GRAY2BGR)  # 3 channel mask

Then, we can apply this 3 channel mask to our color image using the same bitwise_and function.然后,我们可以使用相同的bitwise_and函数将此 3 通道掩码应用于我们的彩色图像。

im_thresh_color = cv.bitwise_and(im_color, mask3)

mask3 from the code is the image below on the left, and im_thresh_color is on its right. mask3从代码是图像下方左侧,和im_thresh_color是在其右侧。

left-mask-3channel,right-bitwise_and_with_3channel-mask

You can plot the results and see for yourself.您可以绘制结果并亲自查看。

cv.imshow("original image", im_color)
cv.imshow("binary mask", mask)
cv.imshow("3 channel mask", mask3)
cv.imshow("im_thresh_gray", im_thresh_gray)
cv.imshow("im_thresh_color", im_thresh_color)
cv.waitKey(0)

The original image is lenacolor.png that I found here . 原始图像是我在 这里找到的 lenacolor.png

The other methods described assume a binary mask.描述的其他方法假定使用二进制掩码。 If you want to use a real-valued single-channel grayscale image as a mask (eg from an alpha channel), you can expand it to three channels and then use it for interpolation:如果要使用实值单通道灰度图像作为蒙版(例如来自 alpha 通道),可以将其扩展为三个通道,然后将其用于插值:

assert len(mask.shape) == 2 and issubclass(mask.dtype.type, np.floating)
assert len(foreground_rgb.shape) == 3
assert len(background_rgb.shape) == 3

alpha3 = np.stack([mask]*3, axis=2)
blended = alpha3 * foreground_rgb + (1. - alpha3) * background_rgb

Note that mask needs to be in range 0..1 for the operation to succeed.请注意, mask需要在0..1范围内才能使操作成功。 It is also assumed that 1.0 encodes keeping the foreground only, while 0.0 means keeping only the background.还假设1.0编码仅保留前景,而0.0表示仅保留背景。

If the mask may have the shape (h, w, 1) , this helps:如果掩码可能具有形状(h, w, 1) ,这有助于:

alpha3 = np.squeeze(np.stack([np.atleast_3d(mask)]*3, axis=2))

Here np.atleast_3d(mask) makes the mask (h, w, 1) if it is (h, w) and np.squeeze(...) reshapes the result from (h, w, 3, 1) to (h, w, 3) .这里np.atleast_3d(mask)制作掩码(h, w, 1)如果它是(h, w)并且np.squeeze(...)将结果从(h, w, 3, 1)重塑为(h, w, 3)

Answer given by Abid Rahman K is not completely correct. Abid Rahman K 给出的答案并不完全正确。 I also tried it and found very helpful but got stuck.我也试过了,发现很有帮助,但卡住了。

This is how I copy image with a given mask.这就是我使用给定蒙版复制图像的方式。

x, y = np.where(mask!=0)
pts = zip(x, y)
# Assuming dst and src are of same sizes
for pt in pts:
   dst[pt] = src[pt]

This is a bit slow but gives correct results.这有点慢,但给出了正确的结果。

EDIT:编辑:

Pythonic way. Pythonic 的方式。

idx = (mask!=0)
dst[idx] = src[idx]

Traverse each step in notebook car image 遍历笔记本车图像中的每个步骤

道路图像

Explanation with example 举例说明

import cv2

import numpy as np



img1 = cv2.imread("road.jpg")

img2 = cv2.imread("car.jpg")

img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

ret, mask = cv2.threshold(img2_gray, 240, 255, cv2.THRESH_BINARY)

mask_inv = cv2.bitwise_not(mask)


road = cv2.bitwise_and(img1, img1, mask=mask)


car = cv2.bitwise_and(img2, img2, mask=mask_inv)

result = cv2.add(road, car)


cv2.imshow("img1", img1)
cv2.imshow("img2", img2)
cv2.imshow("road background", road)

cv2.imshow("car no background", car)

cv2.imshow("mask", mask)
cv2.imshow("mask inverse", mask_inv)

cv2.imshow("result", result)

cv2.waitKey(0)
cv.destroyAllWindows()

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

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