概述
第三章: 图像运算
- 图像加法运算
1、"+"
2、cv2.add()函数
3、图像加权和:cv2.addWeighted()函数 - 图像位运算(位逻辑运算)
1、按位与运算:cv2.bitwise_and()函数
2、按位或运算:cv2.bitwise_or()函数
3、按位非运算:cv2.bitwise_not()函数
4、按位异或运算:cv2.bitwise_xor()函数 - 掩模(掩码)参数
- 图像与数值的运算
- 图像位平面分解
- 图像加密解密
- 数字水印
- 案例:脸部打码解码
一、图像加法运算
1、用加号'+'运算符进行加法运算。
这种运算方法下,当两个像素点的像素值之和大于255时,就将计算结果对256取模:mod(a+b, 256), mod()是取模运算,表示计算'a+b的和除以256取余数'
#例3.1 使用随机数生成一个灰度图像,观察使用'+'对像素值求和的结果
import numpy as np
import cv2
img1 = np.random.randint(0, 256, size=(3, 3), dtype=np.uint8)
img2 = np.random.randint(0, 256, size=(3, 3), dtype=np.uint8)
img1, img2
img1+img2
(array([[153, 183, 176], [ 53, 41, 51], [224, 41, 109]], dtype=uint8), array([[ 85, 200, 6], [ 84, 1, 173], [ 35, 155, 53]], dtype=uint8)) array([[238, 127, 182], [137, 42, 224], [ 3, 196, 162]], dtype=uint8)
说明 :参数dtype=np.uint8是定义我们生成的数组对象的类型,让我们生成的数组对象的类型为uint8类型。
uint8类型的数据对象可以保证数组内的所有数值的大小都在[0, 255]之间。而图像数据中的每个像素点的值都是256个灰度级。
当两个图像的对应像素点相加后,如果数值超过了255,就进行取余操作。
所以,当用+号对两幅图像进行相加后,如果对应位置上的像素点值都非常大,也就是非常亮的时候,相加操作后对应位置的亮度反而变暗了。
2、用cv2.add()函数进行加法运算
这种加法方法下,当两个像素点的像素值之和大于255时,就将计算结果等于像素点的饱和值255(最大值)。
#例3.2 使用随机数生成一个灰度图像,观察使用cv2.add()函数对像素值求和的结果
import numpy as np
import cv2
img1 = np.random.randint(0, 256, size=(3, 3), dtype=np.uint8)
img2 = np.random.randint(0, 256, size=(3, 3), dtype=np.uint8)
img1, img2
cv2.add(img1, img2)
(array([[ 45, 34, 149], [ 66, 0, 241], [104, 134, 103]], dtype=uint8), array([[ 71, 131, 163], [ 88, 184, 104], [227, 215, 71]], dtype=uint8)) array([[116, 165, 255], [154, 184, 255], [255, 255, 174]], dtype=uint8)
#例3.3 用Lena的灰度图像,观察使用'+'号运算符和cv2.add()函数的区别
import cv2
lena_gray = cv2.imread(r'C:Users25584Desktoplena.bmp',0) #参数0表示图像被调整为单通道的灰度图像
lena_copy = lena_gray
lena_1 = lena_gray + lena_copy
lena_2 = cv2.add(lena_gray, lena_copy)
cv2.imshow('lena_gray', lena_gray)
cv2.imshow('lena_1', lena_1)
cv2.imshow('lena_2', lena_2)
cv2.waitKey(20000)
cv2.destroyAllWindows()
32 说明 :使用+号进行图像像素求和时,将大于255的像素值取模处理了,其结果就是导致这个像素点的值变小了,所以本来应该更亮的像素点变更暗了 使用cv2.add()函数进行图像像素求和时,将大于255的像素值都强制等于255这个饱和值(最大值)了,所以,图像整体变亮了。
3、图像加权和:cv2.addWeighted(img1, alpha, img2, beta, gamma)函数
图像加权和也叫图像融合、图像混合。就是将两幅图像对应的像素点的像素值进行加权相加,就是每幅图像的权重考虑进来。
结果图像= img1 * alpha + img2 * beta + gamma
#例3.4 联系cv2.addWeighted()函数
import cv2
import numpy as np
img1 = np.ones((3, 4), dtype=np.uint8)*100
img2 = np.ones((3, 4), dtype=np.uint8)*10
img1, img2
alpha, beta, gamma = 0.6, 5, 8 #可以尝试参数设置为2,5,8看看结果。
img3 = cv2.addWeighted(img1, alpha, img2, beta, gamma)
img3
(array([[100, 100, 100, 100], [100, 100, 100, 100], [100, 100, 100, 100]], dtype=uint8), array([[10, 10, 10, 10], [10, 10, 10, 10], [10, 10, 10, 10]], dtype=uint8)) array([[118, 118, 118, 118], [118, 118, 118, 118], [118, 118, 118, 118]], dtype=uint8)
#例3.5 用函数cv2.addWeighted()对两幅图像进行加权混合,观察结果
import cv2
lena = cv2.imread(r'C:Users25584Desktoplena512.bmp')
boat = cv2.imread(r'C:Users25584Desktopboat.bmp')
lena_boat = cv2.addWeighted(lena, 0.6, boat, 0.4, 0)
cv2.imshow('lena', lena)
cv2.imshow('boat', boat)
cv2.imshow('lena_boat', lena_boat)
cv2.waitKey(10000)
cv2.destroyAllWindows()
-1
#例3.6 用函数cv2.addWeighted()将一幅图像的ROI混合在另外一幅图像中,具体的是把lena的脸放到dollar的脸上。
lena = cv2.imread(r'C:Users25584Desktoplena512.bmp')
dollar = cv2.imread(r'C:Users25584Desktopdollar.bmp')
cv2.imshow('lena', lena)
cv2.imshow('dollar', dollar)
lena_face = lena[220:400, 250:350] #两张脸的ROI大小必须相等
dollar_face = dollar[160:340, 200:300]
face_mix = cv2.addWeighted(lena_face, 0.6, dollar_face, 0.4, 0) #将两张脸进行加权混合
dollar[160:340, 200:300] = face_mix #混合后的脸赋给dollar
cv2.imshow('dollar2', dollar)
cv2.waitKey(10000)
cv2.destroyAllWindows()
图像加法运算小结:
import cv2
import numpy as np
import matplotlib.pyplot as plt
lena = cv2.imread(r'C:Users25584Desktoplena512.bmp')
dollar = cv2.imread(r'C:Users25584Desktopdollar.bmp')
lena_dollar = lena + dollar
lena_add_dollar = cv2.add(lena, dollar)
lena_dollar_weightadd = cv2.addWeighted(lena, 0.6, dollar, 0.4, 0)
fig, axes = plt.subplots(1,5, figsize=(15,8), dpi=100)
axes[0].imshow(lena[:,:,::-1]), axes[0].set_title('lena'), axes[0].xaxis.set_ticks([]), axes[0].yaxis.set_ticks([])
axes[1].imshow(dollar[:,:,::-1]), axes[1].set_title('dollar'), axes[1].xaxis.set_ticks([]), axes[1].yaxis.set_ticks([])
axes[2].imshow(lena_dollar[:,:,::-1]), axes[2].set_title('lena_dollar'), axes[2].xaxis.set_ticks([]), axes[2].yaxis.set_ticks([])
axes[3].imshow(lena_add_dollar[:,:,::-1]), axes[3].set_title('lena_add_dollar'), axes[3].xaxis.set_ticks([]), axes[3].yaxis.set_ticks([])
axes[4].imshow(lena_dollar_weightadd[:,:,::-1]), axes[4].set_title('lena_dollar_weightadd'), axes[4].xaxis.set_ticks([]), axes[4].yaxis.set_ticks([])
plt.show()
二、图像位逻辑运算
1、按位与运算:cv2.bitwise_and()函数
二进制中的与运算,其逻辑关系可以类比为一个串联电路,只有两个开关都闭合时,灯才会亮。也就是说,参与运算的两个逻辑值都是真时,结果才为真。与运算的表示符号是‘and’。
and(0,0)=0
and(0,1)=0
and(1,0)=0
and(1,1)=1
在opencv中,cv2.bitwise_and()函数可以实现按位与运算。
说明:与运算有下面三个特点:
任何数a和0进行按位与运算,都会得到0。
任何数a和255进行按位与运算,都会都得这个数a本身。
任何数a和自身进行按位与运算,也是会得到这个数a本身。
根据与运算的上面特点,我们可以构造掩码图像。
掩码图像上的255位置点的像素值就可以来源于原图像;掩码图像上的0位置点的像素值就是0(黑色)。
#例3.7 用数组演示与掩码图像的按位与运算
import cv2
import numpy as np
a = np.random.randint(0, 256, (5, 5), dtype=np.uint8) #原图像-灰度图像
mask = np.zeros((5,5), dtype=np.uint8) #掩码图像
mask[0:3, 0:3]=255
mask[4,4]=255
b = cv2.bitwise_and(a, mask) #原图像与掩码图像的按位与操作。
a
mask
b
array([[185, 172, 217, 0, 0], [179, 62, 129, 0, 0], [ 95, 10, 182, 0, 0], [ 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 159]], dtype=uint8)
#例3.8 构造一个掩膜图像,保留原灰度图像中掩膜图像指定的部分
import cv2
import numpy as np
lena = cv2.imread(r'C:Users25584Desktoplena512.bmp', 0)
mask = np.zeros(lena.shape, dtype=np.uint8)
mask[100:400, 200:400]=255
mask[100:500, 100:200]=255
lena_mask = cv2.bitwise_and(lena, mask)
cv2.imshow('lena', lena)
cv2.imshow('mask', mask)
cv2.imshow('lena_mask', lena_mask)
cv2.waitKey(10000)
cv2.destroyAllWindows()
#例3.9 构造一个掩膜图像,保留原彩色图像中掩膜图像指定的部分
import cv2
import numpy as np
lena = cv2.imread(r'C:Users25584Desktoplena512.bmp', 1)
mask = np.zeros(lena.shape, dtype=np.uint8)
mask[100:400, 200:400]=255
mask[100:500, 100:200]=255
lena_mask = cv2.bitwise_and(lena, mask)
print(lena.shape, mask.shape)
cv2.imshow('lena', lena)
cv2.imshow('mask', mask)
cv2.imshow('lena_mask', lena_mask)
cv2.waitKey(10000)
cv2.destroyAllWindows()
(512, 512, 3) (512, 512, 3)
2、按位或运算:cv2.bitwise_or()函数
二进制中的与运算,其逻辑关系可以类比为一个并联电路,只要有一个开关闭合,灯就会亮。也就是说,参与运算的两个逻辑值只要有一个是真时,结果就为真。或运算的表示符号是‘or’。
or(0,0)=0
or(0,1)=1
or(1,0)=1
or(1,1)=1
在opencv中,cv2.bitwise_or()函数可以实现按位或运算。
3、按位非运算:cv2.bitwise_not()函数
二进制中的非运算就是取反操作。就是说,当运算数是真时,就返回假,当运算数是假时,就返回真。非运算的表示符号是‘not’。
not(0) = 1
not(1) = 0
在opencv中,cv2.bitwise_not()函数可以实现按位或运算。
4、按位异或运算:cv2.bitwise_xor()函数
异或运算也叫半加运算,运算法则和不带进位的二进制加法类似,所以也叫半加运算。异或运算的表示符号是‘xor’。
xor(0,0)=0
xor(0,1)=1
xor(1,0)=1
xor(1,1)=0
在opencv中,cv2.bitwise_xor()函数可以实现按位异或运算。
三、掩膜参数
掩膜又称掩码,在opencv中有很多函数都有一个掩膜参数,当我们使用这个参数时,操作只会在掩膜值为非空的像素点上执行,并将其他像素点的值置为0。
#例3.10 演示掩码参数在cv2.add()函数中的使用
import cv2
import numpy as np
img1 = np.ones((4,4), dtype=np.uint8)*3
img2 = np.ones((4,4), dtype=np.uint8)*5
mask = np.zeros((4, 4), dtype=np.uint8)
mask[2:4, 2:4]=1
img3 = cv2.add(img1, img2, mask=mask)
img1, img2
mask, img3
(array([[3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3]], dtype=uint8), array([[5, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5]], dtype=uint8)) (array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 1]], dtype=uint8), array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 8, 8], [0, 0, 8, 8]], dtype=uint8)) 说明: 掩膜参数控制的是,在生成的图像中,哪些像素是原图的像素值,哪些像素值是0。
#例3.11 掩膜参数在彩图中应用
import cv2
import numpy as np
colorlena = cv2.imread(r'C:Users25584Desktoplenacolor.png')
w,h,c = colorlena.shape
mask = np.zeros((w,h), dtype=np.uint8)
mask[100:400, 200:400]=255
mask[100:500, 100:200]=255
result = cv2.bitwise_and(colorlena, colorlena, mask=mask)
cv2.imshow('colorlena', colorlena)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(10000)
cv2.destroyAllWindows()
-1
说明: 掩膜参数在三通道的彩图中,参数大小必须和原图大小一致,但维度可以不一致,维度可以是二维的。
但如果不用mask这个参数,而是直接cv2.bitwise_and(原图,掩膜图)进行位与运算时,这个掩码图就必须也原图的维度要一致,否则无法计算。
四、图像与数值的运算
一般用cv2.add()函数进行图像与数值的运算。
一般用于调整图像的明亮度。
#例3.12 演示图像与数值的运算结果
import cv2
import numpy as np
img1 = np.ones((4,4), dtype=np.uint8)*3
img2 = np.ones((4,4), dtype=np.uint8)*5
img3 = cv2.add(img1, img2)
img4 = cv2.add(img1, 6)
img5 = cv2.add(6, img2)
img1,img2,img3
img4,img5
(array([[3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3]], dtype=uint8), array([[5, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5]], dtype=uint8), array([[8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8], [8, 8, 8, 8]], dtype=uint8)) (array([[9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9], [9, 9, 9, 9]], dtype=uint8), array([[11, 11, 11, 11], [11, 11, 11, 11], [11, 11, 11, 11], [11, 11, 11, 11]], dtype=uint8))
五、图像位平面分解
-
1、什么是图像位平面分解?
将图像像素点(0,255)从十进制转化为二进制,每个二进制数字的像素点的每个数字上的对应位置的数字进行组合,得到一个像素点值只有0和1的位平面,这个过程就是位平面分解。 -
2、一张图像位平面分解后变成了什么?
一幅图像可以分解从8个位平面图像。其中第1位数字组合的位平面图叫'最高位平面图',第8位数字组合的位平面图叫'最低位平面图'。
显然,'最高位平面图'与原图相关性最高,看起来与原图最像;'最低位平面图'与原图相关性最低,看起来杂乱无章。 -
3、如何提取一张图片的8个位平面图?
构造8个提取矩阵(第一个提取矩阵全部值是1,第二个提取矩阵全部是2,依次类推是4,8,16,32,64,128)与原始图像进行按位与运算即可。
原理: 将像素值和与一个值为2^n的数值进行按位与运算,能够使像素值的第n位保持不变,而将其他各位均变为0。所以,通过像素值与特定值的按位与运算,能够提取像素值的二进制形式中的指定位置的值。因此,通过原图与提取矩阵之间的位运算,能够提取原图的位平面图。 -
4、阈值处理:为什么要进行阈值处理?
通过上面的步骤我们提取出的8个位平面图是一个0-1的二值图像,如果可视化这种图像,得到的就是一张黑黑的图片,肉眼看不出有何信息。 如果我们想让位平面图人眼能看到,就要进行阈值处理,就是将其中的1处理成255,这样位平面图就是一张黑白照片了,人眼可以看到了。
具体操作方法:
1)先将位平面图a[:,:,:]的所有是1的像素点以及像素点的通道数都全部切出来;
2)让a[:,:,:]>0返回的就是一个形状大小相同的true or false的矩阵;
3)然后a[a[:,:,:]>0]就把全部是1的像素点切出来了;
4)a[a[:,:,:]>0]=255,就把全部是1的像素点更改为255了。此时就可以可视化了。在opencv中,提供了专门的函数进行阈值处理,相关内容会在第6章进行详细介绍。
#例3.13 观察灰度图像的各个位平面图 import cv2 import numpy as np lena = cv2.imread(r'C:Users25584Desktoplena512.bmp', 0) cv2.imshow('lena', lena) r,c = lena.shape list_img = [] #生成一个空列表,保存用循环生成的每个位图 for i in range(8): mat = np.ones((r,c), dtype=np.uint8)*2**i #生成提取矩阵mat bit_img= cv2.bitwise_and(lena, mat) #原始图像与提取矩阵进行按位与运算,得到对应位上的数据。!!!注意 bit_img[bit_img[:,:]!=0]=255 list_img.append(bit_img) cv2.imshow('lena0', list_img[0]) cv2.imshow('lena1', list_img[1]) cv2.imshow('lena2', list_img[2]) cv2.imshow('lena3', list_img[3]) cv2.imshow('lena4', list_img[4]) cv2.imshow('lena5', list_img[5]) cv2.imshow('lena6', list_img[6]) cv2.imshow('lena7', list_img[7]) cv2.waitKey(30000) cv2.destroyAllWindows()
注意: 这里按位与运算提取了原始图像上相应位上的0或1的那个数字,但是返回的位图像像素值不是二进制的,是十进制的,所以返回的位图像像素值就是相应位上是1的像素点的提取矩阵的数值。因为是十进制的显示。
比如当我们的第4个mat矩阵,这个mat矩阵是一个全是8的矩阵,当这个矩阵和lena进行bitwise_and运算时,返回的bit_img就是一个:和lena图像上二进制形式下第4位是1的形式,但这个形式上的值不是1是8。
说明: 第0个位平面图位于8位二进制的最低位,其权重最低,对像素值的影响最小,与lena原图的相关度也是最低的,所以显示出来是一副杂乱无章的图像。
第7个位平面图位于8位二进制的最高位,其权重最高,对像素值的影响最大,与lena原图的相关度也是最高的,所以显示出来的图像是与原始图像最为接近的二值图像。上面程序是一个重点,是理解位图的关键,一定要弄明白其中的逻辑!!!!
六、图像加密解密
-
1、什么是加密解密?
加密: 将明文a与密钥b进行运算,得到密文c。加密完成。
解密: 将密文c与密钥b进行运算,得到名文a。解密完成。 -
2、如何运算可以加解密?
图像是由像素点构成的,像素点是0-255的数字构成的。数字与数字之间的按位异或运算可以实现加密解密。为什么?看下面:
xor(0,0)=0
xor(0,1)=1
xor(1,0)=1
xor(1,1)=0
假设异或运算的第一个算子是明文,第二个算子是密钥,结果是密文,上面的异或运算满足:
xor(明文,密钥)=密文
xor(密文,密钥)=明文
所以,按位异或运算可以实现像素点的加密和解密。比如一张图像上某个像素点的值是216(明文),假设我们用178这个数字作为密钥,让这两个数字按位异或运算:xor(216, 178)=106,就得到密文106,就完成了对这个像素点的加密。当通信的另一方收到106这个密文时,他就用xor(106, 178)=216,就得到明文216了,就实现了这个像素点的解密。同理,如果把一张图像的每个像素点都用这个方法进行运算,就实现了图像的加密解密。也就是说,一个原始图像,我们让它和一个密钥图像(密钥图像是不能公开的,只有加密者和解密者双方共同拥有)进行按位异或运算,就实现了原始图像的加密。当解密者收到加密图像后,把加密图像和密钥进行按位异或运算,就可以看到原图了,就实现了解密密图。
- 3、图像加密解密的具体运算过程:
1)确定加密密钥图像,密钥图像可以是随机生成的也可以是加解密双方指定的某个图像;
2)将原始图像和密钥图像都用二进制表示,并对二者进行异或运算,再把运算结果转化为十进制,就得到加密图像;
3)将加密图像和密钥图像都用二进制表示,并对二者进行异或运算,再把运算结果转化为十进制,就得到解密图像;
在实际操作中,加密和解密双方先协商预先确定一幅密钥图像(可以是一幅有意义的图像,也可以是一幅没有意义的随机生成的图像),密钥图像加解密双方各保存一份备用,这样双方就可以用这个密钥图像进行图像加密解密了。原始图像通过加密后就会变得杂乱无章,其他人无法看到图像到底表示的是什么,而解密者通过密钥图像,就可以把这个杂乱无章的密图还原成原图,从而达到图像信息的安全传输。#例3.14 随机生成一幅密钥图像,对lena进行加密和解密 import cv2 import numpy as np lena = cv2.imread(r'C:Users25584Desktoplena.bmp',0) r, c = lena.shape key_img = np.random.randint(0, 256, size=(r,c), dtype=np.uint8) #生成密钥图像 encryption = cv2.bitwise_xor(lena, key_img) #对lena进行加密 decryption = cv2.bitwise_xor(encryption, key_img) #对lena进行解密 cv2.imshow('lena', lena) cv2.imshow('key_img', key_img) cv2.imshow('encryption', encryption) cv2.imshow('decryption', decryption) cv2.waitKey(20000) cv2.destroyAllWindows()
七、数字水印
-
1、什么是数字水印?
数字水印就是给一幅图像里面嵌入一些其他信息,这些信息不会影响这张图像的视觉感官,但是这张图像背后确实藏着一些信息,并且这些隐藏的信息是可以提取出来的。所以,当一张图背后藏着一些秘密信息的话,不知道这个事的人即使看到这张图像,也发现不了有啥异常,也不知道这张图像到底携带什么信息,如果知道这个事的人就知道这个图像是携带秘密信息,就可以把这个秘密信息提取出来,就得到了秘密,这样就实现了秘密信息的传递。同理,如果这个秘密信息是图像的版权信息,这种操作就能够实现版权认证。如果这个秘密信息是身份信息,这种操作就是数字签名,或者叫数字印章。 -
2、如何给一幅图像嵌入秘密信息?
我们先把想要嵌入的秘密信息做出二值图像(0-1图像),然后把这个二值图像放到原始图像的最低位图位置上,就实现了秘密信息的嵌入。因为一幅图像的最低位图上的数字对这副图像的显示影响最低,低到人类肉眼根本无法识别,所以把一幅图像的最低位数值变成秘密信息对一幅图像来说,基本不改变人类肉眼看它的效果。这样就实现了图像隐藏秘密的目的,并且在必要时可以将最低位的秘密信息提取出来,就达到了提取秘密信息的目的。 -
3、图像嵌入数字水印的具体过程:
1)生成水印图像:就是生成一个像素点只有0和1的二值图像,就是看起来是纯黑的图像。这个操作过程用判别语句即可。
2)处理原始图像得到载体图像:就是保留原始图像的高7位,最低位置为0。具体操作过程是:将原始图像与全部为254(1111 1110)的提取矩阵按位与运算,得到的就是载体图像。
3)往载体图像里面嵌入水印图像,得到含水印图像。具体操作过程是:将载体图像与水印图像进行按位或运算,得到含水印图像。 -
4、含水印图像的水印提取过程:
1)生成提起矩阵:生成一个与含水印图像大小相等的、所有像素点值都为1(0000 0001)的数组,作为提取矩阵。
2)提取水印信息:将含水印图像与提取矩阵进行按位与运算,提取水印信息。
3)将提取的水印信息从0-1转化为0-255,水印信息就可以可视化出来了。 -
5、如何将含水印图像去水印?
就是删除含水印图像中的水印。就是将含水印图像中的最低位置零。
具体操作过程是:用全部像素值为254(1111 1110)的提取矩阵与含水印图像进行按位与运算。就是保留含水印图像的高7位,最低位置0。#例3.15 编写程序,模拟数字水印的嵌入和提取过程。 import cv2 import numpy as np #读取原始图像 lena = cv2.imread(r'C:Users25584Desktoplena512.bmp',0) r,c = lena.shape #生成水印图像,这里我们不是生成一个随机的图像而是一个已经做好的有意义的图像 watermark = cv2.imread(r'C:Users25584Desktopwatermark.bmp',0) #读取水印图像 watermark[watermark[:,:]!=0]=1 #将水印图像处理成0-1的二值图像 #处理原始图像得到载体图像 mat254 = np.ones((r,c), dtype=np.uint8)*254 #生成像素值全部为254的提取矩阵 lena_up7 = cv2.bitwise_and(lena, mat254) #原图像与提取矩阵进行与运算,生成载体图像 #往载体图像里面嵌入水印图像得到含水印图像 lena_watermark = cv2.bitwise_or(lena_up7, watermark) #从lena_watermark中提取水印图像 mat1 = np.ones((r,c), dtype=np.uint8) #生成像素值全部为1的提取矩阵 watermark_new = cv2.bitwise_and(lena_watermark, mat1) #提取0-1二值水印图像 watermark_new[watermark_new[:,:]!=0]=255 #将水印转化为0-255二值图像 cv2.imshow('lena',lena) cv2.imshow('lena_up7',lena_up7) cv2.imshow('lena_watermark',lena_watermark) cv2.imshow('watermark_new',watermark_new) cv2.waitKey(20000) cv2.destroyAllWindows()
说明: 我们通过肉眼无法看出含水印图像和原始图像有什么不同,所以水印的隐蔽性比较高。但是这种方法过于简单,安全性不高,在实际的商业化中是通过更加复杂的方法来嵌入水印的。
八、案例:脸部打码及解码
#例3.16 编写程序,使用掩码对lena图像的脸部进行打码、解码。 import cv2 import numpy as np lena = cv2.imread(r'C:Users25584Desktoplena512.bmp',0) r,c = lena.shape ##给lena打码 #1、只显示lena脸部,其他部分打码 mask1 = np.zeros((r,c), dtype=np.uint8) #生成一个掩膜图像(任何一个数与0与运算都是0,任何一个数与1与运算都是这个数本身) mask1[220:400, 250:350]=255 #这个掩膜图像大小是lena.shape的大小,像素值是0或255 lena_face = cv2.bitwise_and(lena, mask1) #2、给lena脸部打码 mask2 = np.ones((r,c), dtype=np.uint8)*255 mask2[220:400, 250:350]=0 lena_no_face = cv2.bitwise_and(lena, mask2) #3、给lena脸部打彩色码 ROI = np.random.randint(0,256,size=(180,100), dtype=np.uint8) lena_no_face_color = lena.copy() lena_no_face_color[220:400, 250:350] = ROI ##给lena加密解密 key = np.random.randint(0,256,size=(r,c), dtype=np.uint8) #生成一个随机密钥图像 #1、使用密钥key对lena整体加密 lena_encryption = cv2.bitwise_xor(lena, key) #2、只对lena脸部解密 face_only = lena_encryption.copy() face_only[220:400, 250:350] = lena_face[220:400, 250:350] #3、使用密钥key对lena整体解密 lena_decryption = cv2.bitwise_xor(lena_encryption, key) cv2.imshow('lena',lena) cv2.imshow('lena_face',lena_face) cv2.imshow('lena_no_face',lena_no_face) cv2.imshow('lena_no_face_color',lena_no_face_color) cv2.imshow('lena_encryption',lena_encryption) cv2.imshow('face_only',face_only) cv2.imshow('lena_decryption',lena_decryption) cv2.waitKey(40000) cv2.destroyAllWindows()
最后
以上就是冷酷故事为你收集整理的【OpenCV 学习笔记】第三章: 图像运算的全部内容,希望文章能够帮你解决【OpenCV 学习笔记】第三章: 图像运算所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复