图像处理部分5:算术运算、位运算和掩码处理
在这个图像处理系列的第五部分中,我们将更多地讨论Python中的算术和位运算,以及图像屏蔽。
建议在开始这里的隐蔽学习冒险之前,先运行一遍之前的文章。
创建环境
以下代码行在所有给出的应用程序中都使用。我们将在此处包含它们,以便您不必阅读大段的代码。
帮助减少杂乱的摆放 🙂
# importing numpy to work with pixels
import numpy as np
# importing argument parsers
import argparse
# importing the OpenCV module
import cv2
# initializing an argument parser object
ap = argparse.ArgumentParser()
# adding the argument, providing the user an option
# to input the path of the image
ap.add_argument("-i", "--image", required=True, help="Path to the image")
# parsing the argument
args = vars(ap.parse_args())
# reading the image location through args
# and reading the image using cv2.imread
image = cv2.imread(args["image"])
使用Python对图像进行算术操作
算术运算可以改善图像的许多方面。
我们可以运用灯光、阴影以及红色、蓝色和绿色增强来进行工作。
很多应用程序上的图像滤镜都使用相同的方法来改变和美化照片。
所以,让我们开始编写所有的代码吧!
首先,为了了解限制是否可以超过255或者0,我们可以进行一项简单的测试,测试结果会给我们255和0。
# printing out details of image min, max and the wrap around
print("max of 255 :", str(cv2.add(np.uint8([200]), np.uint8([100]))))
print("min of 0 :", str(cv2.subtract(np.uint8([50]), np.uint8([100]))))
print("wrap around :", str(np.uint8([200]) + np.uint8([100])))
print("wrap around :", str(np.uint8([50]) - np.uint8([100])))
在这个例子中,我们将图像中所有的像素值增加100的强度。
# adding pixels of value 255 (white) to the image
M = np.ones(image.shape, dtype="uint8") * 100
added = cv2.add(image, M)
cv2.imshow("Added", added)
cv2.waitKey(0)
通过使用NumPy模块构建一个与我们的图像大小相同的矩阵,并将其与图像相加来完成此操作。
如果我们希望让图像变暗,我们可以从图像的像素值中减去一定数值,如下所示。
# adding pixels of value 0 (black) to the image
M = np.ones(image.shape, dtype="uint8") * 50
subtracted = cv2.subtract(image, M)
cv2.imshow("Subtracted", subtracted)
cv2.waitKey(0)
这将为您提供两种不同版本的原始图像,一种更亮,另一种更暗。
按位运算
在尝试对图像进行掩码时,我们经常使用位运算。
OpenCV的这个特性允许我们过滤出对我们有意义的图像部分。
建立
为了进行按位运算,我们首先需要两个变量或图像,以便对其进行操作。
所以,让我们通过位运算来创建一个位方和一个位圆。
请注意,按位操作需要图像为黑白。
# creating a square of zeros using a variable
rectangle = np.zeros((300, 300), dtype="uint8")
cv2.rectangle(rectangle, (25, 25), (275, 275), 255, -1)
cv2.imshow("Rectangle : ", rectangle)
# creating a circle of zeros using a variable
circle = np.zeros((300, 300), dtype="uint8")
cv2.circle(circle, (150, 150), 150, 255, -1)
cv2.imshow("Circle : ", circle)
你收到的输出图像应该看起来像这样。

与AND操作结合
位运算加法是指对两个不同图像进行相加,并使用每个像素的与操作来决定哪个图像将被显示。
# the bitwise_and function executes the AND operation
# on both the images
bitwiseAnd = cv2.bitwise_and(rectangle, circle)
cv2.imshow("AND", bitwiseAnd)
cv2.waitKey(0)
将圆和正方形进行按位相加,得到的输出应该如下所示。

给定一个选择,使用”或”操作。
按位或运算提供了两幅图像的乘积,对每个像素进行按位或操作。
# the bitwise_or function executes the OR operation
# on both the images
bitwiseOr = cv2.bitwise_or(rectangle, circle)
cv2.imshow("OR", bitwiseOr)
cv2.waitKey(0)
当执行按位或操作时,您应该得到类似这样的结果。

使用XOR操作实现独占性
cv2 模块提供的另一个操作是 XOR 运算,我们可以通过 bitwise_xor 函数进行使用。
# the bitwise_xor function executes the XOR operation
# on both the images
bitwiseXor = cv2.bitwise_xor(rectangle, circle)
cv2.imshow("XOR", bitwiseXor)
cv2.waitKey(0)

使用NOT操作进行否定
最后,我们有否定操作,使用bitwise_not函数执行。
逻辑运算NOT只需要一张图像,因为我们这里不涉及加法或减法操作。
但是,我们在这里仍然可以两者都使用,这也是一个选择。
# the bitwise_not function executes the NOT operation
# on both the images
bitwiseNot = cv2.bitwise_not(rectangle, circle)
cv2.imshow("NOT", bitwiseNot)
cv2.waitKey(0)
在这种情况下,圆形位于正方形内部,因此不可见。

使用Python OpenCV进行图像遮罩
遮罩在图像处理中用于输出感兴趣的区域,或者简单地说,我们所关注的图像部分。
我们倾向于使用按位操作进行掩码,因为它使我们能够丢弃我们不需要的图像部分。
那么,让我们开始遮罩操作吧!
对图像进行遮蔽的过程 (duì de
在我们的屏蔽过程中,我们有三个步骤。
- 创建一个与图像尺寸相同的黑色画布,并将它命名为掩膜。
通过在图像上绘制任何形状并为其提供白色,改变掩膜的值。
对图像和掩膜执行按位相加操作。
按照同样的过程,让我们创建几个蒙版并将它们应用在我们的图片上。
首先,让我们使用一个矩形蒙版来进行操作。
# creating a mask of that has the same dimensions of the image
# where each pixel is valued at 0
mask = np.zeros(image.shape[:2], dtype="uint8")
# creating a rectangle on the mask
# where the pixels are valued at 255
cv2.rectangle(mask, (0, 90), (290, 450), 255, -1)
cv2.imshow("Mask", mask)
# performing a bitwise_and with the image and the mask
masked = cv2.bitwise_and(image, image, mask=mask)
cv2.imshow("Mask applied to Image", masked)
cv2.waitKey(0)
现在我们用一个圆形遮罩来试试。
# creating a mask of that has the same dimensions of the image
# where each pixel is valued at 0
mask = np.zeros(image.shape[:2], dtype="uint8")
# creating a rectangle on the mask
# where the pixels are valued at 255
cv2.circle(mask, (145, 200), 100, 255, -1)
cv2.imshow("Mask", mask)
# performing a bitwise_and with the image and the mask
masked = cv2.bitwise_and(image, image, mask=mask)
cv2.imshow("Mask applied to Image", masked)
cv2.waitKey(0)
如果一切顺利的话,我们应该会收到类似于这样的输出。

结论
我们终于开始进入图像处理的核心部分了,了解其中的位运算和掩码操作非常重要。
这个概念能帮助我们屏蔽掉对我们感兴趣的部分或仅接收我们感兴趣的部分图像,非常有用。
我们的进展速度还算可以,但如果你想直接跳到结尾,就请便吧!
这里有一些关于OpenCV和人脸识别的文章,以及一个关于Android和CameraX OpenCV的Java实现。
参考文献
- Official OpenCV Website
- Introduction to starting out with OpenCV
- My GitHub Repository for Image Processing
- Arithmetic Operations Code
- Bitwise Operations Code
- Masking Code