【Python/Opencv】图像加法函数:cv2.add()详解

【Python/Opencv】图像加法函数:cv2.add()详解

1. 介绍

图像加法主要有两种用途:

  • 一种是可用于减少甚至消除图像采集中混入的噪声,由于图像各点的采集噪声是互不相关的,且噪声具有零均值的统计特性,因此可以对图像进行多次采集形成多副图像,然后将这多副图像相加再取平均值,就可以实现噪点的消除;
  • 另一种是用来做特效,把多幅图像叠加在一起,再进一步进行处理。

Opencv的加运算就是两幅图像或一副图像和一个标量(标量即单一的数值)相加。

  • 对两副图像相加,要求两幅或多幅相加的图像的大小应该相同,处理时将两副图像相同位置的像素的灰度值(灰度图像)或彩色像素各通道值(彩色图像)分别相加;
  • 对一副图像和一个标量相加时,则将图像所有像素的各通道值分别与标量进行相加。

2. API

import cv2
out = cv2.add(src1, src2, dst=None, mask=None, dtype=None)
  • 参数说明

    • src1、src2:需要相加的两副大小和通道数相等的图像或一副图像和一个标量(标量即单一的数值)
    • dst:可选参数,输出结果保存的变量,默认值为None。
      • 如果为非None,输出图像保存到dst对应实参中,其大小和通道数与输入图像相同,图像的深度(即图像像素的位数)由dtype参数或输入图像确认
    • mask:图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0
    • dtype:可选参数,输出图像数组的深度,即图像单个像素值的位数(如RGB用三个字节表示,则为24位)。
  • 返回值

    • out:相加的结果图像

3. 三种用法

3.1 两个相同大小和通道数的图像相加

dst(I) = saturate(src1(I) + src2(I)) if mask(I)0

即目标图像的每个像素,在mask对应位置的值不为0的情况下,该像素每个通道的值等于src1和src2同样位置像素通道的值相加(饱和)。

3.2 一个图像数组和一个标量相加

dst(I) = saturate(src1(I) + src2) if mask(I)0

即目标图像的每个像素,在mask对应位置的值不为0的情况下,该像素每个通道的值等于src1图像的每个像素的每个通道值与标量各值相加(数字化的常量会转成一个代表BGRA的四元组,首元素为该数字值,其他元素为0;如果是四元组则分别相加。下同)。

3.3 一个标量和一个图像数组相加

dst(I)=saturate(src1 + src2(I)) if mask(I)0

即目标图像的每个像素,在mask对应位置的值不为0的情况下,该像素每个通道的值等于src2图像的每个像素的每个通道值与标量相加。

3.4 特殊情况

关于后面两种场景,在OpenCV的文档中,标量还可以用一个与另一个参数对应图像数组的通道数相等元素个数的变量(例如针对场景3,opencv是这样描述的:“Sum of a scalar and an array when src1 is constructed from Scalar or has the same number of elements as src2.channels()”)。

  • 针对三通道的图像,标量用一个三元组或三个元素的列表代替)行不通,
  • 经验证测试,发现换成一个四元组可以,如:
import cv2
import numpy as np

img = cv2.imread(r'a.jpg')
img1 = img[0:3, 0:3]
print(img1)

mask = np.zeros([3, 3], dtype=np.uint8)
d = cv2.add(img1, (1,1,1,1))
print(d)

输出如下

img1:
[[[240 240 240]
  [240 240 240]
  [241 241 241]]

 [[241 241 241]
  [241 241 241]
  [241 241 241]]

 [[241 241 241]
  [241 241 241]
  [241 241 241]]]

d:
[[[241 241 241]
  [241 241 241]
  [242 242 242]]

 [[242 242 242]
  [242 242 242]
  [242 242 242]]

 [[242 242 242]
  [242 242 242]
  [242 242 242]]]

可能的解释:OpenCV可能强制对彩色图像处理是四通道的。

4. 一些案例

4.1 加法中是否允许两个输入图像是否都为标量

>>>import numpy as np
>>>import cv2
>>>img = cv2.add(1,2)
>>> img
array([[3.],
       [0.],
       [0.],
       [0.]])
>>> img.shape
(4, 1)

解释:

  • 可以看到是允许二者都是标量,但输出结果是一个二维数组。为什么是四个元素呢,老猿认为是OpenCV强制将标量转为了BGRA四通道的分量进行处理导致的。

4.2 掩码的使用

>>> imgBeauty = cv2.imread(r'a.jpg')
>>> img = imgBeauty[0:5, 0:5]
>>> img
array([[[230, 225, 224],
        [230, 225, 224],
        [230, 225, 224],
        [229, 224, 223],
        [227, 222, 221]],

       [[231, 226, 225],
        [230, 225, 224],
        [230, 225, 224],
        [230, 225, 224],
        [229, 224, 223]],

       [[231, 226, 225],
        [231, 226, 225],
        [231, 226, 225],
        [231, 226, 225],
        [230, 225, 224]],

       [[230, 225, 224],
        [231, 226, 225],
        [231, 226, 225],
        [231, 226, 225],
        [230, 225, 224]],

       [[231, 226, 225],
        [232, 227, 226],
        [231, 226, 225],
        [231, 226, 225],
        [230, 225, 224]]], dtype=uint8)
>>> mask = np.zeros([5, 5], dtype=np.uint8)
>>> mask[1]=[1,0,-1,1,0]
>>> mask[2] = [-2, -1, 0, 1, 2]
>>> mask
array([[  0,   0,   0,   0,   0],
       [  1,   0, 255,   1,   0],
       [254, 255,   0,   1,   2],
       [  0,   0,   0,   0,   0],
       [  0,   0,   0,   0,   0]], dtype=uint8)
>>> dest = np.zeros([5, 5, 3], dtype=np.uint8)
>>> img2 = cv2.add(img, img, mask=mask, dst=dest)
>>> img2
array([[[  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]],

       [[255, 255, 255],
        [  0,   0,   0],
        [255, 255, 255],
        [255, 255, 255],
        [  0,   0,   0]],

       [[255, 255, 255],
        [255, 255, 255],
        [  0,   0,   0],
        [255, 255, 255],
        [255, 255, 255]],

       [[  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]],

       [[  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]]], dtype=uint8)
>>> img2 is dest
True

从上面执行的案例可以看到:

  • img和img自身相加后,带掩膜参数执行时,只有掩膜为不为0的像素值保留,其他值被置为0
  • 由于img每个像素的单通道的值比较大,导致img+img之后,每个通道的值被置为了255,即是饱和加法的结果
  • 加法的返回值就是dst参数指定的对象

4.3 加法算术表达式

对于上面介绍的加法场景中相同大小和通道数的两个图像数组相加处理,对于公式为:

dst(I)=saturate(src1(I)+src2(I))if mask(I)0

opencv文档中介绍上面函数可以使用矩阵表达式进行替换,替换的矩阵表达式如下:

dst = src1 + src2

结果发现:

  • opencv-python执行该加法时是纯粹的矩阵运算,没有执行opencv-python的add加法,
  • 因为加法结果未执行饱和加法。因此该说法至少在opencv-python中不正确,在opencv-python中要执行图像加法还是调用add函数执行。

5. 图像加法举例(效果展示)

第一张图像为:a.jpg
请添加图片描述
第二张图像为:b.jpg
在这里插入图片描述

5.1 代码

import numpy as np
import cv2
img1 = cv2.imread(r'a.jpg')
img2 = cv2.imread(r'b.jpg')

img1 = cv2.resize(img1, (300, 450))
img2 = cv2.resize(img2, (300, 450))

print(img1.shape,img2.shape)
mask = np.zeros(img1.shape[0:2], dtype=np.uint8)
mask[0:100,0:100] = 1
imgNomask = cv2.add(img1, img2)
imgMask = cv2.add(img1, img2,mask=mask)
cv2.imwrite('imgNomask.jpg', imgNomask)
cv2.imwrite('imgMask.jpg', imgMask)

5.2 效果

  • 没有掩码:imgNomask.jpg
    在这里插入图片描述
  • 有掩码:imgMask.jpg
    在这里插入图片描述

6. 参考

【1】https://blog.csdn.net/LaoYuanPython/article/details/109016144

猜你喜欢

转载自blog.csdn.net/qq_51392112/article/details/129599644