如何正确地将蒙版插入原始图像?

How to properly insert mask into original image?

我的目标是用圆形噪声(盐和 pepper/black 和白点)覆盖一张脸,但我设法实现的只是矩形噪声。

使用这张图片:

我找到了面部坐标 (x,y,w,h) = [389, 127, 209, 209] 并使用这个 function 添加噪音
喜欢:

img = cv2.imread('like_this.jpg')
x,y,w,h = [389, 127, 209, 209]

noised = add_noise(img[y:y+h,x:x+w])
new = img.copy()
new[y:y+h,x:x+w]  = noised

cv2.imshow('new', new)

x,y,w,h 我发现我希望我的圆在 (493, 231) 处,半径为 105

我研究过我发现了一些关于屏蔽和按位运算的东西,所以我尝试了:

mask = np.zeros(new.shape[:2], dtype='uint8')
cv2.circle(mask, (493, 231), 105, 255, -1)

new_gray = cv2.cvtColor(new, cv2.COLOR_BGR2GRAY)
masked = cv2.bitwise_and(new_gray, new_gray , mask=mask)

cv2.imshow('masked', masked)

这里,问题出现了:

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
OR = cv2.bitwise_or(masked, img_gray) # removes the black dots, idk why 

cv2.imshow('bitwise - OR', OR)

黑点从噪声中移除,除此之外,我似乎无法将 OR 转换回 BGR。

也许有更好的方法。

拜托,help/guidance需要!

二进制条件下的按位运算函数在像素值为零时“关闭”像素,在像素值大于零时将其“打开”。

在你的例子中,bitwise_or“移除”了蒙版的黑色背景和噪声的黑点。

我建议这样做:

# Read image
img = cv2.imread('like_this.jpg')
x,y,w,h = [389, 127, 209, 209]

# Add squared noise
noised = add_noise(img[y:y+h,x:x+w])
new = img.copy()
new[y:y+h,x:x+w] = noised

# Transform the image to graylevel
new_gray = cv2.cvtColor(new, cv2.COLOR_BGR2GRAY)

# Create a mask in which black noise is equal to 0 and white to 2
mask = np.zeros(new.shape[:2], dtype='uint8')
mask[new_gray==0] = 1
mask[new_gray==255] = 2

# Mask the previous mask with a circle
circle = np.zeros(new.shape[:2], dtype='uint8')
circle = cv2.circle(circle, (493, 231), 105, 1, -1)
mask = mask * circle

plt.imshow(mask)
plt.show()

# Join the mask adding the noise to the image
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray[mask==1] = 0
gray[mask==2] = 255

cv2.imshow('Result', gray)
cv2.waitKey(0)

希望有用。如果您需要更多帮助,请告诉我。

所以问题是如何使用掩码。有两个选项,numpy 和 OpenCV.

numpy

由于您将噪声区域复制到结果中,现在想要恢复之外的所有内容,我将使用mask == 0获得一个布尔数组圈外处处为真

使用 numpy,布尔数组可以用作索引。结果是一个“视图”,它的行为就像一个切片。通过它的操作会影响原始数据。

noised = add_noise(img[y:y+h,x:x+w])
new = img.copy()
new[y:y+h,x:x+w] = noised # whole rectangle affected

new[mask == 0] = img[mask == 0] # restore everything outside of the circle

所有三个数组 (mask, new, img) 需要具有相同的形状。

OpenCV,掩码

与 Python 和 numpy 无关,但它的许多 C++ API 都采用可选的 mask 参数来修改该函数的操作。 Mat::copyTo() 就是这样一种方法。

OpenCV,按位运算

通过按位运算,掩码将不再只是将每个像素标记为真或假,但它必须是 3 通道并且每个值的所有八位都计数,因此它必须仅包含 0 和 255 ( 0xFF).

我会先擦除圆圈外的所有内容,然后添加回到圆圈外的源部分。两个操作都使用 bitwise_and。需要两个操作,因为按位操作不能只是“覆盖”。它们对两个操作数都有反应。我还将使用 numpy 的 ~ 运算符按位取反掩码。

bitwise_mask = cv.cvtColor(mask, cv.COLOR_GRAY2BGR) # blow it up
new = cv.bitwise_and(new, bitwise_mask)
new += cv.bitwise_and(img, ~bitwise_mask)