0%

opencv_3_图像运算

图像加法运算

  1. 加号运算符“+”
  2. cv2.add()函数
  • 通常情况下,在灰度图像中,像素用8个比特位(一个字节)来表示,像素值的范围是[0, 255]。两个像素值在进行加法运算时,求得的和很可能超过255.上述两种不同的加法运算方式,对超过255的数值的处理方式是不一样的。

加号运算符

bca18dc98736f3894d182cecbce55ea

  • 式中,mod()是取模运算,表示计算“a+b的和除以256取余数”
1
2
3
4
import numpy as np

img1 = np.random.randint(0, 256, size=[3,3], dtype=np.uint8)
img2 = np.random.randint(0, 256, size=[3,3], dtype=np.uint8)
1
img1
array([[ 84,   0, 138],
       [ 86,  82, 191],
       [ 42,  14, 182]], dtype=uint8)
1
img2
array([[202,  39, 180],
       [ 22, 222, 180],
       [196, 207, 191]], dtype=uint8)
1
img1+img2
array([[ 30,  39,  62],
       [108,  48, 115],
       [238, 221, 117]], dtype=uint8)

cv2.add()函数

0160a8c84e41641ccd6b79d46fa1dc2

  • 当像素值的和大于255时统一赋值为255
1
2
import cv2
cv2.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 cv2
import numpy as np
a = 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
# 使用plt进行批量图像绘制
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 cv2
import 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)
1
img3
array([[113, 113, 113, 113],
       [113, 113, 113, 113],
       [113, 113, 113, 113]], dtype=uint8)

案例2:使用函数cv2.addWeighted()对两幅图像进行加权混合,观察处理结果

1
2
3
4
5
import cv2
import numpy as np
a = 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)
1
get_show(a,b,c)

png

按位逻辑运算

按位与运算

  • 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 cv2
import 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 cv2
import 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)

3output_32_0

按位或运算

  • 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 cv2
import numpy as np
img = 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)

png

图像与数值的运算

  • 在上述加法运算和按位运算中,参与运算的两个算子(参数)既可以是两幅图像,也可以是一幅图像与一个数值
  • 例如,如果想增加图像的整体亮度,可以将每一个像素值都加上一个特定值。在具体实现时,可以给图像加上一个统一像素值的图像,也可以给图像加上一个固定值。但是针对彩色图像只能对第一个维度进行处理
1
2
3
4
5
6
7
import numpy as np
import cv2

a = np.random.randint(0, 255, (5,5), dtype=np.uint8)
print('a=\n', a)
b = cv2.add(a, 5) # 每个个像素点加5,但保持最大值为255
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 np
import cv2

img = cv2.imread('data/dog.jpg', cv2.IMREAD_GRAYSCALE)
light_img = cv2.add(img, 100)
get_show(img, light_img) # 提高图像的亮度

3output_40_0

位平面分解

  • 将灰度图像中位于同一比特位上的二进制像素值进行组合,得到一幅二进制值图像,该图像被称为灰度图像的一个位平面,这个过程被称为位平面分解
  • 建立一个值均为2^n的Mat作为提取矩阵(数组),用来与原始图像进行按位与运算,可提取对应的第n个位平面。
  • 位平面的位数越高说明其在原始图像中的权重越高,越接近原始图像。
1
2
3
4
5
6
7
8
9
10
11
12
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = 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')

png

图像的加密和解密

  • 通过按位异或运算可以实现图像的加密和解密
  • 通过对原始图像与密钥图像进行按位异或,可以实现加密;将加密后的图像与密钥图像再次进行按位异或,可以实现解密
  • 根据上述按位异或运算的规则,假设:
  • 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 cv2
import matplotlib.pyplot as plt
import numpy as np

img = 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)

png

数字水印

  • 最低有效位信息隐藏指的是,将一个需要隐藏的二值图像信息嵌入载体图像的最低有效位,即将载体图像的最低有效位层替换位当前需要隐藏的二值图像,从而实现将二值图像隐藏的目的。由于二值图像处于载体图像的最低有效位上,所以对于载体图像的影响非常不明显,其具有较高的隐蔽性。
  • 在必要时直接将载体图像的最低有效位层提取出来,即可得到嵌入在该位上的二值图像,达到提取秘密信息的目的。
  • 这种信息隐藏也被称为数字水印,通过该方式可以实现信息隐藏、版权认证、身份认证等功能。例如,如果嵌入载体图像内的信息是版权信息,就能够实现版权认证;如果嵌入载体图像内的是身份信息,就可以实现数字签名,等等。所以,被嵌入载体图像内的信息也被称为数字水印信息。
  • 数字水印信息可以是文本、视频、音频等多种形式,这里我们仅讨论数字水印信息是二值图像的情况。

案例:将猫的最高有效位嵌入到狗的最低有效位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import cv2

dog = 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 # 将最高有效位处理为最大值为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) # 采用按位与运算得到后七位位平面,第一个位平面全位0
dog_tem = cv2.bitwise_or(dog_temp, cat_max_bit) # 采用按位或运算(因为上方操作已经将第一位位平面全置为了0)
1
get_show(dog,cat,cat_max_bit*255,dog_new)

png

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) # 展示水印

png

脸部打码及解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import cv2
import numpy

# 脸部打码
dog = 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) # 根据mask提取加密图像的脸部信息
entr_no_face = cv2.bitwise_and(dog,dog,mask=1-face_mask) # 根据mask提取原始图像的非脸部信息
entr_face_dog = entr_face+entr_no_face # 将两个信息进行加和
get_show(dog,entr_dog,entr_no_face,entr_face_dog)

png

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)

png

-------------本文结束感谢您的阅读-------------