OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
无匹配项
图像的算术运算

目标

  • 学习图像的几种算术运算,例如加法、减法、位运算等。
  • 学习以下函数:cv.add()cv.addWeighted() 等。

图像加法

可以使用 OpenCV 函数 cv.add() 或简单的 NumPy 运算 res = img1 + img2 来添加两幅图像。两幅图像应具有相同的深度和类型,或者第二幅图像可以只是一个标量值。

注意
OpenCV 加法和 NumPy 加法之间存在差异。OpenCV 加法是饱和运算,而 NumPy 加法是模运算。

例如,考虑以下示例

>>> x = np.uint8([250])
>>> y = np.uint8([10])
>>> print( cv.add(x,y) ) # 250+10 = 260 => 255
[[255]]
>>> print( x+y ) # 250+10 = 260 % 256 = 4
[4]
void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1)
计算两个数组或一个数组和一个标量的逐元素和。

当您添加两幅图像时,这将更加明显。坚持使用 OpenCV 函数,因为它们会提供更好的结果。

图像混合

这也是图像加法,但是为了产生混合或透明感,会赋予图像不同的权重。图像根据以下等式相加

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

通过将 \(\alpha\) 从 \(0 \rightarrow 1\) 进行变化,您可以在一幅图像和另一幅图像之间执行很酷的过渡。

在这里,我取了两幅图像进行混合。第一幅图像的权重为 0.7,第二幅图像的权重为 0.3。cv.addWeighted() 将以下等式应用于图像

\[dst = \alpha \cdot img1 + \beta \cdot img2 + \gamma\]

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

img1 = cv.imread('ml.png')
img2 = cv.imread('opencv-logo.png')
assert img1 is not None, "文件无法读取,请使用 os.path.exists() 检查"
assert img2 is not None, "文件无法读取,请使用 os.path.exists() 检查"
dst = cv.addWeighted(img1,0.7,img2,0.3,0)
cv.imshow('dst',dst)
void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1)
计算两个数组的加权和。
void imshow(const String &winname, InputArray mat)
在指定的窗口中显示图像。
int waitKey(int delay=0)
等待按下按键。
void destroyAllWindows()
销毁所有 HighGUI 窗口。
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
从文件中加载图像。

查看下面的结果

图像

位运算

这包括按位与、按位或、按位非和按位异或运算。在提取图像的任何部分(正如我们将在接下来的章节中看到的那样)、定义和使用非矩形 ROI 等方面,它们将非常有用。下面我们将看到如何更改图像的特定区域。

我想将 OpenCV 徽标放在图像上方。如果我添加两幅图像,它会改变颜色。如果我混合它们,我会得到透明效果。但我希望它是清晰的。如果这是一个矩形区域,我可以像在上一章中那样使用 ROI。但是 OpenCV 徽标不是矩形。因此,您可以使用如下所示的位运算来实现它

# 加载两幅图像
img1 = cv.imread('messi5.jpg')
img2 = cv.imread('opencv-logo-white.png')
assert img1 is not None, "文件无法读取,请使用 os.path.exists() 检查"
assert img2 is not None, "文件无法读取,请使用 os.path.exists() 检查"
# 我想把徽标放在左上角,所以我创建一个 ROI
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols]
# 现在创建徽标的掩码,并创建其反掩码
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)
void bitwise_not(InputArray src, OutputArray dst, InputArray mask=noArray())
反转数组的每一位。
void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray())
计算两个数组的按位与运算 (dst = src1 & src2) 计算逐元素按位…
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
将图像从一个颜色空间转换为另一个颜色空间。
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
将固定级别的阈值应用于每个数组元素。

查看下面的结果。左图显示我们创建的掩码。右图显示最终结果。为了更好地理解,请在上面的代码中显示所有中间图像,尤其是 img1_bg 和 img2_fg。

图像

练习

  1. 使用cv.addWeighted 函数创建一个文件夹中图像的幻灯片放映,图像之间平滑过渡。