目标
学习图像金字塔
使用图像创建一个新水果:“橘子苹果”
将要学习的函数有:
cv2.pyrUp()
,cv2.pyrDown()
。
原理
一般情况下,要处理是一副具有固定分辨率的图像。 但是有些情况下,需要对同一图像的不同分辨率的子图像进行处理。 比如,要在一幅图像中查找某个目标,比如脸,不知道目标在图像中的尺寸大小。 这种情况下,需要创建创建一组图像, 这些图像是具有不同分辨率的原始图像。把这组图像叫做图像金字塔(简单来说就是同一图像的不同分辨率的子图集合)。 如果把最大的图像放在底部,最小的放在顶部,看起来像一座金字塔,故而得名图像金字塔。
有两类图像金字塔:高斯金字塔和拉普拉斯金字塔。
高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。
顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。
这样操作一次一个 MxN 的图像就变成了一个 M/2xN/2 的图像。所以这幅图像的面积就变为原来图像面积的四分之一。
这被称为 Octave。连续进行这样的操作就会得到一个分辨率不断下降的图像金字塔。
可以使用函数 cv2.pyrDown()
和 cv2.pyrUp()
构建图像金字塔。
函数 cv2.pyrDown()
从一个高分辨率大尺寸的图像向上构建一个金子塔(尺寸变小,分辨率降低)。
import cv2
img = cv2.imread('../data/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 0x7f6fdd172720>
下图是一个四层的图像金字塔。
函数 cv2.pyrUp()
从一个低分辨率小尺寸的图像向下构建一个金子塔(尺寸变大,但分辨率不会增加)。
higher_reso2 = cv2.pyrUp(lower_reso)
要记住的是是 higher_reso2
和 higher_reso
是不同的。因为一旦使用 cv2.pyrDown()
,
图像的分辨率就会降低,信息就会被丢失。
下图就是从 cv2.pyrDown()
产生的图像金字塔的(由下到上)第三层图像使用函数 cv2.pyrUp()
得到的图像,与原图像相比分辨率差了很多。
拉普拉斯金字塔可以有高斯金字塔计算得来,公式如下:
拉普拉金字塔的图像看起来就像边界图,其中很多像素都是 0。他们经常被用在图像压缩中。 下图就是一个三层的拉普拉斯金字塔:
使用金字塔进行图像融合
图像金字塔的一个应用是图像融合。例如,在图像缝合中,需要将两幅图叠在一起, 但是由于连接区域图像像素的不连续性,整幅图的效果看起来会很差。这时图像金字塔就可以排上用场了, 他可以帮助实现无缝连接。这里的一个经典案例就是将两个水果融合成一个, 看看下图也许就明白在讲什么了。
可以通过阅读后边的更多资源来了解更多关于图像融合,拉普拉斯金字塔的细节。
实现上述效果的步骤如下:
读入两幅图像,苹果和句子
构建苹果和橘子的高斯金字塔(6 层)
根据高斯金字塔计算拉普拉斯金字塔
在拉普拉斯的每一层进行图像融合(苹果的左边与橘子的右边融合)
根据融合后的图像金字塔重建原始图像。
下图是摘自《学习 OpenCV》展示了金子塔的构建,以及如何从金字塔重建原始图像的过程。 整个过程的代码如下。(为了简单,每一步都是独立完成的,这回消耗更多、的内存, 如果愿意的话可以对他进行优化)
import cv2
from matplotlib import pyplot as plt
import numpy as np,sys
A = cv2.imread('apple.png')
B = cv2.imread('orange.png')
#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)
#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)
#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:cols/2], lb[:,cols/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.hstack((A[:,:cols/2],B[:,cols/2:]))
plt.subplot(121),plt.imshow(ls_)
plt.subplot(122),plt.imshow(real)
cv2.imwrite('Pyramid_blending2.jpg',ls_)
cv2.imwrite('Direct_blending.jpg',real)
--------------------------------------------------------------------------- error Traceback (most recent call last) Cell In[2], line 30 28 for i in range(5,0,-1): 29 GE = cv2.pyrUp(gpA[i]) ---> 30 L = cv2.subtract(gpA[i-1],GE) 31 lpA.append(L) 33 #generate Laplacian Pyramid for B error: OpenCV(4.11.0) /home/conda/feedstock_root/build_artifacts/libopencv_1739279453154/work/modules/core/src/arithm.cpp:662: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function 'arithm_op'