图像的算术操作

2021-12-08 18:34:24 浏览数 (1)

OpenCV 的基础图像操作都只是针对图像中的像素点,并不是直接对图像整体进行的操作。而很多时候并不能仅通过改变像素点来进行图像的操作,为此我们需要学习关于图像的算术操作。

1.图像加法

对于两张相同大小的图像,可以使用 cv2.add 函数对它们进行加法运算。使用该函数时, 两张图像的大小必须一致,或者加数只是一个简单的标量。

cv2.add(img1,img2)

cv2.add 的操作就是将两张图像上 的像素值相加,其语法如下。其参数分别解释如下。

 img1:被加数,即第一张图像。

 img2:加数,即第二张图像,也可以是一个简单的标量。

2.OpenCV 与 NumPy 模块算术加法的区别

从第 1 章中我们就已经知道,图像在程序中是以矩阵的形式保存的,因此我们也可以用矩 阵加法来进行两张图像像素点的相加。除了 OpenCV 中的 cv2.add 函数以外,我们还可以使用 NumPy 模块来进行图像的加法运算。

但两者在某些情况下会产生不同的结果,原因在于 OpenCV 和 NumPy 模块处理溢出的方 法不同。溢出是什么呢?举个例子,如果一张单通道图像的像素点数值为 250,另一张图像上 同位置的像素点数值为 10,那么二者相加以后就是 260,可是像素值的上限是 255,所以这个 时候我们就遇到了溢出问题。

OpenCV 处理溢出的方法是饱和操作,而 NumPy 模块处理溢出的方法是模操作。例如, 在 OpenCV 中,如果遇到了 250 10=260 这种情况,它会选取最大值 255;而在 NumPy 模块中, 它就等于执行了(250 10)%5=5。基于我们的理解来讲,一般比较希望出现 OpenCV 中的 结果,而且 NumPy 模块的结果与原来的两张图像都有比较大的差别,所以在对图像进行算术 加法的时候,相较于 NumPy 模块,我们更加倾向于使用 OpenCV。

3.图像加法练习

了解了 NumPy 模块以及 OpenCV 中图像加法的区别以后,现在我们来实战演练一下。这 里使用了两张差别较大的图像来进行代码的测试,如图 1 和图 2所示。现在我们通过 cv2.add 函数对这两张图像进行图像的算术加法,示例代码如下。

代码语言:javascript复制
import cv2 
import numpy 
img1=cv2.imread('1.jpg') 
img2=cv2.imread('2.jpg') 
img3=cv2.add(img1,img2) 
cv2.imshow('img',img3)
cv2.waitKey(0)
cv2.destroyAllWindows()

图1 星形图 图2 心形图

运行代码以后,结果如图3 所示。

图 3 图像加法结果

4.图像加权

我们进行的简单的图像直接算术加法,只是把两张图像的像素值进行了相加,并 没有进行其他的操作。这里介绍一下权重的概念,对于使用 cv2.add 函数合成的图像,它的像 素值设为 c,图 1 所示图像的像素值设为 a,图 2所示图像的像素值设为 b,那么 c=a b, 这种情况下双方的权重相等。但我们可以改变两张图像的占比,例如第一张图像占比 70%, 第二张图像占比 30%,这个时候 c=0.7×a 0.3×b;如果我们还需要加一个常数 k,那么整个式 子就会变成 c=0.7×a 0.3×b k。对于这个实现,我们可以利用 cv2.addWeighted 函数,其函数语 法如下。

cv2.addWeighted(src1,alpha,src2,beta,gamma)

其参数分别解释如下。

 src1:第一张图像。

 alpha:第一张图像的权重。

 src2:第二张图像。

 beta:第二张图像的权重。

 gamma:附加常数。

示例代码如下。

img=cv2.addWeighted(img1,0.2,img2,0.3,10)

现在我们对图 1 所示的图像和图 2 所示的图像进行加权的操作,常数 k 的取值为 0, 示例代码如下。

代码语言:javascript复制
import cv2 
import numpy 
img1=cv2.imread('1.jpg') 
img2=cv2.imread('2.jpg') 
img3=cv2.addWeighted(img1,0.7,img2,0.3,0) 
cv2.imshow('img',img3) 
cv2.waitKey(0) 
cv2.destroyAllWindows()

图像加权结果如图 4 所示。

图 4 图像加权结果

也可以通过常数 k 给整张图像的所有像素点加上一个固定的值,读者可以自行修改代码来 实现。

5.图像逻辑运算

这里要介绍掩膜(mask)的概念,按照字面意思来理解就是用来掩盖的薄膜。掩膜的作用有很多,这里进行简单的介绍。

 用来提取要捕获的区与区域:用预先制作的感兴趣区域(ROI)掩膜与待处理图像相 乘(即逻辑与运算),得到感兴趣区域图像,感兴趣区域内图像值保持不变,而感兴 趣区域外图像值都为 0。

 起屏蔽作用:用掩膜对图像上的某些区域进行屏蔽,使其不参加处理,用来减少计算 量;也可仅对屏蔽区做处理或统计。

 进行结构特征提取:用相似性变量或图像匹配方法检测和提取图像中与掩膜相似的结 构特征。

 特殊形状图像的制作:用一个想要的形状的掩膜进行图像的覆盖(类似橡皮泥的模具)。在所有图像基本运算的操作函数中,凡是带有掩膜的处理函数,其掩膜都参与运算(输入 图像在进行函数逻辑运算之后再与掩膜图像或矩阵进行相关的运算)。在计算机视觉中,我们常用的逻辑运算有以下几种。

逻辑非的语法如下。

cv2.bitwise_not(img,mask=None) #将图像里的像素值按位取反

逻辑与的语法如下。

cv2.bitwise_and (img1,img2,mask=None) #将图像里的像素值按位与

逻辑或的语法如下。

cv2.bitwise_or(img1,img2,mask=None) #将图像里的像素值按位或

逻辑异或的语法如下。

cv2.bitwise_xor (img1,img2,mask=None) #将图像里的像素值按位异或

其参数分别解释如下。

 img:处理的图像。

 img1:进行操作的第一张图像。

 img2:进行操作的第二张图像。

 mask:进行操作时用到的掩膜,默认为没有掩膜。按位运算的具体介绍如下。

 AND:当且仅当两个像素值都大于 0 时,才为真。

 OR:如果两个像素值中的任何一个大于 0,则为真。

 XOR:异或,当且仅当两个像素值转换为二进制时进行异或计算。

 NOT:取反,倒置图像中的“开”和“关”像素值。我们一个一个来看逻辑运算的效果。

首先是对图 1 所示的图像进行逻辑非运算,示例代码如下。

代码语言:javascript复制
import cv2 
import numpy 
img=cv2.imread('1.jpg',0) 
img=cv2.bitwise_not(img) 
cv2.imshow('img',img)
cv2.waitKey(0) 
cv2.destroyAllWindows()

注意:这里笔者是直接用灰度图的形式读入,因为图 1所示的图像只有黑白二色,所 以可以看成二值图。

运行代码,效果如图5 所示。

下面我们引入图 2 所示的图像来作为掩膜,对图5 所示的图像进行掩膜式的逻辑非 运算, 示例代码如下。

代码语言:javascript复制
import cv2 
import numpy 
img1=cv2.imread('1.jpg',0) 
mask=cv2.imread('2.jpg',0) 
img=cv2.bitwise_not(img1,mask=mask) 
cv2.imshow('img',img)
 cv2.waitKey(0) 
cv2.destroyAllWindows()

运行代码以后,效果如图6 所示。

图 5 逻辑非运算 图 6 掩膜式的逻辑非运算

观察图6,可以看到图 2 所示的黑色部分(逻辑 0)与图 5所示的白色部分的重 叠处变模糊了,这就是掩膜的作用。

下面我们来尝试进行其他的逻辑运算,首先创建一张方形图,如图 7 所示。我们将方形图作为掩膜,对星形图和心形图进行掩膜式的逻辑与运算,示例代码如下。

代码语言:javascript复制
import cv2 
import numpy 
img1=cv2.imread('1.jpg',0) 
img2=cv2.imread('2.jpg',0) 
mask=cv2.imread('3.jpg',0) 
img=cv2.bitwise_and(img1,img2,mask=mask) 
cv2.imshow('img',img)
 cv2.waitKey(0) 
cv2.destroyAllWindows()

代码的运行结果如图8 所示。

图7 方形图 图8 掩膜式的逻辑与运算

因为掩膜的中央为逻辑 0,所以中间的一块全部被抠除了。接下来,我们来对星形图和心形图进行掩膜式的逻辑或和掩膜式的逻辑异或的运算,掩膜 式的逻辑或运算的代码如下。

代码语言:javascript复制
import cv2 
import numpy 
img1=cv2.imread('1.jpg',0) 
img2=cv2.imread('2.jpg',0) 
mask=cv2.imread('3.jpg',0) 
img=cv2.bitwise_or(img1,img2,mask=mask) 
cv2.imshow('img',img) 
cv2.waitKey(0) 
cv2.destroyAllWindows()

掩膜式的逻辑异或运算的代码如下。

代码语言:javascript复制
import cv2 
import numpy 
img1=cv2.imread('1.jpg',0) 
img2=cv2.imread('2.jpg',0) 
mask=cv2.imread('3.jpg',0) 
img=cv2.bitwise_xor(img1,img2,mask=mask) 
cv2.imshow('img',img) 
cv2.waitKey(0) 
cv2.destroyAllWindows()

两段代码的运行结果分别如图 9 与图 10所示。

掩膜主要运用在颜色追踪中,即指定追踪的颜色后,追踪指定颜色物体的运动。

注意:对于掩膜,建议使用二值图,因为它本身的含义为逻辑 0 和逻辑 1,分别对应着二 值图中的 0 和 255。

图 9 掩膜式的逻辑或运算 图 10 掩膜式的逻辑异或运算

本文节选自《 OpenCV图像处理入门与实践》,作者荣嘉祺,本文已获得人民邮电出版社转载授权。

0 人点赞