文章目录
加法运算、位运算是图像的基础运算,但它们是很多复杂图像处理功能的基础。
一.图像加法运算
图像加法运算有两种方式:
- “+”加号运算符
- cv2.add() 函数
像素用 8 个比特位来表示,范围是 [0, 255]。两个像素在相加时的和可能超过 255,上面两种方法对超过 255 的值处理方式不一样。
1.加号运算符
(1).求和规则
设有图像 a 和 图像 b 进行像素求和,加号运算符求和规则如下:
a
+
b
=
m
o
d
(
a
+
b
,
256
)
a+b=mod(a+b,256)
a+b=mod(a+b,256)
m
o
d
(
a
,
b
)
mod(a,b)
mod(a,b) 表示 a 除以 b 取余数。
(2).示例
import numpy as np
a = np.random.randint(0,255,(2,3),np.uint8)
b = np.random.randint(0,255,(2,3),np.uint8)
print("a=:\n",a)
print("b=:\n",b)
print("a+b=:\n",a+b)
'''结果如下
a=:
[[ 90 118 221]
[113 18 251]]
b=:
[[203 145 74]
[ 78 168 88]]
a+b=:
[[ 37 7 39]
[191 186 83]]
'''
2.cv2.add() 函数
(1).求和规则
设有图像 a 和 图像 b 进行像素求和,cv2.add() 函数求和规则如下:
a
+
b
=
{
a
+
b
,
a
+
b
≤
255
255
,
a
+
b
>
255
a+b= \begin{cases} a+b,&a+b\leq255\\ 255,&a+b>255 \end{cases}
a+b={a+b,255,a+b≤255a+b>255
(2).相关函数
dst = cv2.add(src1, src2[, dst[, mask[, dtype]]])
:
- src1:图像或数值
- src2:图像或数值
- dst:返回的目标值
注意:当 src1 和 src2 都是图像时,图像的大小和类型要保持一致
(3).示例
import cv2
import numpy as np
a = np.random.randint(0,255,(2,3),np.uint8)
b = np.random.randint(0,255,(2,3),np.uint8)
print("a=:\n",a)
print("b=:\n",b)
c1 = cv2.add(a,b)
c2 = cv2.add(a,200)
c3 = cv2.add(200,b)
print("a+b=:\n",c1)
print("a+200=:\n",c2)
print("b+200=:\n",c3)
'''结果如下
a=:
[[140 101 189]
[182 80 223]]
b=:
[[169 228 2]
[183 109 186]]
a+b=:
[[255 255 191]
[255 189 255]]
a+20=:
[[255 255 255]
[255 255 255]]
b+20=:
[[255 255 202]
[255 255 255]]
'''
3.图像相加
import cv2
a = cv2.imread('dog.jpg')
b = a
c1 = a+b
c2 = cv2.add(a,b)
cv2.imshow('a',a)
cv2.imshow('a+b',c1)
cv2.imshow('cv2.add(a+b)',c2)
cv2.waitKey()
cv2.destroyAllWindows()
结果如下图所示,从左到右依次是 ‘a’、‘a+b’、‘cv2.add(a+b)’ 窗口:
由于 cv2.add
采用的是饱和形式,所以第三张图明显亮度会提高。
二.图像加权和
1.加权和规则
图像加权和,就是在图像的像素求和的时候,把每幅图像的权重考虑进来,计算公式为:
d
s
t
=
s
a
t
u
r
a
t
e
(
s
r
c
1
×
α
+
s
r
c
2
×
β
+
γ
)
dst=saturate(src1\times\alpha+src2\times\beta+\gamma)
dst=saturate(src1×α+src2×β+γ)其中,
s
a
t
u
r
a
t
e
(
)
saturate()
saturate() 表示取饱和值,
α
,
β
\alpha,\beta
α,β 表示图像权重,
γ
\gamma
γ 可以理解为亮度调节。
2.相关函数
dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
- src1:图像1
- src2:图像2
- alpha:图像1权重
- beta:图像2权重
- gamma:亮度调节
- dst:返回的图像
注意:图像的大小和类型要相同
3.示例
import cv2
dog = cv2.imread('dog.jpg')
cat = cv2.imread('cat.jpg')
c = cv2.addWeighted(dog,0.7,cat,0.3,10)
cv2.imshow('dog', dog)
cv2.imshow('cat', cat)
cv2.imshow('addWeighted', c)
cv2.waitKey()
cv2.destroyAllWindows()
结果如下图所示,从左到右依次是 ‘dog’、‘cat’、‘addWeighted’ 窗口:
三.按位逻辑运算
1.按位与运算
与运算的规则是,当参与两个运算的两个逻辑值都为真时,结果才为真,一般用 0 表示假,用 1 表示真。
(1).相关函数
dst=cv2.bitwise_and(src1, src2[, dst[, mask]])
- src1:第一个图像 array 或 数值 scalar
- src2:第二个图像 array 或 数值 scalar
- mask:可选操作掩码,8 位单通道 array
- dst:返回的结果
(2).示例
由于任何数与 ‘0’ 求与都得0,任何数与 ‘1’ 求与都得本身,所以我们可以构建两个不同的 src2,来保留图像的特定部分,注意在 8 比特位的图像中,前边提到的 ‘1’ 对应的像素值为 255。
import cv2
import numpy as np
dog = cv2.imread('dog.jpg')
a = np.zeros(dog.shape,dtype=np.uint8)
a[100:400,100:400]=255
res = cv2.bitwise_and(dog,a)
cv2.imshow('dog',dog)
cv2.imshow('a',a)
cv2.imshow('res',res)
cv2.waitKey()
cv2.destroyAllWindows()
由于 ‘a’ 本身是一个 0 矩阵,但是在其 [100:400,100:400] 部分(狗头部分)的值为 255,所以经过按位与运算以后,图像只保留了狗头部分,而其他部分的像素值都为 0。
2.按位或运算
或运算的规则是,当参与运算的两个逻辑值有一个为真时,结果就为真。
相关函数
dst=cv2.bitwise_or(src1, src2[, dst[, mask]])
- src1:第一个图像 array 或 数值 scalar
- src2:第二个图像 array 或 数值 scalar
- mask:可选操作掩码,8 位单通道 array
- dst:返回的结果
3.按位非运算
非运算的规则是其实是取反操作:
- 当运算逻辑数为真,结果为假
- 当运算逻辑数为假,结果为真
相关函数
dst=cv2.bitwise_not(src, [, dst[, mask]])
- src:array
- mask:可选操作掩码,8 位单通道 array
- dst:返回的结果
4.按位异或运算
异或运算的规则与不带进位的二进制加法类似,如果用 x o r xor xor 来表示异或,那么它的规则如下:
- x o r ( 0 , 0 ) = 0 xor(0,0)=0 xor(0,0)=0
- x o r ( 0 , 1 ) = 1 xor(0,1)=1 xor(0,1)=1
- x o r ( 1 , 0 ) = 1 xor(1,0)=1 xor(1,0)=1
- x o r ( 1 , 1 ) = 0 xor(1,1)=0 xor(1,1)=0
相关函数
dst=cv2.bitwise_xor(src1, src2[, dst[, mask]])
- src1:第一个图像 array 或 数值 scalar
- src2:第二个图像 array 或 数值 scalar
- mask:可选操作掩码,8 位单通道 array
- dst:返回的结果
四.掩码
在上面的内容中,多次提到了一个参数 mask ,它叫掩码,又称作掩模。当函数中有掩码参数时,函数操作只会在掩码值非空的像素点上执行,并将其他像素点的值置为 0。
示例:
dog = cv2.imread('dog.jpg')
w,h,c= dog.shape
mask = np.zeros((w,h),dtype=np.uint8)
mask[100:400,100:400]=255
# 注意 bitwise_and(a,a)的结果仍然是其本身
dog2 = cv2.bitwise_and(dog,dog,mask=mask)
cv2.imshow('dog',dog)
cv2.imshow('mask',mask)
cv2.imshow('dog2',dog2)
cv2.waitKey()
cv2.destroyAllWindows()
在没有 mask 掩码时,‘dog’ 与 ‘dog’ 按位与运算的结果仍然是自己本身,现在假如有 mask 时,cv2.bitwise_and(dog,dog,mask=mask)
只会对 mask 不为 0 的部分进行按位与运算操作,而mask[100:400,100:400]=255 被设置成了狗头部分不为0,所以结果会和 三.1 中示例的结果相同: