[英]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(白色)的位置,生成的图像保留了原始灰度值。
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
是在其右侧。
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.