OpenCV8-图像金字塔

OpenCV8-图像金字塔

    • 1.图像金字塔
    • 2.高斯金字塔
    • 3.拉普拉斯金字塔
    • 4.Demo


1.图像金字塔

图像”金字塔“是通过多个分辨率表示图像的一种有效且简单的结构。一个图像”金字塔“是一系列以金字塔形状排列、分辨率逐步降低的图像集合。图像”金字塔“的底部是待处理图像的高分辨率表示,顶部是低分辨率表示。本文中将介绍图像”金字塔“中比较著名的两种:高斯”金字塔“和拉普拉斯”金字塔“。

2.高斯金字塔

高斯”金字塔“是指通过下采样不断地将图像的尺寸缩小,进而在图像”金字塔“中包含多个尺寸的图像。一般情况下,高斯”金字塔“的底层为图像的原图,每往上一层就会通过下采样缩小一次图像的尺寸,通常情况下,尺寸会缩小为原来的一半,但是如果有特俗需求,缩小的尺寸也可以根据实际情况进行调整。由于每次图像的尺寸都缩小为原来的一半,图像尺寸缩小的速度非常快,因此常见的高斯”金字塔“的层数为3~6层。

OpenCV中提供了pyrDown函数专门用于图像的下采样计算,以便构建图像的高斯”金字塔“:

void pyrDown(
    InputArray src,  // 输入待下采样的图像
    OutputArray dst, // 输出下采样后的图像
    const Size& dstsize = Size(),  // 输出图像尺寸,可以默认
    int borderType = BORDER_DEFAULT // 像素边界外推方法的标志,图像几何变换一文中-仿射变换有说明
);

该函数用于实现图像模糊并对其进行下采样,默认标志下,函数输出图像的尺寸为输入图像尺寸的一半,但是也可以通过dstsize参数来设置输出图像的大小,需要注意的是,无论输出尺寸为多少,应该满足下面公式的条件:
{ ∣ d s t s i z e . w i d t h 2 − s r c . c o l s ∣ ≤ 2 ∣ d s t s i z e . h e i g h t 2 − s r c . r o l s ∣ ≤ 2 \left\{ \begin{matrix} | dstsize.width2 - src.cols | \leq 2 \\ | dstsize.height2 - src.rols | \leq 2 \\ \end{matrix} \right. {dstsize.width2src.cols2dstsize.height2src.rols2
该函数首先将原始图像与内核矩阵进行卷积,之后通过不适用偶数行和列的方式对图像进行下采样,最终实现尺寸缩小的下采样,内核矩阵如下:
k = 1 256 [ 1 4 6 4 1 4 6 24 6 4 6 24 36 24 6 4 16 24 16 4 1 4 6 4 1 ] k = \frac{1}{256} \begin{bmatrix} 1 & 4 & 6 & 4 & 1 \\ 4 & 6 & 24 & 6 & 4 \\ 6 & 24 & 36 & 24 & 6 \\ 4 & 16 & 24 & 16 & 4 \\ 1 & 4 & 6 & 4 & 1 \\ \end{bmatrix} k=2561 14641462416462436246462416414641
该函数的功能与resize函数将图像尺寸缩小一样,但是使用的内部算法不同。

3.拉普拉斯金字塔

拉普拉斯”金字塔“是通过上层小尺寸的图像构建下层大尺寸的图像。拉普拉斯”金字塔“具有预测残差的作用,需要与高斯”金字塔“一起使用。

假设我们有了一个高斯图像”金字塔“,对于其中的第i层图像(高斯”金字塔“最下面为第0层),首先通过下采样得到一个尺寸缩小一半图像,即高斯”金字塔“中的第i+1层或者不在高斯”金字塔“中,之后对这福图像进行上采样,将图像尺寸恢复到第i层图像的大小,最后求取高斯”金字塔“第i层图像与经过上采样后的图像的残差图像,这个残差图像就是拉普拉斯”金字塔“的第i层图像。

对于上采样操作OpenCV提供了pyrUp函数:

void pyrUp(
    InputArray src, 
    OutputArray dst,
    const Size& dstsize = Size(), 
    int borderType = BORDER_DEFAULT 
);
// 函数参数同pyrDown

4.Demo

#include 
#include  // debug no log
#include 
using namespace cv;
using namespace std;

int main()
{
	cout << "OpenCV Version: " << CV_VERSION << endl;
	utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);

	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	vector<Mat> Gauss, Lap;  //高斯金字塔和拉普拉斯金字塔
	int level = 3;  //高斯金字塔下采样次数
	Gauss.push_back(img);  //将原图作为高斯金字塔的第0层
	//构建高斯金字塔
	for (int i = 0; i < level; i++)
	{
		Mat gauss;
		pyrDown(Gauss[i], gauss);  //下采样
		Gauss.push_back(gauss);
	}
	//构建拉普拉斯金字塔
	for (int i = Gauss.size() - 1; i > 0; i--)
	{
		Mat lap, upGauss;
		if (i == Gauss.size() - 1)  //如果是高斯金字塔中的最上面一层图像
		{
			Mat down;
			pyrDown(Gauss[i], down);  //上采样
			pyrUp(down, upGauss);
			lap = Gauss[i] - upGauss;
			Lap.push_back(lap);
		}
		pyrUp(Gauss[i], upGauss);
		lap = Gauss[i - 1] - upGauss;
		Lap.push_back(lap);
	}
	//查看两个金字塔中的图像
	for (int i = 0; i < Gauss.size(); i++)
	{
		string name = to_string(i);
		imshow("G" + name, Gauss[i]);
		imshow("L" + name, Lap[i]);
	}

	waitKey(0);
	return 0;
}

你可能感兴趣的:(OpenCV,c++,计算机视觉,opencv)