本章将学习如下内容:
- 学习图像上的几种算术运算,如加法、减法、位运算等。
- 介绍如下函数:
cv2.add()
、cv2.addWeighted()
等。
图像相加
可以通过OpenCV函数cv2.add()
或简单地通过numpy操作res=img1+img2
将两个图像相加。
两个图像的深度和类型应该相同,或者第二个图像只能是标量值。
OpenCV加法和Numpy加法对溢出情况处理方式存在差异。OpenCV加法是饱和运算,而Numpy加法是模运算。
OpenCV加法(cv2.add)是一种饱和运算(saturate arithmetic),即当两个数相加超过了数据类型的范围时,将结果截断到最大值或最小值处。例如,对于无符号8位整型数据类型(uint8),最大值为255,最小值为0。如果进行255+10的运算,OpenCV会将结果截断到255处。
Numpy加法(np.add)是一种模运算(modulo arithmetic),即当两个数相加超过了数据类型的范围时,将结果对数据类型的范围取模。例如,对于无符号8位整型数据类型(uint8),最大值为255,最小值为0。如果进行255+10的运算,Numpy会将结果对256取模,并返回265%256=9的结果。
因此,在使用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([[260.], [ 0.], [ 0.], [ 0.]])
x+y # 250+10 = 260 % 256 = 4
array([4], dtype=uint8)
当添加两张图片时,它会更明显。OpenCV函数将提供更好的结果。所以最好还是坚持使用OpenCV函数。
图像融合
这也是图像添加,但对图像赋予了不同的权重,使其给人一种混合或透明的感觉。图像按照以下方程式添加:
$$g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x)$$
通过从 $0 \rightarrow 1$B 更改为 $\alpha$ , 可以在一个图像到另一个图像之间进行很酷的转换。
在这里把两张图像融合在一起。第一图像被赋予0.7的权重,第二图像被赋予0.3的权重,
cv2.addWeighted()
在图像上应用以下方程式:
$$dst = \alpha \cdot img1 + \beta \cdot img2 + \gamma$$
这里 $\gamma$ 取零。
img1 = cv2.imread('/data/cvdata/ml.png')
img2 = cv2.imread('/data/cvdata/opencv-logo.png')
import cv2 as cv
img1 = cv.imread('/data/cvdata/ml.png')
img2 = cv.imread('/data/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 0x7fa2dfaa8b60>
# dst = cv2.addWeighted(img1,0.3,img2,0.3,8)
# plt.imshow(dst)
# cv2.imshow('dst',dst)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
加载两张图像。
# img1 = cv.imread('messi5.jpg')
# img2 = cv.imread('opencv-logo-white.png')
img1 = cv2.imread('/data/cvdata/messi5.jpg')
img2 = cv2.imread('/data/cvdata/opencv-logo-white.png')
我想把 logo 放在左上角,所以创建了一个 ROI(感兴趣区域)。
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
生成 logo 的掩膜及其反向掩膜。
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
对 ROI 内的 logo 区域进行黑化处理。
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
截取 logo 图像中的 logo 区域。
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
将 logo 叠加到 ROI 区域,并对主图进行修改。
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
plt.imshow(img1)
<matplotlib.image.AxesImage at 0x7f9282a62ba0>
cv2.imwrite('xx_a.jpg', img1)
True
from IPython.display import Image
Image('/data/cvdata/opencv-logo-white.png')
# cv2.imshow('res',img1)
# cv2.waitKey(0)
# cv2.destroyAllWindows()