图像上的算术运算
图像融合
图像融合即也是图像加法,但它是对每个图像乘以相应的权重,使其具有融合或透明的感觉。根据以下等式进行运算。
f(x)可作为输入的图像,则上式可变为:
在OpenCV中进行图像融合的函数为cv.addWeighted(img1,$\beta$,img2,$\alpha,\gamma$),其有四个参数,img1与img2分别为输入的图像,$\beta,\alpha$分别为各自图像融合时所占的权重,一般情况下$\gamma$为0。
以下为测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img1=cv.imread(r'D:\Python\image_processing\exercise\save.png')
img2=cv.imread(r'D:\Python\image_processing\exercise\imori.jpg')
dst1=cv.addWeighted(img1,0.8,img2,0.2,0)
dst2=cv.addWeighted(img1,0.2,img2,0.8,0)
images=[dst1,dst2]
titles=['dst1','dst2']
for i in range(2):
images[i]=cv.cvtColor(images[i],cv.COLOR_BGR2RGB)
plt.subplot(1,2,i+1)
plt.imshow(images[i],'jet')
plt.title(titles[i],fontsize=16)
plt.xticks([]),plt.yticks([])
plt.show()代码解读:
在这里要注意到,使用Matplotlib显示图片时,要先将图片转换为RGB形式,在OpenCV中,图像是以BGR通道存储的,直接显示会出现问题。
上述测试代码里的img1为img2的灰度图,可以发现当$\beta$取0.8,$\alpha$取0.2时,img1融合时占比较高,当$\beta$取0.2,$\alpha$取0.8时,二者的对比结果如下图所示:
可以发现前者更加偏灰度,后者更加偏向原图。
按位运算
有时候,我们不想将图像相加或者融合,例如,下面这张图片:
它就是由两张图片——(西电LOGO和人物图)进行“掩盖”合成的。
按位操作分为以下四种:AND,OR,NOT,XOR,一一介绍它们的运算:
1. AND:即“与”运算,(1&1=1,1&0=0,0&1=0,0&0=0),其具体意义可理解为,只有两值都大于0,其为真。而在像素中,其取值在0~255之间,0为黑色,255为白色,而这里大于0的像素值都可以看作1。在两个都大于0的像素值之间进行AND运算,其结果取较小的像素值!
2. NOT:即“非”运算,(~1=0,~0=1),其具体意义可理解为,取像素的相反值,则当图像为二值图时,原图的黑色变为白色,白色变为黑色。
3. OR:即“与”运算,(1|1=1,1|0=1,0|1=1,0|0=0),其具体意义可理解为,只有当两值都为0,其为假。而对于两像素值,其先进行二进制转换,后对其进行运算,例如3|5:00000011|00000101=00000111,因此3|5=7。
4. XOR:即“异或”运算,(1^1=0,1^0=1,0^1=1,0^0=0),其具体意义可理解为,只有当两值不相同时,其为真。对于两两像素值,先进行二进制转换,后对其进行运算,例如3^5:00000011^00000101=00000110,因此3^5=6。
OpenCV中,进行按位运算的有以下四个函数:cv.bitwise_not,cv.bitwise_and,cv.bitwise_or,cv.bitwise_xor,这四个函数即对应上面的运算规则。下面将以下两张图片合成为上图:
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img1=cv.imread(r'D:\Python\image_processing\exercise\xidian1.jpg')
img2=cv.imread(r'D:\Python\image_processing\exercise\girl.jpg')
row,cols,channels=img1.shape
roi=img2[0:row,0:cols]
img1_gray=cv.cvtColor(img1,cv.COLOR_BGR2GRAY)
ret,dst1=cv.threshold(img1_gray,200,255,cv.THRESH_BINARY_INV)
dst1_inv=cv.bitwise_not(dst1)
img2_bg=cv.bitwise_and(roi,roi,mask=dst1_inv)
img1_bg=cv.bitwise_and(img1,img1,mask=dst1)
dst=cv.add(img1_bg,img2_bg)
img2[0:row,0:cols]=dst
cv.imshow('images',img2)
cv.waitKey(0)
cv.destroyAllWindows()代码解读:
首先由shape得到img1(LOGO)图像的大小,即行数和列数。由此,可以在img2图像上,通过numpy直接划分出与img1图像一样大小的 roi图像(为原图的左上角)。
通过threshold函数可将img1图像二值化,而在这之前需要将img1图像转换为灰度图,才能将其传入。使用 THRESH_BINARY_INV方法将其二值化,二值化图像如下:
将得到的二值化图像(dst1)利用“非”运算,得到的图像如下:
可以发现,进行“非”运算后,对二值图来说,其实即进行了颜色反转。
阈值分割
固定阈值分割
阈值分割简单来说,即大于阈值的变成一种值,小于阈值的为另一种值
在python的cv2库中实现固定阈值分割的为cv2.threshold()函数。
1 | import cv2 as cv |
运行结果如图所示:
cv2.threshold()函数由4个参数组成,img为传入函数的图像,127为设置的阈值大小(threshold),255为阈值设定方式里的阈值最大值(maxval),THRESH_BINARY为阈值设定的方式。
ret代表当前的阈值。
matplotlib.pyplot中subplot(2,3,i+1)即为将窗口分为2行3列,i+1表示当前的第i+1个子图,imshow()则是对图像进行处理,它不会让图片进行显示,图像显示需要show()
阈值设定有5种方法,分别为:
1.THRESH_BINARY:
当原像素值大于阈值,原像素值变为maxval,除此之外为0。
2.THRESH_BINARY_INV:
该阈值方法与上述阈值方法相反,从图像也可以观察得到。
3.THRESH_TOZERO:
当原像素值大于阈值时,原像素值保持不变,除此之外,原像素值变为0。
4.THRESH_TOZERO_INV:
该阈值方法与上述阈值方法相反。
5.THRESH_TRUNC:
放原像素值大于阈值,则原像素值变为阈值,除此之外,原像素值保持不变。