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

时间:2012-05-06 08:32:57

标签: python opencv image-processing mask

如何在最新的python绑定(cv2)中将蒙版应用于彩色图像?在以前的python绑定中,最简单的方法是使用cv.Copy例如

cv.Copy(dst, src, mask)

但是这个功能在cv2绑定中不可用。没有使用样板代码有没有解决方法?

6 个答案:

答案 0 :(得分:46)

如果您已有掩码图像,可以使用cv2.bitwise_and功能。

检查以下代码:

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

对于lena图像和矩形蒙版,输出如下。

enter image description here

答案 1 :(得分:11)

嗯,如果您希望背景不是纯黑色,这是一个解决方案。我们只需要反转蒙版并将其应用于相同大小的背景图像 ,然后将背景和前景结合起来。这个解决方案的专家是背景可以是任何东西(甚至是其他图像)。

此示例已从Hough Circle Transform修改。第一个图像是OpenCV徽标,第二个是原始蒙版,第三个是背景+前景组合。

apply mask and get a customized background

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

注意:最好使用opencv方法,因为它们已经过优化。

答案 2 :(得分:3)

所描述的其他方法假设二进制掩码。如果要使用实值单通道灰度图像作为遮罩(例如,从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

请注意,mask必须在0..1范围内才能成功完成操作。还假设1.0仅对前景进行编码,而0.0表示仅保留背景。

如果蒙版的形状为(h, w, 1),则有助于:

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

如果np.atleast_3d(mask) (h, w, 1) (h, w) np.squeeze(...) (h, w, 3, 1) (h, w, 3) #include <emmintrin.h> #include <stdio.h> #include <stdlib.h> void simd_2x2(int lda, double *A, double *B, double *C) { __m128d a, b1, c1; for (int k = 0; k < lda; k++) { //printf("%f\n",C[k * lda]); c1 = _mm_loadu_pd(C + k * lda); //load unaligned block in C //c2 = _mm_loadu_pd(C + 1 * lda); for (int i = 0; i < lda; ++i) { a = _mm_load_pd(A + i * lda);//load aligned i-th column of A b1 = _mm_load1_pd(B + i + k * lda); //load i-th row of B //b2 = _mm_load1_pd(B + i + 1 * lda); c1 = _mm_add_pd(c1, _mm_mul_pd(a, b1)); //rank-1 update //c2 = _mm_add_pd(c2, _mm_mul_pd(a, b2)); } _mm_storeu_pd(C + k * lda, c1); //store unaligned block in C //_mm_storeu_pd(C + 1 * lda, c2); } } int main() { int n = 2; double *buf = NULL; buf = (double *)malloc(3 * n * n * sizeof(double)); double *A = buf + 0; double *B = A + n * n; double *C = B + n * n; simd_2x2(n, A, B, C); return 0; } ,则n=2会将结果从A = 4.000000 3.000000 2.000000 4.000000 B = 1.000000 3.000000 2.000000 4.000000 C = 0.000000 0.000000 0.000000 0.000000 C = C + A * B = 10.000000 24.000000 10.000000 22.000000 重新塑造为n=4

答案 3 :(得分:2)

import cv2 as cv

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

在这一点上,您有彩色和灰色图像。我们在这里处理8-bituint8图片。这意味着图像的像素值可以在[0, 255]范围内,并且这些值必须为整数。

left-color,right-gray

让我们执行二进制阈值操作。它创建一个遮罩的图像。黑色区域的值为0,白色区域的值为255

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

二进制掩码可在下面的左侧看到。右边的图像是在灰色图像和蒙版之间应用bitwise_and操作的结果。发生的是,蒙版的像素值为零(黑色)的空间位置在结果图像中变为像素值为零。蒙版的像素值为255(白色)的位置,结果图像将保留其原始灰度值。

left-mask,right-bitwise_and_with_mask

要将此蒙版应用于原始彩色图像,我们需要将蒙版转换为3通道图像,因为原始彩色图像是3通道图像。

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

然后,我们可以使用相同的bitwise_and函数将此蒙版应用于原始彩色图像。

im_thresh_color = cv.bitwise_and(im_color, mask3)
代码中的

mask3是左下图,右边是im_thresh_color

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

您可以绘制结果并亲自查看。

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)

原始图片是我发现的herelenacolor.png

答案 4 :(得分:1)

遍历笔记本的每个步骤 car image

road image

示例说明

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

答案 5 :(得分:0)

Abid Rahman K给出的答案并不完全正确。我也尝试过,发现非常有帮助,但卡住了。

这是我用给定面具复制图像的方式。

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]

这有点慢,但会给出正确的结果。

编辑:

Pythonic方式。

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