3.8. 影像金字塔

3.8.1. 目标

在本章中,
-我们将学习图像金字塔-我们将使用图像金字塔创建新的水果“oraapple”-我们将看到以下功能: pyrUp()pyrDown()

3.8.2. 理论

通常情况下,我们使用的是恒定大小的图像。但在某些情况下,我们需要处理同一图像的不同分辨率的图像。例如,在搜索图像中的某个对象(如面)时,我们不确定对象在图像中的大小。在这种情况下,我们需要创建一组分辨率不同的图像,并在所有图像中搜索对象。这些具有不同分辨率的图像集合称为图像金字塔(因为当它们被保存在一个堆栈中,最大的图像在底部,最小的图像在顶部看起来像一个金字塔)。

有两种图像金字塔。1) 高斯金字塔和2)拉普拉斯金字塔

高斯金字塔中的高阶(低分辨率)是通过移除低阶(高分辨率)图像中的连续行和列而形成的。然后,利用高斯权重对底层5个像素的贡献,形成上层的每个像素。这样做,a \(M \times N\) 图像变成 \(M/2 \times N/2\) 形象。所以面积减少到原来面积的四分之一。它被称为八度音阶。同样的模式继续,因为我们走上金字塔(即,分辨率下降)。同样地,在扩展时,每个级别的面积变为4倍。我们可以使用 pyrDown()pyrUp() 功能。

>>> import cv2
>>> img = cv2.imread('/cvdata/messi5.jpg')
>>> higher_reso = 4
>>> lower_reso = cv2.pyrDown(higher_reso)
>>> %matplotlib inline
>>> import matplotlib.pyplot as plt
>>> plt.imshow(lower_reso)
<matplotlib.image.AxesImage at 0x7fa390229f28>
../_images/sec08-pyramids_2_1.png

下面是图像金字塔中的4个级别。

现在你可以用 pyrUp() 功能。

>>> higher_reso2 = cv2.pyrUp(lower_reso)

记得, \(higher_reso2\) 不等于 \(higher_reso\) ,因为一旦降低分辨率,就会丢失信息。下图是前一种情况下从最小图像创建的金字塔的3层。将其与原始图像进行比较:

拉普拉斯金字塔是由高斯金字塔形成的。这没有排他性的功能。拉普拉斯金字塔图像只是边缘图像。它的大部分元素都是零。它们用于图像压缩。拉普拉斯金字塔中的一个级别是由高斯金字塔中的该级别与其在高斯金字塔中的上层扩展版本之间的差异形成的。拉普拉斯等级的三个等级如下所示(调整对比度以增强内容):

3.8.3. 使用金字塔的图像混合

金字塔的一个应用是图像混合。例如,在图像拼接中,需要将两个图像堆叠在一起,但由于图像之间的不连续性,这可能看起来不太好。在这种情况下,图像与金字塔的混合可以让您无缝地混合,而不会在图像中留下太多数据。一个典型的例子是两种水果,橘子和苹果的混合。现在就看结果来理解我的意思:

请检查附加资源中的第一个参考,它有关于图像混合、拉普拉斯金字塔等的完整的图解细节。简单地说,它如下所示:

  1. 加载苹果和橘子的两个图像

  2. 找到apple和orange的高斯金字塔(在这个特殊的例子中,层数是6)

  3. 从高斯金字塔,找到他们的拉普拉斯金字塔

  4. 现在加入到拉普拉斯金字塔的左半部分苹果和右半部分橘子中

  5. 最后从这个联合图像金字塔中,重建出原始图像。

下面是完整的代码。(为了简单起见,每一步都是分开进行的,这可能会占用更多的内存。你可以优化它,如果你想的话)。

>>> import cv2 as cv
>>> import numpy as np,sys
>>>
>>> A = cv2.imread('/cvdata/apple.jpg')
>>> B = cv2.imread('/cvdata/orange.jpg')
>>>
>>>
>>> # generate Gaussian pyramid for A
>>> G = A.copy()
>>> gpA = [G]
>>> for i in range(6):
>>>     G = cv.pyrDown(G)
>>>     gpA.append(G)
>>> # generate Gaussian pyramid for B
>>> G = B.copy()
>>> gpB = [G]
>>> for i in range(6):
>>>     G = cv.pyrDown(G)
>>>     gpB.append(G)
>>> # generate Laplacian Pyramid for A
>>> lpA = [gpA[5]]
>>> for i in range(5,0,-1):
>>>     GE = cv.pyrUp(gpA[i])
>>>     L = cv.subtract(gpA[i-1],GE)
>>>     lpA.append(L)
>>> # generate Laplacian Pyramid for B
>>> lpB = [gpB[5]]
>>> for i in range(5,0,-1):
>>>     GE = cv.pyrUp(gpB[i])
>>>     L = cv.subtract(gpB[i-1],GE)
>>>     lpB.append(L)
>>> # Now add left and right halves of images in each level
>>> 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)
>>> # now reconstruct
>>> ls_ = LS[0]
>>> for i in range(1,6):
>>>     ls_ = cv.pyrUp(ls_)
>>>     ls_ = cv.add(ls_, LS[i])
>>> # image with direct connecting each half
>>> real = np.hstack((A[:,:int(cols/2)],B[:,int(cols/2):]))
>>> cv.imwrite('xx_Pyramid_blending2.jpg',ls_)
>>> cv.imwrite('xx_Direct_blending.jpg',real)
True

3.8.4. 额外资源

  1. Image Blending

3.8.5. 练习