基于python的opencv快速入门——图像运算
太原理工机器人团队20日打卡day15
1、图像加法运算
- 图像加法运算分为两种
- 加号运算符
- cv2.add()函数
加号运算符
- 加号运算符遵循以下规则
- 如果两个图像对应像素和小于255,取相加值
- 如果两个图像像素值的和大于255,取对于256的模
cv2.add()函数
- cv2.add()的函数满足以下规则
- 两个图像对应像素和小于255,取相加值
- 如果两个图像像素值的和大于255,取255
- 语法为
计算结果 = cv2.add(像素值a,像素值b)
Notes:
- cv2.add()的参数有可能有以下3种情况
- 计算结果 = cv2.add(图像1,图像2)
- 两个参数都是图像
- 此时参与运算的图像大小和类型必须保持一致
- 计算结果 = cv2.add(数值,图像)
- 第一个参数是数值,第二个参数是图像
- 此时将超过图像饱和值的数值处理为饱和值(最大值)
- 计算结果 = cv2.add(图像,数值)
- 第一个参数是图像,第二个参数是数值
- 此时将超过图像饱和值的数值处理为饱和值(最大值)
import cv2
a = cv2.imread("Second.jpg")
b = a
result1 = a+b
result2 = cv2.add(a,b)
cv2.imshow("original",a)
cv2.imshow("result1",result1)
cv2.imshow("result2",result2)
cv2.waitKey()
cv2.destroyAllWindows()
- 从上述运算结果可以看出
- 使用加号运算符计算图像像素值的和时,将和大于255的值进行了取模处理,取模后大于255的这部分值变得更小了,导致本来应该更亮的像素点变得更暗了,相加所得的图像看起来并不自然。
- 使用函数cv2.add()计算图像像素值的和时,将和大于255的值处理为饱和值255。图像像素值相加后让图像的像素值增大了,图像整体变亮。
2、图像加权和
- 将每幅图像权重考虑进来,可以用公式表达
$$
dst=saturate(src1×α+src2×β+γ)
$$
- 式中,saturate()表示取饱和值(最大值)。
- 图像进行加权和计算时,要求src1和src2必须大小、类型相同,但是对具体是什么类型和通道没有特殊限制。
- 它们可以是任意数据类型,也可以有任意数量的通道(灰度图像或者彩色图像),只要二者相同即可。
- opencv中提供了函数cv2.addWeighted()函数
- 语法格式如下
dst = cv2.addWeighted(scr1, alpha ,scr2, beta, gamma)
- 其中,参数alpha和beta是src1和src2所对应的系数,它们的和可以等于1,也可以不等于1。
- 该函数实现的功能是dst = src1×alpha + src2×beta + gamma。
- 需要注意,式中参数gamma的值可以是0,但是该参数是必选参数,不能省略。
- 可以将上式理解为“结果图像=图像1×系数1+图像2×系数2+亮度调节量”。
3、按位逻辑运算
按位与运算
算子1 | 算子2 | 结果 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
- 再OpenCV中可以使用cv2.bitwise_and()函数实现按位与运算
- 其语法为
dst = cv2.bitwise_and( src1, src2[,mask])
dst表示与输入值具有同样大小的array输出值。
- src1表示第一个array或scalar类型的输入值。
- src2表示第二个array或scalar类型的输入值。
- mask表示可选操作掩码,8位单通道array。
按位与操作有如下特点
- 将任何数值N与数值0进行按位与操作,都会得到数值0。
- 将任何数值N(这里仅考虑8位值)与数值255(8位二进制数是11111111)进行按位与操作,都会得到数值N本身。
一种应用
根据上述特点,可以构造一幅掩模图像M,掩模图像M中只有两种值:一种是数值0,另外一种是数值255。将该掩模图像M与一幅灰度图像G进行按位与操作,在得到的结果图像R中:
- 与掩模图像M中的数值255对应位置上的值,来源于灰度图像G。
- 与掩模图像M中的数值0对应位置上的值为零(黑色)。
import cv2
import numpy as np
a=cv2.imread("lena.bmp",0)
b=np.zeros(a.shape, dtype=np.uint8)
b[100:400,200:400]=255
b[100:500,100:200]=255
c=cv2.bitwise_and(a, b)
cv2.imshow("a", a)
cv2.imshow("b", b)
cv2.imshow("c", c)
cv2.waitKey()
cv2.destroyAllWindows()
按位或运算
算子1 | 算子2 | 结果 |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
- 在OpenCV中可以使用cv2.bitwise_or()函数来实现
- 其语法格式如下
dst = cv2.bitwise_or(scr1 ,scr2 [,mask])
按位非运算
- 运算为真时,结果为假
- 运算为假时,结果为真
- 语法如下
dst = cv2.bitwise_not(scr[,mask])
按位异或
算子1 | 算子2 | 结果 |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
- 语法格式如下
dst = cv2.bitwise_xor(sc1 ,scr2 [,mask])
4、掩模
- 当使用掩模参数时,操作只会在掩模为非空的像素点上执行,并将其他像素点的值置为0
5、位平面分解
将灰度图像中处于同一比特位上的二进制像素值进行组合,得到一幅二进制值图像,该图像被称为灰度图像的一个位平面,这个过程被称为位平面分解
- 在八位灰度图中,每一个像素使用8位二进制来表示
- 其值在[0,255]之间
- 可以将其中的值表示为
$$
value=a7×27+a6×26+a5×25+a4×24+a3×23+a2×22+a1×21+a0×20
$$
- 式中,ai的可能值为0或1。
- 可以看出,各个ai的权重是不一样的,a7的权重最高,a0的权重最低。
- 这代表a7的值对图像的影响最大,而a0的值对图像的影响最小。
import cv2
import numpy as np
lena=cv2.imread("lena.bmp",0)
cv2.imshow("lena", lena)
r, c=lena.shape
x=np.zeros((r, c,8), dtype=np.uint8)
for i in range(8):
x[:, :, i]=2**i
r=np.zeros((r, c,8), dtype=np.uint8)
for i in range(8):
r[:, :, i]=cv2.bitwise_and(lena, x[:, :, i])
mask=r[:, :, i]>0
r[mask]=255
cv2.imshow(str(i), r[:, :, i])
cv2.waitKey()
cv2.destroyAllWindows()
在本例中,通过两个循环提取了灰度图像的各个位平面,具体说明如下。
- 使用x=np.zeros((r, c,8), dtype=np.uint8)语句设置一个用于提取各个位平面的提取矩阵。该矩阵是“r×c×8”大小的,其中r是行高,c是列宽,8表示共有8个通道。r、c的值来源于要提取的图像的行高、列宽。矩阵x的8个通道分别用来提取灰度图像的8个位平面。例如,x[:, :,0]用来提取灰度图像的第0个位平面。
- 在第1个for循环中,使用x[:, :, i]=2**i语句设置用于提取各个位平面的提取矩阵的值。
- 在第2个for循环中,实现了各个位平面的提取、阈值处理和显示。
6、数字水印
从位平面的角度考虑,数字水印的处理过程分为下面两步。
- 嵌入过程:将载体图像的第0个位平面替换为数字水印信息(一幅二值图像)。
- 提取过程:将载体图像的最低有效位所构成的第0个位平面提取出来,得到数字水印信息。