图像加法运算
加号运算符“+”
cv2.add()函数
加号运算符
式中,mod()是取模运算,表示计算“a+b的和除以256取余数”
1 2 3 4 import numpy as npimg1 = np.random.randint(0 , 256 , size=[3 ,3 ], dtype=np.uint8) img2 = np.random.randint(0 , 256 , size=[3 ,3 ], dtype=np.uint8)
array([[ 84, 0, 138],
[ 86, 82, 191],
[ 42, 14, 182]], dtype=uint8)
array([[202, 39, 180],
[ 22, 222, 180],
[196, 207, 191]], dtype=uint8)
array([[ 30, 39, 62],
[108, 48, 115],
[238, 221, 117]], dtype=uint8)
cv2.add()函数
1 2 import cv2cv2.add(img1, img2)
array([[255, 39, 255],
[108, 255, 255],
[238, 221, 255]], dtype=uint8)
案例:分别使用加号运算符和函数cv2.add()计算两幅灰度图像的像素值之和。 1 2 3 4 5 6 7 8 9 import cv2import numpy as npa = cv2.imread('data/dog.jpg' , flags=cv2.IMREAD_GRAYSCALE) b = a c = a+b d = cv2.add(a, b) cv2.imshow('dog' , np.hstack([a, c, d])) cv2.waitKey() cv2.destroyAllWindows()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def get_show (*args ): import matplotlib.pyplot as plt img_list = [] if len (args[0 ].shape) == 3 : for i in args: img_list.append(i[:,:,::-1 ]) plt.figure(figsize=[20 ,20 ]) plt.xticks([]) plt.yticks([]) plt.imshow(np.hstack(img_list)) plt.show() else : img_list = args plt.figure(figsize=[20 ,20 ]) plt.xticks([]) plt.yticks([]) plt.imshow(np.hstack(img_list), cmap='gray' ) plt.show()
图像加权和
所谓图像加权和,就是在计算两幅图像的像素值之和时,将每幅图像的权重考虑进来
用公式表示为dst=saturate(src1×α+src2×β+γ)
式中:
saturate()表示取饱和值(最大值)。
图像进行加权和计算时,要求src1和src2必须大小、类型相同,但是对具体是什么类型和通道没有特殊限制。它们可以是任意数据类型,也可以有任意数量的通道(灰度图像或彩色图像),只要二者相同即可
cv2.addWeighted(src1, alpha, src2, beta, gamma)函数 案例1:使用数组演示函数cv2.addWeighted()的使用 1 2 import cv2import numpy as np
1 2 3 4 img1 = np.ones((3 ,4 ), dtype=np.uint8)*100 img2 = np.ones((3 ,4 ), dtype=np.uint8)*10 gamma = 3 img3 = cv2.addWeighted(img1, 0.6 , img2, 5 , gamma)
array([[113, 113, 113, 113],
[113, 113, 113, 113],
[113, 113, 113, 113]], dtype=uint8)
案例2:使用函数cv2.addWeighted()对两幅图像进行加权混合,观察处理结果 1 2 3 4 5 import cv2import numpy as npa = cv2.imread('data/dog.jpg' ) b = np.zeros(a.shape, dtype=np.uint8) b[:,:,0 ]=255
1 c = cv2.addWeighted(a,0.5 , b, 0.9 , 0.5 )
按位逻辑运算 按位与运算
dst=cv2.bitwise_and(src1, src2[,mask])
式中:
dst:表示与输入值具有同样大小的array输出值
src1:表示第一个array或scalar类型的输入值
src2:表示第二个array或scalar类型的输入值
mask:表示可选操作掩码,8位单通道array
任何数值与0进行按位与操作,都会得到0;任何数值与255进行按位与操作都会得到其本身
案例1:使用数组演示与掩膜图像的按位与运算 1 2 import cv2import numpy as np
1 2 3 4 5 6 7 8 a = np.random.randint(0 ,255 ,(5 ,5 ), dtype=np.uint8) b = np.zeros((5 ,5 ), dtype=np.uint8) b[0 :3 , 0 :3 ]=255 b[4 ,4 ] = 255 c=cv2.bitwise_and(a,b) print ("a=\n" , a)print ("b=\n" , b)print ("c=\n" , c)
a=
[[ 84 160 87 219 74]
[ 39 218 132 80 0]
[ 4 211 49 22 27]
[ 0 122 195 76 13]
[131 143 210 71 244]]
b=
[[255 255 255 0 0]
[255 255 255 0 0]
[255 255 255 0 0]
[ 0 0 0 0 0]
[ 0 0 0 0 255]]
c=
[[ 84 160 87 0 0]
[ 39 218 132 0 0]
[ 4 211 49 0 0]
[ 0 0 0 0 0]
[ 0 0 0 0 244]]
案例2:构造一个掩模图像,使用按位与运算保留图像中被掩膜指定的部分 1 2 import cv2import numpy as np
1 2 img = cv2.imread('data/dog.jpg' ) a = np.zeros(img.shape, dtype=np.uint8)
1 a[200 :300 , 250 :350 ,:]=255
1 2 b = cv2.bitwise_and(img,a) get_show(img,a,b)
按位或运算
dst=cv2.bitwise_or(src1,src2[,mask])
dst:表示与输入值具有同样大小的array输出值
src1:表示第一个array或scalar类型的输入值
src2:表示第二个array或scalar类型的输入值
mask:表示可选操作掩码,8位单通道array
按位非运算
dst=cv2.bitwise_not(src[,mask])
dst:表示与输入值具有同样大小的array输出值
src:表示array类型的输入值
mask:表示可选操作掩码,8位单通道array
按位异或运算
dst=cv2.bitwise_xor(src1,src2[,mask])
dst:表示与输入值具有同样大小的array输出值
src1:表示第一个array或scalar类型的输入值
src2:表示第二个array或scalar类型的输入值
mask:表示可选操作掩码,8位单通道array
掩膜
opencv中很多函数都会指定一个掩膜,也被称为掩码,例如:
计算结果=cv2.add(参数1, 参数2, 掩膜)
当使用掩膜参数时,操作只会在掩膜值为非空的像素点上执行,并将其他像素点的值置为0.
1 2 3 4 5 6 7 8 import cv2import numpy as npimg = cv2.imread('data/dog.jpg' ) a = np.zeros(img.shape[:2 ], dtype=np.uint8) print ('掩膜的尺寸为:' , a.shape)a[200 :300 , 250 :350 ]=255 b = cv2.bitwise_and(img,img, mask=a) get_show(img,b)
掩膜的尺寸为: (300, 534)
图像与数值的运算
在上述加法运算和按位运算中,参与运算的两个算子(参数)既可以是两幅图像,也可以是一幅图像与一个数值
例如,如果想增加图像的整体亮度,可以将每一个像素值都加上一个特定值。在具体实现时,可以给图像加上一个统一像素值的图像,也可以给图像加上一个固定值。但是针对彩色图像只能对第一个维度进行处理
1 2 3 4 5 6 7 import numpy as npimport cv2a = np.random.randint(0 , 255 , (5 ,5 ), dtype=np.uint8) print ('a=\n' , a)b = cv2.add(a, 5 ) print ('b=\n' , b)
a=
[[223 18 28 73 52]
[184 232 223 182 254]
[166 239 98 0 211]
[ 96 158 239 31 230]
[ 26 228 100 247 67]]
b=
[[228 23 33 78 57]
[189 237 228 187 255]
[171 244 103 5 216]
[101 163 244 36 235]
[ 31 233 105 252 72]]
1 2 3 4 5 6 import numpy as npimport cv2img = cv2.imread('data/dog.jpg' , cv2.IMREAD_GRAYSCALE) light_img = cv2.add(img, 100 ) get_show(img, light_img)
位平面分解
将灰度图像中位于同一比特位上的二进制像素值进行组合,得到一幅二进制值图像,该图像被称为灰度图像的一个位平面,这个过程被称为位平面分解
建立一个值均为2^n的Mat作为提取矩阵(数组),用来与原始图像进行按位与运算,可提取对应的第n个位平面。
位平面的位数越高说明其在原始图像中的权重越高,越接近原始图像。
1 2 3 4 5 6 7 8 9 10 11 12 import cv2import numpy as npimport matplotlib.pyplot as pltimg = cv2.imread('data/dog.jpg' , 0 ) h,w = img.shape x = np.zeros((h,w,8 ), dtype=np.uint8) for i in range (8 ): x[:,:,i] = np.power(2 , i) img_bit_split = np.zeros((h,w,8 ), dtype=np.uint8) for i in range (8 ): img_bit_split[:,:,i] = cv2.bitwise_and(img, x[:,:,i])
1 2 3 4 5 6 7 8 9 10 11 12 13 plt.rcParams['font.sans-serif' ]='SimHei' plt.figure(figsize=(10 ,10 )) plt.subplot(3 ,3 ,1 ) plt.title('原始图像' ) plt.xticks([]) plt.yticks([]) plt.imshow(img, cmap='gray' ) for i in range (1 ,9 ): plt.subplot(3 ,3 ,i+1 ) plt.title('第%d位位平面图' %i) plt.xticks([]) plt.yticks([]) plt.imshow(img_bit_split[:,:,i-1 ], cmap='gray' )
图像的加密和解密
通过按位异或运算可以实现图像的加密和解密
通过对原始图像与密钥图像进行按位异或,可以实现加密;将加密后的图像与密钥图像再次进行按位异或,可以实现解密
根据上述按位异或运算的规则,假设:
xor(a,b)=c
则可以得到:
xor(c,b)=a
xor(c,a)=b
根据上述规则:
a——->明文
b——->密钥
c——->密文
1 2 3 4 5 6 7 8 9 10 11 12 import cv2import matplotlib.pyplot as pltimport numpy as npimg = cv2.imread('data/dog.jpg' , 0 ) w,h = img.shape key_img = cv2.resize(cv2.imread('data/car.jpg' , 0 ), (h,w)) img2entr = cv2.bitwise_xor(img, key_img) entr2img = cv2.bitwise_xor(img2entr, key_img) get_show(img, key_img, img2entr, entr2img)
数字水印
最低有效位信息隐藏指的是,将一个需要隐藏的二值图像信息嵌入载体图像的最低有效位,即将载体图像的最低有效位层替换位当前需要隐藏的二值图像,从而实现将二值图像隐藏的目的。由于二值图像处于载体图像的最低有效位上,所以对于载体图像的影响非常不明显,其具有较高的隐蔽性。
在必要时直接将载体图像的最低有效位层提取出来,即可得到嵌入在该位上的二值图像,达到提取秘密信息的目的。
这种信息隐藏也被称为数字水印,通过该方式可以实现信息隐藏、版权认证、身份认证等功能。例如,如果嵌入载体图像内的信息是版权信息,就能够实现版权认证;如果嵌入载体图像内的是身份信息,就可以实现数字签名,等等。所以,被嵌入载体图像内的信息也被称为数字水印信息。
数字水印信息可以是文本、视频、音频等多种形式,这里我们仅讨论数字水印信息是二值图像的情况。
案例:将猫的最高有效位嵌入到狗的最低有效位 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import cv2dog = cv2.imread('data/dog.jpg' , 0 ) cat = cv2.imread('data/cat.jpg' , 0 ) w,h = dog.shape cat = cv2.resize(cat, (h,w)) bit_max = np.zeros((w,h), dtype=np.uint8) bit_max[:,:] = 2 **7 cat_max_bit = cv2.bitwise_and(cat, bit_max) ind = cat_max_bit==2 **7 cat_max_bit[ind] = 1 bit_min = np.ones((w,h), dtype=np.uint8) dog_min_bit = cv2.bitwise_and(dog, bit_min) dog_new = dog-dog_min_bit+cat_max_bit
1 2 3 4 5 bit_tmp = np.zeros((w,h), dtype=np.uint8) bit_tmp[:,:] = 254 dog_temp = cv2.bitwise_and(dog, bit_tmp) dog_tem = cv2.bitwise_or(dog_temp, cat_max_bit)
1 get_show(dog,cat,cat_max_bit*255 ,dog_new)
1 2 3 4 dog_new_min_bit = cv2.bitwise_and(dog_new,bit_min) dog_new_other_bit = cv2.bitwise_and(dog_new,bit_tmp) get_show(dog_new_min_bit*255 ,dog_new_other_bit)
脸部打码及解码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import cv2import numpydog = cv2.imread('data/dog.jpg' , 0 ) w, h = dog.shape face_mask = np.zeros((w,h), dtype=np.uint8) face_mask[200 :300 , 250 :350 ]=1 entr_key = np.random.randint(0 , 255 , size=(w,h), dtype=np.uint8) entr_dog = cv2.bitwise_xor(dog, entr_key) entr_face = cv2.bitwise_and(entr_dog,entr_dog, mask=face_mask) entr_no_face = cv2.bitwise_and(dog,dog,mask=1 -face_mask) entr_face_dog = entr_face+entr_no_face get_show(dog,entr_dog,entr_no_face,entr_face_dog)
1 2 3 4 5 6 get_entr_face = cv2.bitwise_and(entr_face_dog, entr_face_dog, mask=face_mask) get_face = cv2.bitwise_xor(get_entr_face, entr_key, mask=face_mask) get_no_face = cv2.bitwise_and(entr_face_dog, entr_face_dog, mask=1 -face_mask) return_dog = get_no_face + get_face get_show(entr_face_dog,get_entr_face,get_face,get_no_face,return_dog)