OpenCV4学习笔记(18)——图像金字塔及拉普拉斯金字塔

本次要整理记录的内容是关于图像金字塔的部分知识,主要分为高斯图像金字塔以及拉普拉斯金字塔两种。

  • (高斯)图像金字塔
    图像金字塔是指将一幅图像变换为不同的尺寸,并从底部到顶部按照图像尺寸从大到小的顺序排列,形成的金字塔状的图像集。构建图像金字塔时,首先对一张输入图像进行高斯模糊再进行下采样为原来尺寸大小的1/4(高、宽均缩小为原来的二分之一),这部分操作也称为reduce操作:从原图生成高斯金字塔图像、生成一系列低分辨率图像;每一层图像大小,是前一层的1/4;每一层图像的高和宽,都是前一层的1/2,除去了前一层的偶数行和列。
    然后不断重复地高斯模糊与下采样的过程,最终得到了不同分辨率的多张输出图像,将这些输出图像叠加在一起形成自底而上、从大到小的图像集,这就构建出了一个图像金字塔。所以图像金字塔是一幅图像的空间多分辨率存在形式。
    由于每次生成一层图像时都会进行高斯模糊,所以也将图像金字塔称为高斯图像金字塔。在生成图像层时进行高斯模糊是为了得到每一层图像的DOG(Different Of Gaussian),也就是高斯不同,其含义是:把同一张图像在不同的参数下做高斯模糊之后的结果相减,得到的输出图像。高斯不同是图像的内在特征,在灰度图像增强、角点检测中经常用到。
    下面用代码实现一个四层高斯图像金字塔的构建,并将每一层的图像都逐一输出:
	Mat image_down, image_up;
	int level = 4;				//包含原图像,为第0层
	image_down = image.clone();			//第一张下采样图像初始化为原图像,即最底层(第0层)图像
	vector<Mat> Gauss_pyramid;			
	//reduce操作
	for (int i = 0; i < level; i++)
	{
		Gauss_pyramid.push_back(image_down);
		Mat temp = image_down.clone();
		pyrDown(temp, image_down);
	}
	int last_index = Gauss_pyramid.size() - 1;			//图像金字塔中最顶层的索引(也就是最小的图像)
	image_up = Gauss_pyramid[last_index].clone();			//第一张上采样图像初始化为图像金字塔的最顶层图像
	for (int j = last_index; j > -1; j--)
	{
		imshow(format("pyramid_iamge_%d", j), image_up);
		pyrUp(Gauss_pyramid[j], image_up);
	}

首先,定义一个Mat类型的向量来存放高斯图像金字塔,第0个元素即为金字塔的第0层,也就是原图像。然后通过for循环进行多次reduce操作,其中的主要API是pyrDown(temp, image_down),其第一个参数是要进行下采样的输入图像,第二个参数就是输出的高、宽分别缩减1/2后的下采样图像。然后将每次得到的下采样图像存放入表示高斯图像金字塔的向量中。循环结束后,就完成了一个高斯图像金字塔的构建。
接着是利用高斯图像金字塔的顶层低分辨率图像,来反向生成高分辨率图像,这个过程也称为expand操作。通过expand操作最后得到的图像虽然和原图像尺寸相同,但是相比原图像会丢失掉细节部分。这个部分的主要API是pyrUp(Gauss_pyramid[j], image_up),其第一个参数是输入的需要扩展的图像,第二个参数是输出的高、宽扩展了两倍的上采样图像。
下面是高斯图像金字塔的效果:
OpenCV4学习笔记(18)——图像金字塔及拉普拉斯金字塔_第1张图片

  • 拉普拉斯金字塔
    拉普拉斯金字塔是在获得高斯图像金字塔的前提下的拓展变换。
    首先需要获取图像的level层高斯图像金字塔G,再对每一层分别进行expand操作,得到一个反向的(level-1)层的图像集expand(G),最后将两个图像集的相邻层相减得到拉普拉斯金字塔L,可以表示为:
    L(0) = G(0) - expand(G(1)) ;
    L(1) = G(1) - expand(G(2)) ;
    L(2) = G(2) - expand(G(3)) ;

    拉普拉斯金字塔的每一层结果,就是一张图像在不同参数下做两次高斯模糊的差异值,也就是高斯不同(DOG)。由于其结果约等于LOG(对图像高斯模糊后进行拉普拉斯运算)操作,所以称为拉普拉斯金字塔。
    拉普拉斯金字塔的应用有:利用拉普拉斯金字塔,将一幅低分辨率的图像重建为高分辨率的图像(分辨率重建),且能在一定程度上恢复原图像细节。
    分辨率重建过程可以表示为:G(k) = L(k) +expand(G(k+1)),低分辨率图像作为G(k+1),根据上式求得G(k),逐层计算最终求出G(0),即为原高分辨率图像。
    下面是拉普拉斯金字塔的代码实现:
	int levels = 4;
	Mat image_down, image_up;
	image_down = image.clone();
	Mat sizeFlag;			//用于规定上采样和下采样时的输出图像尺寸

	vector<Mat> Gauss_pyramid;			//以向量形式定义高斯金字塔,第0个元素即为最底层
	for (int i = 0; i < levels; i++)
	{
		Mat temp = image_down.clone();
		sizeFlag = image_down.clone();
		Gauss_pyramid.push_back(image_down);
		pyrDown(temp, image_down, Size(sizeFlag.cols / 2, sizeFlag.rows / 2));
	}
	
	vector<Mat> expand_image;			//定义对高斯金字塔的每一层上采样后的图像,层数为高斯金字塔层数减一
	for (int j = 1; j < Gauss_pyramid.size(); j++)
	{
		sizeFlag = Gauss_pyramid[j-1].clone();			//第j层向高斯金字塔的第j-1层对齐,Size也需要相等
		pyrUp(Gauss_pyramid[j], image_up, Size(sizeFlag.cols, sizeFlag.rows));
		expand_image.push_back(image_up);
	}

	vector<Mat> Laplacian_pyramid;			//拉普拉斯金字塔
	for (int k = 0; k < expand_image.size(); k++)
	{
		Mat temp;
		subtract(Gauss_pyramid[k], expand_image[k], temp, Mat(), CV_16S);			//L(k) = G(k)-expand(G(k+1))
		convertScaleAbs(temp, temp);				//将相减结果映射到[0,255]区间
		Laplacian_pyramid.push_back(temp);
	}
	//逐层显示拉普拉斯金字塔
	for (int m = 0; m < Laplacian_pyramid.size(); m++)
	{
		imshow(format("Laplacian_pyramid_%d", m), Laplacian_pyramid[m]);
	}

下面是拉普拉斯金字塔的效果图:

本次关于图像金字塔的整理记录就到此结束啦,谢谢阅读。

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

你可能感兴趣的:(学习笔记)