OpenCV  4.10.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')
断言 img1 None"文件无法读取,请使用 os.path.exists() 核查"
断言 img2 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)
从文件中加载图像。

请查看以下结果

图像

位操作

包含位与、位或、非、和异或操作。在提取图像任意部分时(如我们将在接下来的章节中看到的那样)定义和使用非矩形 ROI 等时,这些操作将非常有用。下面我们将会看到如何更改图像的特定区域。

我想将 OpenCV 徽标放在图像上方。如果我添加两幅图像,其颜色就会发生变化。如果将它们混合,则会产生透明效果。但我希望它是 непрозрачный。如果它是矩形区域,我可以像上一章中所做的那样使用 ROI。但 OpenCV 徽标并不是矩形。因此,您可以使用位操作执行此操作,如下所示

# 加载两幅图像
img1 = cv.imread('messi5.jpg')
img2 = cv.imread('opencv-logo-white.png')
断言 img1 None"文件无法读取,请使用 os.path.exists() 核查"
断言 img2 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)
将图像从一个色彩空间转换为另一个色彩空间。
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
对每个元素应用一个固定级别的阈值。

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

图像

其他资源

习题

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