【OpenCV图像处理】十四、图像金字塔

来源:互联网 发布:色诺芬经济金融数据库 编辑:程序博客网 时间:2024/05/22 02:34

首先简单介绍一下图像金字塔,下面这段内容来自百科

图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效但概念简单的结构。一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

图像金字塔主要用于图像的分割,是一种用多分辨率来解释图像的有效且概念简单的结构。

图像金字塔一开始主要用于机器视觉和图像压缩方面,图像金字塔的底部是待处理图像的高分辨率表示,顶部是低分辨率的近似

一般情况下主要有两种类型的图像金字塔常常应用在图像处理领域。他们分别是

·高斯金字塔(Gaussian pyramid):主要用来进行下采样,是主要的图像金字塔。

·拉普拉斯金字塔(Laplacian pyramid):主要用来从金字塔底层图像重建上层未采样图像,在数字图像处理中也就是预测残差,可以用于对图像进行最大程度的还原,配合高斯金字塔一起使用。

二者的区别在于:

高斯金字塔用来向下降采样图像,而拉普拉斯金字塔则用来从底层图像中向上采样,重建一个图像。

1.高斯金字塔:

高斯金字塔的生成过程包含高斯卷积和下采样的过程,设源图像为G0(x,y),分辨率为MxN,G0表示的是高斯金字塔的最底层为第0层,也就是和源图像相同。为了得到高斯金字塔层数G i+1 图像,首先对源图像Gi进行高斯内核卷积,然后删除所有偶数行和偶数列。从而新得到的图像面积是源图像的四分之一。常用的高斯核函数δ如下所示:


高斯金字塔向下减少的方式如下:


其中对于层级i,Gi=Reduce[Gi-1],w(m, n)为生成核,窗口函数是一个低通滤波器,上述对生成核的限制是为了既能保证低通的性质,又能保持图像缩扩后的亮度平滑,不出现边界缝隙。通过上式可以看出,图像高斯金字塔是对下一层进行低通滤波后再进行隔行列采样得到的。

我们可以看到,向下取样会逐渐丢失图像的信息。

如果这个过程想放大图像,则需要通过向上取样操作得到,具体做法如下:

a.将图像在每个方向扩大为原来的2倍,新增的行和列用0进行填充

b.使用先前同样的内核(乘以4)与放大后的图像进行卷积,获得“新增像素”的近似值

通过上面的两个步骤就可以得到放大的图像,但是和源图像相比会发觉图像变得比较模糊,因为在缩放的过程中已经丢失了一些信息。如果想在缩小和放大整个过程中减少信息的丢失,这些数据就形成了拉普拉斯金字塔


2.拉普拉斯金字塔

拉普拉斯金字塔实现图像向上重建,对Gi进行内插得到放大图像Gi*,使Gi*的尺寸与Gi-1的尺寸相同,可以表示为下式:


其中i的取值范围是(0,N),x的取值范围是[0,M),y的取值范围是[0, N)。对于上式中的Gi*[(x+m)/2,(y+n)/2],当(x+m)/2与(y+n)/2为整数时可变换为Gi[(x+m)/2,(y+n)/2],在其他情况时为0。

通过上面的插值运算可以将金字塔的第i级扩大到i-1级同尺度,可定义为当i取值范围是[0,N)满足LPi = Gi - G*i+1,当i=N时满足LP N=GN,N为拉普拉斯金字塔塔顶的层号,LPi是拉普拉斯金字塔分解的第i层图像。

拉普拉斯金字塔实际上就是高斯金字塔与其上一层通过插值扩大后的插值图像,上层图像是下层低通滤波后通过下采样得到的,扩大后与原级的插值反映的是高斯金字塔两级间的信息差,这个步骤类似于带通滤波,最终拉普拉斯金字塔也表示出同级高斯金字塔的高频分量(细节部分)。

综上,也就是说,拉普拉斯金字塔是通过源图像减去先缩小后再放大的图像的一系列图像构成的。

所以,可以将拉普拉斯金字塔理解为高斯金字塔的逆形式。

在介绍OpenCV中相关函数之前,还要说明一点,关于图像金字塔非常重要的一个应用是图像分割,图像分割要先建立一个图像金字塔,然后对Gi和Gi+1的像素直接依照对应的关系,建立起“父与子”的关系。而快速初始分割可以现在金字塔高层的低分辨率图像上完成,然后逐层对分割加以优化。


3.OpenCV中图像金字塔相关函数

在OpenCV中对图像金字塔的实现主要是pyrUp, pyrDown这一对函数分别用来进行上采样和下采样。下面分别进行介绍。

(a.向上采样:pyrUp()函数

pyrUp()函数的作用是向上采样并模糊一张图像,也就是对一张图片进行放大。函数的声明如下:

void pyrUp( InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT );
第一个参数src指的是源图像,使用Mat类的对象即可

第二个参数dst指的是输出图像,和源图像有一样的尺寸和类型

第三个参数dstsize,指的是输出图像的大小,有默认值Size(),也就是默认情况下,由Size(src.cols*2, src.rows*2)来进行计算,而且一直需要满足下面的条件

| dstsize.width - src.cols*2 | ≦ ( dstsize.width mod 2 )

| dstsize.height - src.rows*2 | ≦ ( dstsize.height mod 2 )

第四个参数boderType表示的是边界模式,一般直接使用默认值即可。
这个函数执行高斯金字塔的采样操作,其实也可以用于乱普拉斯金字塔。

首先,它通过插入可为0的行与列,对源图像进行向上取样操作,然后将结果与pyrDown()乘以4的内核做卷积。

(b.采样:pyrDown()函数

这个函数的作用是向下采样并模糊一张图片,也就是对一张图片进行缩小的操作。函数的声明如下:

void pyrDown( InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT );

第一个参数src指的是源图像,使用Mat类的对象即可

第二个参数dst指的是输出图像,和源图像有一样的尺寸和类型

第三个参数dstsize,指的是输出图像的大小,有默认值Size(),也就是默认情况下,由Size(src.cols/2, src.rows/2)来进行计算,而且一直需要满足下面的条件

| dstsize.width - src.cols*2 | ≦ 2

| dstsize.height - src.rows*2 | ≦ 2

这个函数执行了高斯金字塔建造的向下采样的步骤。首先它将元图像与上面的高斯核函数矩阵进行卷积运算,然后通过对图像的偶数航和列做插值进行向下采样操作。

具体的示例程序如下:

//图像金字塔的相关操作#include <iostream>#include <opencv2\core\core.hpp>#include <opencv2\highgui\highgui.hpp>#include <opencv2\imgproc\imgproc.hpp>using namespace cv;using namespace std;void Pyramid(Mat srcImage);int main(){Mat srcImage = imread("4567.jpg");if (!srcImage.data){cout << "读入图片有误!" << endl;system("pause");return -1;}Pyramid(srcImage);waitKey();return 0;}void Pyramid(Mat srcImage){//根据图像尺寸判断是否需要进行缩放if (srcImage.rows > 400 && srcImage.cols > 400)resize(srcImage, srcImage, Size(), 0.5, 0.5);//缩小为原图像的二分之一else   //不需要进行缩放resize(srcImage, srcImage, Size(), 1, 1);imshow("原图像", srcImage);Mat pyrDownImage, pyrUpImage;//下采样过程pyrDown(srcImage, pyrDownImage, Size(srcImage.cols / 2, srcImage.rows / 2));imshow("下采样图像", pyrDownImage);//上采样过程pyrUp(srcImage, pyrUpImage, Size(srcImage.cols * 2, srcImage.rows * 2));imshow("上采样图像", pyrUpImage);//对下采样过程重构Mat pyrBuildImage;pyrUp(pyrDownImage, pyrBuildImage, Size(pyrDownImage.cols * 2, pyrDownImage.rows * 2));imshow("下采样图像重构后图像", pyrBuildImage);////比较重构后的性能//Mat differentImage;//absdiff(srcImage, pyrBuildImage, differentImage);//imshow("原图像与重构图像作差", differentImage);}

执行后的结果如下:















0 0