opencv学习-高斯金字塔和拉普拉斯金字塔

图像金字塔

  • 一个图像金字塔是由一系列的图像组成,最底下一张是图像尺寸最大,最上方的图像尺寸最小,从空间上从上向下看就像一个古代的金字塔。
  • 金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。
  • 图像金字塔常用于图像缩放、图像重构、图像融合、图像增强技术中。

高斯金字塔

高斯金字塔是通过高斯平滑和亚采样获得一系列采样图像,也就是说第K层高斯金字塔通过平滑,亚采样就可以获得K+1层高斯图像,高斯金字塔包含了一系列低通滤波器,其截止频率从上一层到下一层是以因子2逐渐增加,所以高斯金字塔就可以跨越很大的频率范围,金字塔的图像如下:

opencv学习-高斯金字塔和拉普拉斯金字塔_第1张图片

另外,每一层都按从下到上的次序编号, 层级 G_i+1 (表示为 G_i+1尺寸小于第i层G_i)。

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

(1)对图像G_i进行高斯内核卷积(高斯模糊滤波,这样做既能保证高斯金字塔低通处理的性质,又能对图像进行平滑,使下采样得到的图像不至于出现边界缝隙)

(2)将所有偶数行和列去除

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

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

  1. 对图像的向上取样

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

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

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

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

在OpenCV中提供了函数pyrDown(),用于生成图像的上一层高斯金字塔。
函数pyrDown()的原型如下:

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

参数说明:
src—输入图像
dst—输出图像,它的宽度和高度大致为src的1/2 ,具体精确的大小由第三个参数dstsize决定。
dstsize—目标图像的大小,默认值为Size((src.cols+1)/2, (src.rows+1)/2),自己指定时需要满足以下条件。

使用函数pyrDown()生成上一层高斯金字塔包含两个过程,即高斯核卷积(用于实现高斯模糊滤波)和下采样两个过程。
在这里插入图片描述

函数pyrDown()使用的高斯核如下:

opencv学习-高斯金字塔和拉普拉斯金字塔_第2张图片

拉普拉斯金字塔

拉普拉斯金字塔实际上是为了实现高斯金字塔的图像重建而存在的。它是在高斯金字塔的基础上生成的。拉普拉斯金字塔是高斯金字塔与其上一层通过上采样扩大后的差值图像,这里的上采样一般采用插值的方式进行。

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

opencv学习-高斯金字塔和拉普拉斯金字塔_第3张图片

opencv学习-高斯金字塔和拉普拉斯金字塔_第4张图片

也就是说,拉普拉斯金字塔是通过源图像减去先缩小后再放大的图像的一系列图像构成的
整个拉普拉斯金字塔运算过程可以通过下图来概括:
opencv学习-高斯金字塔和拉普拉斯金字塔_第5张图片
简化流程:
opencv学习-高斯金字塔和拉普拉斯金字塔_第6张图片
从上面的这幅图我们可以看出,第n层拉普拉斯图像实际上是第n层高斯图像与第n+1层高斯图像经上采样后的差值,由于高斯滤波器是一种低通滤波器,所以我们可以说某一级的拉普拉斯金字塔可以反映出其同级的高斯金字塔的高频分量。有些文献把拉普拉斯金字塔反映其同级高斯金字塔的高频分量的性质称为拉普拉斯金字塔的预测残差作用。

从上面拉普拉斯图像的生成过程我们可以看出,在利用高斯金字塔生成拉普拉斯金字塔的过程中,假设高斯金字塔为N层,则在计算第N层的拉普拉斯金字塔时我们还要额外计算出第N+1层的高斯金字塔才能进而计算出第N层的拉普拉斯金字塔。

OpenCV提供了函数pyrUp()用于帮助计算出拉普拉斯金字塔。通过它可以把第n层的高斯金字塔图像进行上采样后再进行高斯卷积模糊滤波操作。

函数pyrDown()的的原型如下:

void cv::pyrUp(InputArray src,
               OutputArray dst,
               const Size & dstsize = Size(),
               int borderType = BORDER_DEFAULT )

参数与pyrDown类似

实现代码:

#include 
#include "opencv2\xfeatures2d.hpp"
#include 
#include 
#include
#include 
#include 
#include 

using namespace std;

using namespace cv;
using namespace cv::xfeatures2d;

int main()
{
	cv::Mat img = cv::imread("C:\\Users\\Administrator\\Downloads\\1.jpeg");
	cv::Mat G_0(img);
	cv::imshow("G_0", img);

	cv::Mat G_1;
	cv::pyrDown(G_0, G_1);
	cv::imshow("G_1", G_1);

	cv::Mat Pyrup_G_1;
	cv::pyrUp(G_1, Pyrup_G_1);
	cv::imshow("Pyrup_G_1", Pyrup_G_1);

	cv::Mat L_0;
	cv::subtract(G_0, Pyrup_G_1, L_0);
	cv::imshow("L_0", L_0);

	//以下几行代码是显示出第0层拉普拉斯金字塔的图像
	cv::Mat L_0_norm = L_0;
	cv::normalize(L_0, L_0_norm, 0, 255, cv::NORM_MINMAX);
	L_0_norm.convertTo(L_0_norm, CV_8U);
	cv::Mat L_0_norm_gray;
	cv::cvtColor(L_0_norm, L_0_norm_gray, cv::COLOR_BGR2GRAY);

	cv::imshow("L_0_norm_gray", L_0_norm_gray);

	
	//利用第1层高斯金字塔图像和第0层拉普拉斯金字塔图像重构第0层高斯金字塔
	//第0层高斯金字塔实际上就是原图
	cv::Mat G_0_reconstruction;
	cv::add(Pyrup_G_1, L_0, G_0_reconstruction, cv::Mat(), CV_16S);
	cv::normalize(G_0_reconstruction, G_0_reconstruction, 0, 255, cv::NORM_MINMAX);
	
	G_0_reconstruction.convertTo(G_0_reconstruction, CV_8U);

	cv::imshow("G_0_reconstruction", G_0_reconstruction);

	cv::waitKey(0);

	return 0;
}

效果图:
opencv学习-高斯金字塔和拉普拉斯金字塔_第7张图片

参考:
https://www.hhai.cc/thread-198-1-1.html
https://www.cnblogs.com/wyuzl/p/6294275.html
https://blog.csdn.net/weixin_44651073/article/details/126355704

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