# 图像的算术运算

## 目标

* 学习对图像的几种算术运算，如加法，减法，按位运算等。
* 您将学习以下函数：[cv.add()](https://docs.opencv.org/4.0.0/d2/de8/group__core__array.html#ga10ac1bfb180e2cfda1701d06c24fdbd6)，[cv.addWeighted()](https://docs.opencv.org/4.0.0/d2/de8/group__core__array.html#gafafb2513349db3bcff51f54ee5592a19)等。

## 图像加法

您可以通过 OpenCV 函数，[cv.add()](https://docs.opencv.org/4.0.0/d2/de8/group__core__array.html#ga10ac1bfb180e2cfda1701d06c24fdbd6)或简单地通过 numpy 操作将两个图像相加，res = img1 + img2。两个图像应该具有相同的深度和类型，或者第二个图像可以是像素值，比如(255,255,255)，白色值。

> **注意**
OpenCV 相加操作和 Numpy 相加操作之间存在差异。OpenCV 添加是饱和操作，而 Numpy 添加是模运算。要注意的是，两种加法对于结果溢出的数据，会通过某种方法使其在限定的数据范围内。

例如，请考虑以下示例：

```python
>>> x = np.uint8([250])
>>> y = np.uint8([10])

>>> print(cv.add(x,y)) #250 + 10 =260 => 255
[[255]]

>>> print(x + y)
[4]
```
在将两个图象相加时会发现 OpenCV 函数能够提供更好的结果，所以尽可能地选择 OpenCV 函数。
## 图像混合

这也是将图像相加，但是对图像赋予不同的权重，从而给出混合感或透明感。图像按以下等式添加：

<div align=center>
<img src="img/blending_equation.gif">
</div>

通过在(0,1)之间改变![](https://github.com/zhangqizky/opencv-doc-zh/blob/master/docs/4.0.0/img/alpha.gif)的值, 可以用来对两幅图像或两段视频产生时间上的 *画面叠化* （cross-dissolve）效果，就像在幻灯片放映和电影制作中那样（很酷吧?)（译者注：在幻灯片翻页时可以设置为前后页缓慢过渡以产生叠加效果，电影中经常在情节过渡时出现画面叠加效果）。

在这里，我拍了两张图片将它们混合在一起。第一图像的权重为 0.7，第二图像的权重为 0.3。[cv.addWeighted()](https://docs.opencv.org/4.0.0/d2/de8/group__core__array.html#gafafb2513349db3bcff51f54ee5592a19)在图像上应用以下等式。

<div align=center>
<img src="img/blending_equation.gif">
</div>

```Python
img1= cv.imread('ml.png')
img2= cv.imread('opencv-logo.png')

dst = cv.addWeighted(img1,0.7,img2,0.3,0)

cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()
```
观察以下结果：

<div align=center>
<img src="img/blending.jpg">
</div>


## 按位操作

这包括按位 AND，OR，NOT 和 XOR 运算。它们在提取图像的某一部分（我们将在后面的章节中看到）、定义和使用非矩形 ROI 等方面非常有用。下面我们将看到如何更改图像的特定区域的示例：

假如我想加一个OpenCV的 logo在一个图像上，如果只是简单的将两张图像想加，则会改变叠加处的颜色。如果进行上面所说的混叠操作，则会得到一个有透明效应的结果，但我希望得到一个不透明的logo。如果logo是一个矩形logo，那可以用上节所讲的ROI来做。但是OpenCV的logo是不规则形状的，所以用下面的bitwise操作来进行。

```python
#加载两张图片
img1 = cv.imread（'messi5.jpg'）
img2 = cv.imread（'opencv-logo-white.png'）
#我想在左上角放置一个logo，所以我创建了一个 ROI,并且这个ROI的宽和高为我想放置的logo的宽和高
rows，cols，channels = img2.shape
roi = img1 [0：rows，0：cols]
#现在创建一个logo的掩码，通过对logo图像进行阈值，并对阈值结果并创建其反转掩码
img2gray = cv.cvtColor（img2，cv.COLOR_BGR2GRAY）
ret，mask = cv.threshold（img2gray，10,255，cv.THRESH_BINARY）
mask_inv = cv.bitwise_not（mask）
#现在使 ROI 中的徽标区域变黑
img1_bg = cv.bitwise_and（roi，roi，mask = mask_inv）
#仅从徽标图像中获取徽标区域。
img2_fg = cv.bitwise_and（img2，img2，mask = mask）
#在 ROI 中放置徽标并修改主图像
dst = cv.add（img1_bg，img2_fg）
img1 [0：rows，0：cols] = dst
cv.imshow（'res'，img1）
cv.waitKey（0）
cv.destroyAllWindows（）
```

请参阅下面的结果。左图显示了我们创建的蒙版。右图显示最终结果。为了加深理解，请在上面的代码中显示所有中间图像，尤其是 img1_bg 和 img2_fg。
<div align=center>
<img src="img/overlay.jpg">
</div>

## 其他资源
## 练习
1. 使用[cv.addWeighted()](https://docs.opencv.org/4.0.0/d2/de8/group__core__array.html#gafafb2513349db3bcff51f54ee5592a19)函数在文件夹中创建图像之间平滑过渡的幻灯片并放映。
