计算机视觉之OpenCV中的图像处理2(18章-20章)
程序员文章站
2023-12-27 08:42:03
...
导入所需的库
import cv2
import numpy as np
import matplotlib.pyplot as plt
for i in [cv2, np]:
print(i.__name__,": ",i.__version__,sep="")
输出:
cv2.cv2: 4.2.0
numpy: 1.17.4
# 定义图像显示函数
def showImages(original, processed):
plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.imshow(original[:,:,[2,1,0]]) # 由于OpenCV读入的图像是BGR,故在显示时转换成RGB格式
plt.axis("off")
plt.title("Original"+": "+str(original.shape))
plt.subplot(1,2,2)
plt.imshow(processed[:,:,[2,1,0]])
plt.axis("off")
plt.axis("off")
plt.title("Processed"+": "+str(processed.shape))
plt.tight_layout()
plt.show()
18. 图像梯度
梯度简单来说就是求导,OpenCV中提供三种不同的梯度滤波器:Sobel,Scharr和Laplacian。其中前两个求一阶导或二阶导,Scharr是对Sobel的优化,Laplacian求二阶导。
学习函数:cv2.Sobel(), cv2.Schar(), cv2.Laplacian()等
18.1 Sobel算子和Scharr算子
img = cv2.imread("4.jpg")
laplacian = cv2.Laplacian(img, cv2.CV_64F)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)
showImages(img, laplacian)
showImages(img, sobelx)
showImages(img, sobely)
输出:
输出图片的深度不同造成的不同效果:
sobelx8u = cv2.Sobel(img, cv2.CV_8U,1,0,ksize=5)
sobelx64f = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
showImages(img, sobelx8u)
showImages(img, sobel_8u)
输出:
19. 边缘检测
学习函数:cv2.Canny()
19.1 原理
Canny边缘检测是一种非常流行的边缘检测算法,该算法由很多步构成。
- 噪声去除:由于边缘检测很容易受到噪声影响,因此第一步使用5*5的高斯滤波器去除噪声。
- 计算图像梯度: 对平滑后的图像使用Sobel算子计算水平方向和竖直方向的一阶导数,根据得到的两幅梯度图找到边界的梯度和方向。梯度的方向总是与边界垂直,梯度的方向归为四类:垂直、水平和两个对角线。
- 非极大值抑制:获得梯度的方向和大小后,对整幅图像做扫描,去除那些非边界上的点。
- 确定那些边界才是真正的边界。
19.2 OpenCV中的Canny边界检测
cv2.Canny()函数:
- 参数1:输入图像
- 参数2和参数3:minVal和maxVal
- 参数4:Sobel卷积核大小,默认为3
- 参数5:L2gradient,默认为False
img = cv2.imread("messi5.jpg")
edges = cv2.Canny(img, 100, 600)
showImages(img ,edges)
输出:
20. 图像金字塔
学习函数:cv2.pyrUp(), cv2.pyrDown()
20.1 原理
图像金字塔:同一图像的不同分辨率的子图集合。如果把分辨率最大的放在底部,最小的放在顶部,看起来就像一座金子塔。图像金字塔分为两类:高斯和拉普拉斯。
- 高斯金字塔:顶部是由底部图像中连续行和列去除得到的。即顶部图像中的每个像素值等于下一层图像中5个像素的高斯加权平均值。
- 拉普拉斯:看起来像边界图,其中很多像素是0,经常被用在图像压缩中。
lower_reso = cv2.pyrDown(img)
higher_reso = cv2.pyrUp(img)
showImages(img, lower_reso)
showImages(img, higher_reso)
输出:
注意:输出图像的分辨率增大一倍或减少一倍。
higher_reso2 = cv2.pyrUp(lower_reso)
showImages(img, higher_reso2)
输出:
上述输出过程:首先对原图进行Down,分辨率降为一半,再进行Up,分辨率升为一倍。最终得到的图像与原图分辨率大小一样,但很明显图像已经变得很模糊了,这是因为在Down的过程中信息有丢失。
20.2 使用金字塔进行图像融合
步骤:
- 读入苹果和橘子两幅图像
- 构建苹果和橘子的高斯金字塔(6层)
- 根据高斯金字塔计算拉普拉斯金字塔
- 在拉普拉斯的每一层进行图像融合
- 根据融合后的图像金字塔重建原始图像
# 读入两幅图像
A, B = cv2.imread("apple.jpg"), cv2.imread("orange.jpg")
# 构建高斯金字塔
G = A.copy()
gpA = [G]
for i in range(6):
G = cv2.pyrDown(G)
gpA.append(G)
G = B.copy()
gpB = [G]
for i in range(6):
G = cv2.pyrDown(G)
gpB.append(G)
# 计算拉普拉斯金字塔
lpA = [gpA[5]]
for i in range(5,0,-1):
GE = cv2.pyrUp(gpA[i])
L = cv2.subtract(gpA[i-1],GE)
lpA.append(L)
lpB = [gpB[5]]
for i in range(5,0,-1):
GE = cv2.pyrUp(gpB[i])
L = cv2.subtract(gpB[i-1],GE)
lpB.append(L)
# 拉普拉斯每一层进行融合
LS = []
for la, lb in zip(lpA, lpB):
rows, cols, dpt = la.shape
ls = np.hstack((la[:,0:int(cols/2)],lb[:,int(cols/2):]))
LS.append(ls)
# 重建图像
ls_ = LS[0]
for i in range(1,6):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_, LS[i])
# 直接重建
real = np.hstack((A[:,:int(cols/2)],B[:,int(cols/2):]))
showImages(A, ls_)
showImages(ls_, B)
showImages(A, real)
showImages(real, B)
输出:
可以看到,图像融合的结果比直接拼接在一起的效果要好很多。