一,图像金字塔

解释:

图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。

图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。

金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。

我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

 

一般情况下有两种类型的图像金字塔常常出现在文献和以及实际运用中。他们分别是:

  • 高斯金字塔(Gaussianpyramid): 用来向下采样,高斯金字塔的顶部是通过将底部图像中的连续的行和列(一般为偶数)去除得到的。顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。这样 操作一次一个 MxN 的图像就变成了一个 M/2xN/2 的图像。所以这幅图像的面积就变为原来图像面积的四分之一。这被称为an Octave(一个八度)。连续进行这样的操作就会得到一个分辨率不断下降的图像金字塔。

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

下式是拉普拉斯金字塔第i层的数学定义:

 

式中的表示第i层的图像。而UP()操作是将源图像中位置为(x,y)的像素映射到目标图像的(2x+1,2y+1)位置,即在进行向上取样。符号表示卷积,为5x5的高斯内核。

我们下文将要介绍的pryUp,就是在进行上面这个式子的运算。

因此,我们可以直接用OpenCV进行拉普拉斯运算:

 

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

整个拉普拉斯金字塔运算过程可以通过下图来概括:

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

另外再提一点,关于图像金字塔非常重要的一个应用就是实现图像分割。图像分割的话,先要建立一个图像金字塔,然后在G_i和G_i+1的像素直接依照对应的关系,建立起”父与子“关系。而快速初始分割可以先在金字塔高层的低分辨率图像上完成,然后逐层对分割加以优化。

高斯金字塔的作用(通俗):

整个高斯金字塔,或者说是差分高斯金字塔是我们确定SIFT特征的基础,让我们首先想想高斯金字塔到底干了一件什么事情,他到底模仿的是什么?答案很容易确定,高斯金字塔模仿的是图像的不同的尺度,尺度应该怎样理解?对于一副图像,你近距离观察图像,与你在一米之外观察,看到的图像效果是不同的,前者比较清晰,后者比较模糊,前者比较大,后者比较小,通过前者能看到图像的一些细节信息,通过后者能看到图像的一些轮廓的信息,这就是图像的尺度,图像的尺度是自然存在的,并不是人为创造的。好了,到这里我们明白了,其实以前对一幅图像的处理还是比较单调的,因为我们的关注点只落在二维空间,并没有考虑到“图像的纵深”这样一个概念,如果将这些内容考虑进去我们是不是会得到更多以前在二维空间中没有得到的信息呢?于是高斯金字塔横空出世了,它就是为了在二维图像的基础之上,榨取出图像中自然存在的另一个维度:尺度。因为高斯核是唯一的线性核,也就是说使用高斯核对图像模糊不会引入其他噪声,因此就选用了高斯核来构建图像的尺度

 

对图像的向下取样

为了获取层级为 G_i+1 的金字塔图像,我们采用如下方法:

<1>对图像G_i进行高斯内核卷积

<2>将所有偶数行和列去除

得到的图像即为G_i+1的图像,显而易见,结果图像只有原图的四分之一。通过对输入图像G_i(原始图像)不停迭代以上步骤就会得到整个金字塔。同时我们也可以看到,向下取样会逐渐丢失图像的信息。

以上就是对图像的向下取样操作,即缩小图像。

pyrUp(img, dst, Size(img.cols*2, img.rows*2)); //放大一倍

对图像的向上取样

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

<1>将图像在每个方向扩大为原来的两倍,新增的行和列以0填充

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

得到的图像即为放大后的图像,但是与原来的图像相比会发觉比较模糊,因为在缩放的过程中已经丢失了一些信息,如果想在缩小和放大整个过程中减少信息的丢失,这些数据形成了拉普拉斯金字塔。

pyrDown(img, dst2, Size(img.cols * 0.5, img.rows * 0.5)); //缩小为原来的一半

二,图像缩放

两种标准使用方法:

Mat dst = Mat::zeros(512, 512, CV_8UC3); //我要转化为512*512大小的
resize(img, dst, dst.size());

Mat dst;
resize(img, dst, Size(),0.5,0.5);//我长宽都变为原来的0.5倍

 

三,代码展示

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
	Mat src1, src2, dst;
	src1 = imread("C:\\Users\\马迎伟\\Desktop\\douyin.jpg");
	if (src1.empty())
	{
		cout << "could not find src1" << endl;
	}
	namedWindow("input",CV_WINDOW_AUTOSIZE);
	imshow("input",src1);

	//上采样(高斯模糊-->填0 高斯填充)
	pyrUp(src1,src2,Size(2*src1.cols,2*src1.rows));
	imshow("上采样",src2);

	//下采样 (删除偶数行列)
	pyrDown(src1,dst,Size(src1.cols/2,src1.rows/2));
	imshow("下采样",dst);

	//DOG
	Mat DOGimg,g1,g2 ;
	GaussianBlur(src1,g1,Size(3,3),0,0);
	GaussianBlur(g1,g2,Size(3,3),0,0);
	subtract(g1,g2,DOGimg,Mat());
	//对DOGimg进行归一化操作
	normalize(DOGimg, DOGimg, 255, 0, NORM_MINMAX);
	imshow("DOG image", DOGimg);
	waitKey(0);
	return 0;
}