2.2. 图像的算术运算

2.2.1. 目标

  • 学习一些图像上的算术运算,如加法、减法、按位运算等。

  • 你将学习以下功能: cv2.add()cv2.addWeighted() 等。

2.2.2. 图像加法

你可以通过OpenCV函数 cv2.add()``将两个图像相加, 或者仅仅通过这样的numpy操作,``res = img1 + img2 。 这要求两幅图像的深度和类型应该相同,或者第二幅图像只能是标量值。

Note

OpenCV加法和Numpy加法有区别。OpenCV加法是饱和运算,Numpy加法是模运算。

例如,考虑以下示例:

>>> import cv2
>>> import numpy as np
>>>
>>> x = np.uint8([250])
>>> y = np.uint8([10])
>>> cv2.add(x,y) # 250+10 = 260 => 255
array([[255]], dtype=uint8)
>>> x+y          # 250+10 = 260 % 256 = 4
array([4], dtype=uint8)

当你做两个图像的加法时,这区别会更加明显。OpenCV函数将提供更好的结果。所以最好还是使用OpenCV函数。

2.2.3. 图像混合

这也是图像的加法,但是给图像赋予了不同的权重,从而给人一种混合或透明的感觉。图像按以下公式进行相加:

\[g(x)=(1-alpha)f{0}(x)+alpha f{1}(x)\]

通过在 \(0 \rightarrow 1\) 范围内改变 :math:`alpha`的取值,可以实现一个图像到另一个图像的冷转换。

在这里我将两张图像混合在一起。第一个图像的权重为0.7,第二个图像的权重为0.3。 cv2.addWeighted() 应用以下公式于图像上。

\[dst=alphacdot img1+betacdot img2+gamma\]

在这里 \(\gamma\) 取为零。

>>> img1 = cv2.imread('/cvdata/ml.png')
>>> img2 = cv2.imread('/cvdata/opencv_logo.png')
>>> import cv2 as cv
>>> img1 = cv.imread('/cvdata/ml.png')
>>> img2 = cv.imread('/cvdata/opencv-logo.png')
>>> img1.shape
(380, 308, 3)
>>> img2.shape
(739, 600, 3)
>>> dst = cv.addWeighted(img1,0.3,img1,0.3,0)
>>> %matplotlib inline
>>>
>>> import  matplotlib.pyplot as plt
>>> plt.imshow(dst)
<matplotlib.image.AxesImage at 0x7ff98cf73748>
../_images/sec02-image-arithmetics_14_1.png
>>> # dst = cv2.addWeighted(img1,0.3,img2,0.3,8)
>>> # plt.imshow(dst)
>>> # cv2.imshow('dst',dst)
>>> # cv2.waitKey(0)
>>> # cv2.destroyAllWindows()

检查以下结果:

2.2.4. 按位运算

这包括按位“AND”、“OR”、“NOT”和“XOR”操作。它们在提取图像的任何部分(我们将在接下来的章节中看到)、定义和使用非矩形ROI等时将非常有用。下面我们将看到一个关于如何更改图像特定区域的示例。

我想把OpenCV的标志放在图片上方。如果我添加两个图像,它将改变颜色。如果我混合它,我得到一个透明的效果。但我希望它是不透明的。如果是矩形区域,我可以像上一章那样使用ROI。但是OpenCV的标志不是矩形的。因此,你可以按如下方式执行按位操作:

>>> # Load two images
>>>
>>> # img1 = cv.imread('messi5.jpg')
>>> # img2 = cv.imread('opencv-logo-white.png')
>>>
>>> img1 = cv2.imread('/cvdata/messi5.jpg')
>>> img2 = cv2.imread('/cvdata/opencv-logo-white.png')
>>>
>>>
>>> # I want to put logo on top-left corner, So I create a ROI
>>> rows,cols,channels = img2.shape
>>> roi = img1[0:rows, 0:cols ]
>>>
>>> # Now create a mask of logo and create its inverse mask also
>>> img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
>>> ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
>>> mask_inv = cv2.bitwise_not(mask)
>>>
>>> # Now black-out the area of logo in ROI
>>> img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
>>>
>>> # Take only region of logo from logo image.
>>> img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
>>>
>>> # Put logo in ROI and modify the main image
>>> dst = cv2.add(img1_bg,img2_fg)
>>> img1[0:rows, 0:cols ] = dst
>>> plt.imshow(img1)
<matplotlib.image.AxesImage at 0x7ff98cf0fbe0>
../_images/sec02-image-arithmetics_21_1.png
>>> cv2.imwrite('xx_a.jpg', img1)
True

image0

>>> from IPython.display import Image
>>> Image('/cvdata/opencv-logo-white.png')
../_images/sec02-image-arithmetics_26_0.png
>>> # cv2.imshow('res',img1)
>>> # cv2.waitKey(0)
>>> # cv2.destroyAllWindows()

见下面的结果。左图显示了我们创建的遮罩。右图显示了最终结果。为了更好的理解,请显示上面的代码中产生的所有中间图像,特别是 img1_bgimg2_fg .

2.2.5. 额外资源

2.2.6. 练习

  1. 使用 cv2.addWeighted 函数在文件夹中创建图像的幻灯片放映