一、关于图像金字塔
以多个分辨率来表示图像的一种有效且概念简单的结构是图像金字塔,一个图像金字塔是一系列以金子塔形状排列的、分辨率逐渐降低的图像集合。——《数字图像处理》。
图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔性质排列的分辨率逐步降低,且来源同一张原始图的图像集合。
其通过梯次向下采样获得,直到达到某个终止条件才停止采样。
金字塔的底部是待处理的图像的高分辨率表示,而顶部是低分辨率的近似。
我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。
通常有两种类型的图像金字塔,分别是:
高斯金字塔(Gaussianpyramid):用来向下采样,主要的图像金字塔。
拉普拉斯金字塔(Laplacianpyramid): 用来从金字塔底层图像重建上层未采样的还原,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用,是从金字塔底层图像向上采样,重建一个图像。
二、原理
2.1 高斯金字塔
高斯金字塔是通过高斯模糊和下采样获得一系列采样图像,也就是说第K层高斯金字塔通过模糊,下采样就可以获得第K+1层高斯图像,高斯金字塔包含了一系列低通滤波器,其截止频率从上一层到下一层是以因子2逐渐增加,所以高斯金字塔就可以跨越很大的频率范围,金字塔的图像如下:
每一层都按从下到上的次序编号,层级G_i+1(表示为G_i+1尺寸小于第i层 G_i)。
为了获取层级为G_i+1的金字塔图像,我们采用如下方法:
1、对图像 G_i 进行高斯内核卷积
2、将所有的偶数行和列去除
得到的图像即为 G_i+1 的图像,显而易见,结果图像只有上一层图像的四分之一。通过对输入图像 G_i(原始图像)不停迭代以上步骤就能得到整个金字塔。同时我们也可以看到,向下采样会逐渐丢失图像的信息。
上面就是对图像的向下取样操作,缩小图像,如果想放大图像,则需要通过向上采样操作得到,具体做法如下:
1、将图像在每个方向扩大为原来的两倍,新增的行和列以 0 填充
2、使用先前同样的内核(乘以4)与放大后的图像卷积,获得“新增图像”的近似值
得到的图像即为放大后的图像,但是与原来的图像相比会发现比较模糊,因为在缩放的过程中已经丢失了一些信息,如果想在缩小和放大整个过程中减少信息的丢失,那么就需要用到拉普拉斯金字塔。
2.2拉普拉斯金字塔
下式是拉普拉斯金字塔第i层的数学定义:
式中的 Gi 表示第i层的图像。而UP()操作是将源图像中位置为(x, y)的像素映射到目标图像的(2x+1, 2y+1)位置,即在进行向上取样。符号叉表示卷积,G5x5 为5x5的高斯内核。
我们可以直接用OpenCV进行拉普拉斯运算:
也就是说,拉普拉斯金字塔就是通过源图像减去先缩小后再放大的图像的一系列图像构成的。
整个拉普拉斯金字塔运算过程可以通过下图来概括:
所以,我们可以将拉普拉斯金字塔理解为高斯金字塔的逆形式。
另外再提一点,关于图像金字塔非常重要的一个应用就是实现图像分割。图像分割的话,先要建立一个图像金字塔,然后在G_i和G_i+1的像素直接依照对应的关系,建立起”父与子“关系。而快速初始分割可以先在金字塔高层的低分辨率图像上完成,然后逐层对分割加以优化。
三、代码实现
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#下采样
def pyramid_down_demo(img):
level = 3 # 迭代次数
temp = img.copy()
pyramid_down_imgs = [] # 存放图像
for i in range(level):
dst = cv.pyrDown(temp)
'''
pyrDown(src, dst=None, dstsize=None, borderType=None)
dstsize: 目标图像的大小,默认为 ((cols+1)/2, (rows+1)/2),在任何情况下,下面的条件都必须满足:
|dstsize.width * 2 - src.cols|<=2
|dstsize.height * 2 - src.rows|<=2
'''
pyramid_down_imgs.append(dst)
cv.imshow('pyramid_down_'+str(i), dst)
temp = dst
return pyramid_down_imgs
#上采样
def pyramid_up_demo(img):
pyramid_down_imgs = pyramid_down_demo(img)
level = len(pyramid_down_imgs)
for i in range(level-1, -1, -1):
if (i-1) < 0:
expand = cv.pyrUp(pyramid_down_imgs[i], dstsize=img.shape[:2])
'''
pyrUp(src, dst=None, dstsize=None, borderType=None)
src: 源图像
dst: 目标图像,和源图像有同样的大小和类型
dstsize: 目标图像的大小,默认为(src.cols*2, src.rows*2) ,在任何情况下,下面的条件都必须满足:
|dstsize.width - src.cols*2|<=(dstsize.width % 2)
|dstsize.height - src.rows*2|<=(dstsize.height % 2)
'''
lpls = cv.subtract(img, expand)
# 用源图像减去先缩小再放大的图像 得到拉普拉斯金字塔
cv.imshow('pyramid_up_'+str(i), lpls)
else:
expand = cv.pyrUp(pyramid_down_imgs[i], dstsize=pyramid_down_imgs[i-1].shape[:2])
lpls = cv.subtract(pyramid_down_imgs[i-1], expand)
# 用源图像减去先缩小再放大的图像 得到拉普拉斯金字塔
cv.imshow('pyramid_up_'+str(i), lpls)
img = cv.imread('img/lena.png')
cv.namedWindow('img',cv.WINDOW_AUTOSIZE)
cv.imshow('img',img)
pyramid_up_demo(img)
cv.waitKey(0)
cv.destroyAllWindows()
具体效果:
高斯金字塔:
上采样效果:
拉普拉斯金字塔: