三、图像运算
1、图像加法运算
3.1.1 加法运算符
对图像a(像素值为a)和图像b(像素值为)进行求和运算
a + b = a + b , a + b < = 255 a+b=a+b , a+b<=255 a+b=a+b,a+b<=255
$a+b=mod(a+b,256), a+b>255 $
mod(a+b,256) “表示计算a+b的和除以256取余数”
3.1.2 cv2.add()函数
计算结果 = cv2.add(像素值a,像素值b)
a + b = a + b , a + b < = 255 a+b=a+b,a+b<=255 a+b=a+b,a+b<=255
a + b = 255 , a + b > 255 a+b=255,a+b>255 a+b=255,a+b>255
**形式1:**计算结果=cv2.add(图像1,图像2),两个参数都是图像,此时参与运算的图像大小和类型必须保持一致。
形式2∶计算结果=cv2.add(数值,图像),第1个参数是数值,第2个参数是图像,此时将超过图像饱和值的数值处理为饱和值(最大值)。
形式3∶计算结果=cv2.add(图像,数值),第1个参数是图像,第2个参数是数值,此时将超过图像饱和值的数值处理为饱和值(最大值)。
示例:用加法运算符和cv2.add()函数计算两幅灰度图像的像素值之和
import cv2
a=cv2.imread ("lena.png",0)
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 ()
结果:
2、图像加权和
dst=cv2.addWeighted (src1,alpha,src2,beta,gamma)
参数alpha和beta是src1和src2所对应的系数
dst=src1×alpha+src2×beta+gamma
其中gamma不能省略,表示亮度调节量
3、按位逻辑运算
常见位运算函数:
函数名 | 基本含义 |
---|---|
cv2.bitwise_and() | 按位与 |
cv2.bitwise_or() | 按位或 |
cv2.bitwise_xor() | 按位异或 |
cv2.bitwise_not() | 按位取反 |
3.3.1 按位与运算
dst=cv2.bitwise_and (src1,src2[,mask]])
**src1、src2:**为输入图像或标量,标量可以为单个数值或一个四元组
**mask:**图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0
构造掩模图像M,值只有0和255,与灰度图像进行按位与操作,与掩模图像255对应的数值来源灰度图像,与0对应的值为0
示例:构造掩模图像,只保留lena的头部
import cv2
import numpy as np
a=cv2.imread ("lena.png",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()
结果:
3.3.2 按位或运算
dst=cv2.bitwise_or (src1,src2[,mask]])
3.3.3 按位非运算
dst=cv2.bitwise_not (src[,mask]])
3.3.4 按位异或运算
相同为0,不同为1
dst=cv2.bitwise_xor (src1,src2[,mask]])
四、掩模
计算结果=cv2.add(参数1,参数2,掩模)
当使用掩模参数时,操作只会在掩模值为非空的像素点上执行,并将其他像素点的值置为0。
我们通过将掩模图像转换为BGR模式的彩色图像,让彩色图像与(彩色)掩模图像进行按位与操作,从而实现掩模运算。
使用掩模图像作为掩模参数,完成按位与运算,即可得到由掩模控制的彩色图像。
五、图像与数值的运算
参与运算的两个算子既可以是两幅图像,也可以是一幅图像与一个数值。
例如,如果想要增加图像的整体亮度,可以将每一个像素值加上一个特定值。
六、位平面分解
定义:将灰度图像中处于同一比特位上的二进制像素值进行组合,得到一幅二进制值图像,该图像被称为灰度图像的一个位平面,这个过
程被称为位平面分解。
每一个像素用8位二进制表示为:value=a7×27+a6×26+a5×25+a4×24+a3×23+a2×22+a1×21+a0×20
a7权重最高,其值对图像影响最大
平面分解的具体步骤:
(1)图像预处理
读取原始图像O,获取原始图像O的宽度M和高度N
(2)构造提取矩阵
使用按位与操作提取指定位置上的数字
构造值为 2 n 2^n 2n的mat作为提取矩阵(数组),与原始图像进行按位与运算,提取第n个位平面
(3)提取位平面
将灰度图像与提取矩阵进行按位与运算,得到各个位平面
(4)阈值处理
通过计算得到的位平面是一个二值图像,要想让二值位平面能够以黑白颜色显示出来,要将得到的二值位平面进行阈值处理,大于0的值处理为255
mask=RD[:,:,i]>0
RD[mask]=255
(5)显示图像
示例:观察灰度图的各个位平面
import cv2
import numpy as np
lena=cv2 .imread("lena.png",0)
cv2.imshow("lena",lena)
r,c=lena.shape
x=np.zeros((r,c,8), dtype=np.uint8) #该矩阵是r行高,c列宽,8通道的矩阵,用来提取灰度图像的8个位平面
for i in range(8):
x[ :,:,i]=2**i #2的i次方,提取各个位平面的提取矩阵的值
r=np.zeros((r,c,8),dtype=np.uint8) #该矩阵是r行高,c列宽,8通道的矩阵,用来提取灰度图像的8个位平面
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()
七、图像加密和解密
通过按位异或可以实现图像的加密和解密
按位异或运算的过程示例
a | b | c=(xor(a,b)) | xor(c,b)=a | xor(c,a)=b |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 1 | 1 | 0 |
1 | 1 | 0 | 1 | 1 |
所以有:
a:明文,原始数据
b:密匙
c:密文,通过xor(a,b)实现
(1)加密过程: 将明文a与密钥b进行按位异或,完成加密,得到密文c。
(2)解密过程: 将密文c与密钥b进行按位异或,完成解密,得到明文a。
示例:
import cv2
import numpy as np
lena=cv2.imread("lena.png",0) #明文(原始图像)
r,c=lena.shape
key=np.random.randint (0,256,size=[r,c],dtype=np.uint8) #密匙图像,由随机数生成
encryption=cv2.bitwise_xor(lena,key) #加密图像,明文与密匙按位异或生成
decryption=cv2.bitwise_xor (encryption,key)
cv2.imshow ("lena",lena) #解密图像
cv2.imshow("key",key)
cv2.imshow("encryption",encryption)
cv2.imshow("decryption",decryption)
cv2.waitKey()
cv2.destroyAllWindows()
八、数字水印
**最低有效位(Least Significant Bit,LSB):**指的是一个二进制数中的第0位(即最低位)
**数字水印:**最低有效位信息隐藏指的是,将一个需要隐藏的二值图像信息嵌入载体图像的最低有效位,即将载体图像的最低有效位
层替换为当前需要隐藏的二值图像,从而实现将二值图像隐藏的目的。由于二值图像处于载体图像的最低有效位上,所以对于载体图像
的影响非常不明显,具有极高的隐蔽性,这种信息隐藏叫做数字水印。
3.8.1 原理
3.8.1.1 嵌入过程
**嵌入过程:**将载体图像的第0个位平面替换为数字水印信息(一幅二值图像)。
嵌入过程步骤:以原始图像为灰度图像,水印图像为二值图像
(1)原始载体图像预处理
提取图像的第0个位平面
(2)水印图像处理
将灰度二值水印信息进行阈值处理,转为二进制二值水印信息
(3)嵌入水印
将载体图像的最低有效位替换为二进制水印图像,完成水印的嵌入
3.8.1.2 提取过程
**提取过程: **将载体图像的最低有效位所构成的第0个位平面提取出来,得到数字水印信息。
在实际中可以根据需要在多个通道内嵌入相同的水印(提高鲁棒性,即使部分水印丢失,也能提取出完整水印信息),或在各个不同的通道内嵌入不同的水印(提高嵌入容量)
3.8.2 实现方法
3.8.2.1 嵌入过程
将数字水印信息嵌入载体图像内,步骤如下:
(1)载体图像预处理
读取原始载体图像,并获取载体图像的行数M和列数N
(2)建立提取矩阵
建立一个MxN大小、元素值均为254的提取矩阵(数组),用来提取载体图像的高七位。
(3)保留载体图像的高七位,将最低位置为0
载体图像与元素值为254的矩阵进行按位与运算
(4)水印图像处理
将8位灰度图的二值图像转换为二进制二值图像
(5)嵌入水印
将一个最低有效位(LSB)为0的数值A与一个单位二进制值B进行按位或运算,相当于用该单位二进制值B替换原始数值A的最低有效位,即可以实现将单位二进制值B嵌入数值A的最低有效位上。
(6)显示图像
水印嵌入过程的流程图
3.8.2.2 提取过程
(1)含水印载体图像处理
读取包含水印的载体图像,获取含水印载体的图像的大小M×N
(2)建立提取矩阵
定义一个与含水印载体图像等大小的值为1的矩阵作为提取矩阵
(3)提取水印信息
将含水印载体图像与提取矩阵进行按位与运算,提取水印信息
基于上述规则,针对图像内的每个像素,将其与数值1进行按位与操作,即可将图像的最低有效位提取出来
(4)计算去除水印后的载体图像
有时需要删除包含在水印载体图像内的水印信息。通过将含水印载体图像的最低有效位置零,即可实现删除水印信息。
(5)显示图像
示例:
import cv2
import numpy as np
#读取原始载体图像
lena=cv2.imread ("lena.bmp",0)
#读取水印图像
watermark=cv2.imread ("watermark.bmp",0)
#将水印图像内的值255处理为1,以方便嵌入
#后续章节会介绍使用threshold处理
w=watermark[:,:]>0
watermark[w]=1
#读取原始载体图像的shape值
r,c=lena.shape
#============嵌入过程============
#生成元素值都是254的数组
t254=np.ones ( (r,c) ,dtype=np.uint8) *254
#获取lena图像的高七位
lenaH7=cv2.bitwise_and (lena,t254)
#将watermark嵌入lenaH7内
e=cv2.bitwise_or (lenaH7,watermark)
#==========提取过程============
#生成元素值都是1的数组
t1=np.ones ( (r,c) ,dtype=np.uint8)
#从载体图像内提取水印图像
wm=cv2.bitwise_and (e,t1 )
print (wm)
#将水印图像内的值1处理为255,以方便显示
#后续章节会介绍使用threshold实现
w=wm[:,:]>0
wm[w]=255
#============显示============
cv2.imshow ("lena",lena)
cv2.imshow ("watermark",watermark*255)
#当前watermark内最大值为1
cv2.imshow ("e",e)
cv2.imshow ("wm",wm)cv2.waitKey ()
cv2.destroyAllWindows ()