OpenCV-Python教程:图像的减法运算、标量加减运算(subtract、absdiff)

返回Opencv-Python教程

原文链接:http://www.juzicode.com/archives/5853

OpenCV-Python教程:图像的加法运算 一文中介绍了对图像进行加法运算的方法,我们知道add和addWeighted都是一种饱和运算,如果直接结算结果超过该数据类型所表示的最大值,将会在最大值被截断,比如uint8类型的数据,如果直接计算结果大于255,则会被截断到255。同样地,减法运算的subtract()也遵循“饱和运算”规则,如果2个图像相减直接计算结果小于0,也会被截断到255。

图像的减法运算的一个应用场景是比较2幅图像的差异,比如判断前后2个时间点的图像是否发生了变化,在用你的邮箱为你看家护院 一文中有一个关于subtract()的应用例子。

1、图像相减subtract()

2个图像相减仍然要求通道数一样,图像尺寸一样。

下面的例子分别读取lena.jpg和opencv-logo.png,因为默认方式读取得到的图像都是3通道,然后截取行列大小一样的部分图像,再用subtract()方法将2个图像相减:

import cv2
print('VX公众号: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)

img = cv2.imread('..\\lena.jpg')[0:512,0:512] #截取部分,保证大小一致
img2 = cv2.imread('..\\opencv-logo.png' )[0:512,0:512]
img3 = cv2.subtract(img,img2)
print('img[161,199]:',img[161,199])
print('img2[161,199]:',img2[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('subtract(img,img2)',img3)

img3 = cv2.subtract(img2,img)
print('img2[161,199]:',img2[161,199])
print('img[161,199]:',img[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('subtract(img2,img)',img3)

cv2.waitKey(0)

运行结果:

VX公众号: 桔子code / juzicode.com
cv2.__version__: 4.5.2
img[161,199]: [109 105 201]
img2[161,199]: [  0   0 255]
img3[161,199]: [109 105   0]

img2[161,199]: [  0   0 255]
img[161,199]: [109 105 201]
img3[161,199]: [ 0  0 54]

从运行结果看,2个图像相减,如果直接计算的结果小于0,也会被截断到0,不会出现负数值,比如上面例子中img-img2得到的新图像其像素点[161,199]的R通道相减后结果小于0,实际得到的结果为0。从img-img2得到的新图像也可以看到opencv-logo.png白色区域作用到lena.jpg上后显示的为黑色。

2、图像相减 运算符-

 也可以通过符号 – 的方法将2个图像相减:

import cv2
print('VX公众号: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)

img = cv2.imread('..\\lena.jpg')[0:512,0:512] #截取部分,保证大小一致
img2 = cv2.imread('..\\opencv-logo.png' )[0:512,0:512]
img3 = img-img2
print('img[161,199]:',img[161,199])
print('img2[161,199]:',img2[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('img-img2',img3)

img4 = img2 - img
print('img2[161,199]:',img2[161,199])
print('img[161,199]:',img[161,199])
print('img4[161,199]:',img4[161,199])
cv2.imshow('img2 - img',img4)
cv2.waitKey(0)

运行结果:

VX公众号: 桔子code / juzicode.com
cv2.__version__: 4.5.2
img[161,199]: [109 105 201]
img2[161,199]: [  0   0 255]
img3[161,199]: [109 105 202]
img2[161,199]: [  0   0 255]
img[161,199]: [109 105 201]
img4[161,199]: [147 151  54]

2个图像用符号-相减,如果直接计算的结果小于0,得到的结果不会出现负数,而是在这个负数的基础上加上256,比如0-109=-109,实际的像素值则为-109+256=147,和符号+运算一样也是对256求模的结果。

 

3、绝对值减法absdiff()

而不是像subtract()和符号-减法那样做饱和运算或者求模,absdiff()得到的是2个图像间像素的绝对差值。

下面这个例子将lena.jpg和opencv-logo.png做绝对值减法:

import cv2
print('VX公众号: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)

img = cv2.imread('..\\lena.jpg')[0:512,0:512] #截取部分,保证大小一致
img2 = cv2.imread('..\\opencv-logo.png' )[0:512,0:512]

print('img3 = cv2.absdiff(img,img2):')
img3 = cv2.absdiff(img,img2)
print('img[161,199]:',img[161,199])
print('img2[161,199]:',img2[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('absdiff(img,img2)',img3)

print('img3 = cv2.absdiff(img2,img):')
img3 = cv2.absdiff(img2,img)
print('img2[161,199]:',img2[161,199])
print('img[161,199]:',img[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('absdiff(img2,img)',img3)

cv2.waitKey(0)

运行结果:

VX公众号: 桔子code / juzicode.com
cv2.__version__: 4.5.2
img3 = cv2.absdiff(img,img2):
img[161,199]: [109 105 201]
img2[161,199]: [  0   0 255]
img3[161,199]: [109 105  54]
img3 = cv2.absdiff(img2,img):
img2[161,199]: [  0   0 255]
img[161,199]: [109 105 201]
img3[161,199]: [109 105  54]

 从像素值的运行结果看,二者对调减数和被减数时效果是一样的,从图像效果看也是如此:

4、图像和标量加减

图像除了和图像进行加减外,还可以和一个标量值进行加减,图像之间的加减运算可以看成是2个向量之间的加减,将相同下标之间的元素值进行加减运算,如果和标量进行加减,则是将图像的每一个元素都和这个标量值进行加减。

当标量值只是1个数值时,只会对多通道图像的第1个通道进行运算,如果要进行多通道运算,标量值则使用一个包含4个数值的元组表示,即使是3通道的彩色图像也要用4元组表示这个标量值。下面这个例子对图像进行第1通道和3个通道的加减运算:

import cv2
print('VX公众号: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)

img = cv2.imread('..\\lena.jpg')[0:512,0:512] #截取部分,保证大小一致 
print(img.shape)

print('add(img,50)')
img3 = cv2.add(img,50)#第1通道加一个标量值
print('img[161,199]:',img[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('add(img,50)',img3)

print('add(img,(50,50,50,0))')
img3 = cv2.add(img,(50,50,50,0))#3个通道加一个标量值
print('img[161,199]:',img[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('add(img,(50,50,50,0))',img3)

print('subtract(img,50)')
img3 = cv2.subtract(img,50)#第1通道减一个标量值
print('img[161,199]:',img[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('subtract(img,50)',img3) 

print('subtract(img,(50,50,50,0))')
img3 = cv2.subtract(img,(50,50,50,0))#3个通道减一个标量值
print('img[161,199]:',img[161,199])
print('img3[161,199]:',img3[161,199])
cv2.imshow('subtract(img,(50,50,50,0))',img3)

cv2.waitKey(0)

运行结果:

VX公众号: 桔子code / juzicode.com
cv2.__version__: 4.5.2
(512, 512, 3)
add(img,50)
img[161,199]: [109 105 201]
img3[161,199]: [159 105 201]

add(img,(50,50,50,0))
img[161,199]: [109 105 201]
img3[161,199]: [159 155 251]

subtract(img,50)
img[161,199]: [109 105 201]
img3[161,199]: [ 59 105 201]

subtract(img,(50,50,50,0))
img[161,199]: [109 105 201]
img3[161,199]: [ 59  55 151]

第1通道和所有3个通道加一个标量值的对比:

第1通道和所有3个通道减一个标量值的对比:

从上面加减标量值的4幅图像看,可以观察到明显的亮度差异,3通道都加标量值的图片最亮,3通道都减标量值的图像最暗。

小结:subtract()做图像减法同样遵循“饱和运算”规则,直接计算结果小于0时被截断到0。和符号+计算一样,如果2个图像直接用运算符-进行计算,实际是按照numpy数组计算,最终是对256求模计算后的结果;absdiff()能从绝对值差异的角度反映2个图像之间的差异。图像和标量加减运算时,多通道的标量值用一个4元组表示。

 

扩展阅读:

  1. OpenCV-Python教程
  2. OpenCV-Python教程:图像的加法运算

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注