一般情况下,我们要处理是一副具有固定分辨率的图像。但是有些情况下,我们需要对同一图像的不同分辨率的子图像进行处理。比如,我们要在一幅图像中查找某个目标,比如脸,我们不知道目标在图像中的尺寸大小。这种情况下,我们需要创建创建一组图像,这些图像是具有不同分辨率的原始图像。我们把这组图像叫做图像金字塔(简单来说就是同一图像的不同分辨率的子图集 合)。如果我们把最大的图像放在底部,最小的放在顶部,看起来像一座金字塔,故而得名图像金字塔。
有两类图像金字塔:高斯金字塔和拉普拉斯金字塔。
高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。这样 操作一次一个 MxN 的图像就变成了一个 M/2 x N/2 的图像。所以这幅图像的面积就变为原来图像面积的四分之一。这被称为 Octave。连续进行这样的操作我们就会得到一个分辨率不断下降的图像金字塔。我们可以使用函数 cv2.pyrDown() 和 cv2.pyrUp() 构建图像金字塔。
函数 cv2.pyrDown() 从一个高分辨率大尺寸的图像向上构建一个金子塔(尺寸变小,分辨率降低)。
img = cv2.imread('cat1.jpg')
lower_reso = cv2.pyrDown(img)
cv2.imshow("img", img)
cv2.imshow("img1", lower_reso)
cv2.waitKey(0)
cv2.destroyAllWindows()
函数cv2.pyrUp()从一个低分辨率小尺寸的图像向下构建一个金子塔(尺寸变大,但分辨率不会增加)。
higher_reso = cv2.pyrUp(lower_reso)
cv2.imshow("img", img)
cv2.imshow("img1", lower_reso)
cv2.imshow("img2", higher_reso)
cv2.waitKey(0)
cv2.destroyAllWindows()
higher_reso 和 img 是不同的。因为一旦使用 cv2.pyrDown(),图像的分辨率就会降低,信息就会被丢失。下图就是从 cv2.pyrDown() 产生的图像金字塔的(由下到上)第二层图像使用函数 cv2.pyrUp() 得到的图像,与原图像相比清晰度差了很多。
拉普拉斯金字塔可以有高斯金字塔计算得来,公式如下:
拉普拉金字塔的图像看起来就像边界图,其中很多像素都是 0。他经常被用在图像压缩中。下图就是一个三层的拉普拉斯金字塔:
图像金字塔的一个应用是图像融合。例如,在图像缝合中,你需要将两幅图叠在一起,但是由于连接区域图像像素的不连续性,整幅图的效果看起来会很差。这时图像金字塔就可以排上用场了,他可以帮你实现无缝连接。这里的一个经典案例就是将两个水果融合成一个。
A = cv2.imread('orange.jpg')
B = cv2.imread('apple.jpg')
# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in range(6):
G = cv2.pyrDown(G)
gpA.append(G)
# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in range(6):
G = cv2.pyrDown(G)
gpB.append(G)
# generate Laplacian Pyramid for A
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)
u = gpA[i-1]
v = GE
# generate Laplacian Pyramid for B
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)
# 把金字塔的每一层图像都上下拼接
#Take a sequence of arrays and stack them horizontally
#to make a single array.
LS = []
for la,lb in zip(lpA,lpB):
rows,cols,dpt = la.shape
ls = np.vstack((la[0:round(rows/2),:], lb[round(rows/2):,:]))
LS.append(ls)
# now reconstruct
ls_ = LS[0]
for i in range(1,6):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_, LS[i])
# image with direct connecting each half
real = np.vstack((A[:round(rows/2),:],B[round(rows/2):,:]))
cv2.imwrite('Pyramid_blending2.jpg',ls_)
cv2.imwrite('Direct_blending.jpg',real)
结果如下,左图是直接拼接,右图是用金字塔拼接,由于大小没有调整好所以还是有些许不和谐