OpenCV入门(二十一)快速学会OpenCV 20 图像金字塔
作者:Xiou
1.基本概念
一般情况下,我们要处理的是一幅具有固定分辨率的图像。有些情况下,我们需要对同一图像的不同分辨率的子图像进行处理。比如,我们要在一幅图像中查找某个目标(比如脸),但是不知道目标在图像中的尺寸大小。在这种情况下,我们需要创建一组图像,这些图像是具有不同分辨率的原始图像。
我们把这组图像叫作图像金字塔(简单来说就是同一图像的不同分辨率的子图集合)。如果我们把最大的图像放在底部、最小的放在顶部,看起来就像一座金字塔,故而得名图像金字塔,如图所示。
图像金字塔是以多个分辨率来表示图像的一种有效且概念简单的结构。图像金字塔最初用于机器视觉和图像压缩。一个图像金字塔是一系列以金字塔形状排列的、分辨率逐步降低的图像集合。
图像金字塔可以通过梯次向下采样获得,直至达到某个终止条件才停止采样;在向下采样中,层级越高,图像越小,分辨率越低。
图像金字塔有两种:第一种是高斯金字塔(Gaussian pyramid),第二种是拉普拉斯金字塔(Laplacian pyramid)。
高斯金字塔用来向下采样,是主要的图像金字塔。
拉普拉斯金字塔用来从金字塔底层图像重建上层未采样的图像,在数字图像处理中也就是预测残差,可以对图像进行最大限度的还原,配合高斯金字塔一起使用。
两者的区别是:高斯金字塔用来向下降采样图像,拉普拉斯金字塔用来从金字塔底层图像中向上采样重建一个图像。
2.高斯金字塔
高斯金字塔是由底部的最大分辨率图像逐次向下采样得到的一系列图像。最下面的图像分辨率最高,越往上图像分辨率越低。
高斯金字塔的向下采样过程是:对于给定的图像先做一次高斯平滑处理,也就是先对原始图像进行高斯内核卷积操作,然后对图像进行采样,去除图像中的偶数行和偶数列,然后得到一幅图像,对这幅图像再进行上述操作,就可以得到高斯金字塔。
2.1 向下取样
在图像向下取样中,一般分两步:
(1)对图像Gi进行高斯卷积核(高斯滤波)。
(2)删除所有的偶数行和列,如图所示:
其中,高斯核卷积运算(高斯滤波)就是对整幅图像进行加权平均的过程,每一个像素点的值都由其本身和邻域内的其他像素值(权重不同)经过加权平均后得到。常见的3×3和5×5高斯核如图所示。
假设原始图像Gi具有M×N个像素,进行向下取样之后所得到的图像Gi+1具有M/2×N/2个像素,只有原图的1/4。
通过对输入的原始图像不停迭代以上步骤,就会得到整个金字塔。
在OpenCV中,向下取样使用的函数为pyrDown(),函数声明如下:
pyrDown(src,dst = None,dstsize = None, borderType = None)
其中,参数
src表示输入图像;
dst表示输出图像(和输入图像具有一样的尺寸和类型);
dstsize表示输出图像的大小,默认值为Size();
borderType表示像素外推方法(仅支持BORDER_DEAFULT)。
代码实例一:
import cv2 as cv
img = cv.imread(r"test.jpg")
down=cv.pyrDown(img) #图像向下取样
cv.imshow("original", img); #显示图像
cv.imshow("PyrDown", down);
cv.waitKey(0);
cv.destroyAllWindows(); #销毁所有窗口
在上述代码中,使用函数pyrDown进行了向下取样。可以看到,pyrDown函数的使用非常简单。
输出结果:
代码实例一是对图像一次向下取样,下面再看一个对图像多次向下取样的例子。
代码实例二:
import cv2 as cv
img = cv.imread(r"img.jpg")
r1=cv.pyrDown(img);
r2=cv.pyrDown(r1);
r3=cv.pyrDown(r2);
cv.imshow("PyrDown1", r1);
cv.imshow("PyrDown2", r2);
cv.imshow("PyrDown3", r3);
cv.waitKey(0);
cv.destroyAllWindows(); #销毁所有窗口
输出结果:
2.2 向上取样
图像向上取样是由小图像不断放大图像的过程。它将图像在每个方向上扩大为原图像的2倍,新增的行和列均用0来填充,并使用与“向下取样”相同的卷积核乘以4,再与放大后的图像进行卷积运算,以获得“新增像素”的新值。值得注意的是,放大后的图像比原始图像要模糊。例如,在原始像素45、123、89、149之间新增一行和一列值为0的像素,如图所示。
在OpenCV中,向上取样使用pyrUp函数,其函数声明如下:
pyrUp (src,dst = None,dstsize = None, borderType = None)
其中,参数
src表示输入图像;
dst表示输出图像(和输入图像具有一样的尺寸和类型);
dstsize表示输出图像的大小,默认值为Size();
borderType表示像素外推方法。
代码实例:
import cv2 as cv
img = cv.imread(r"img.jpg")
r1=cv.pyrDown(img);
r2=cv.pyrUp(r1);
cv.imshow("PyrDown1", r1);
cv.imshow("PyrDown2", r2);
cv.waitKey(0);
cv.destroyAllWindows(); #销毁所有窗口
在上述代码中,我们先对一幅图像做向下取样,再进行向上取样,可以发现向上取样后图像变模糊了。
输出结果:
3.拉普拉斯金字塔
拉普拉斯金字塔可以从高斯金字塔计算得来,拉普拉斯金字塔主要应用于图像融合。在OpenCV 4版本中,拉普拉斯金字塔位于imgproc模块的Image Filtering子模块中。
拉普拉斯金字塔是高斯金字塔的修正版,可以通过计算残差图来还原到原图。拉普拉斯金字塔第i层的数学定义如下:
在OpenCV中,拉普拉斯金字塔的函数原型如下:
Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
其中,参数
src表示原图;
dst表示目标图像;
ddepth表示目标图像的深度;
ksize表示用于计算二阶导数滤波器的孔径大小,必须为正数和奇数;
scale用于计算拉普拉斯值的可选比例因子,默认情况下,不应用缩放;
delta表示在将结果存储到dst之前添加到结果中的可选增量值;
borderType用于决定在图像发生几何变换或者滤波操作(卷积)时边沿像素的处理方式。
代码实例:
import cv2 as cv
import numpy as np
# 拉普拉斯算子
def Laplace_demo(image):
dst = cv.Laplacian(image, cv.CV_32F)
lpls_1 = cv.convertScaleAbs(dst)
cv.imshow("Laplace_1", lpls_1)
# 自定义拉普拉斯算子
kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]])
dst = cv.filter2D(image, cv.CV_32F, kernel)
lpls_2 = cv.convertScaleAbs(dst)
cv.imshow("Laplace_2", lpls_2)
if __name__ == "__main__":
src = cv.imread(r"img.jpg")
src = cv.resize(src, None, fx=0.5, fy=0.5)
cv.imshow("image", src)
Laplace_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
在上述代码中,我们先利用函数Laplacian进行了拉普拉斯边缘计算,然后实现了自定义拉普拉斯算子。
输出结果: