【图像处理】OpenCV系列十四 --- 图像金字塔
上一篇我们学习了图像卷积处理filter2D函数,相信大家通过阅读已经对filter2D图像卷积有了一定的了解,那么今天这节我们就来学习一下图像金字塔的概念以及如何使用图像金字塔对图像进行处理。
一、原理
一个图像金字塔是一系列图像的集合 - 所有图像来源于同一张原始图像 - 通过梯次向下采样获得,直到达到某个终止条件才停止采样。

有两种类型的图像金字塔常常出现在文献和应用中:
- 高斯金字塔(Gaussian pyramid): 用来向下采样
- 拉普拉斯金字塔(Laplacian pyramid): 用来从金字塔低层图像重建上层未采样图像
1、高斯金字塔
高斯金字塔是在图像处理、计算机视觉、信号处理上所使用的一项技术。高斯金字塔本质上为信号的多尺度表示法,亦即将同一信号或图片多次的进行高斯模糊,并且向下取样,藉以产生不同尺度下的多组信号或图片以进行后续的处理,例如在影像辨识上,可以借由比对不同尺度下的图片,以防止要寻找的内容可能在图片上有不同的大小。高斯金字塔的理论基础为尺度空间理论,而后续也衍生出了多分辨率分析。
每一层都按从下到上的次序编号, 层级(i+1) (表示为 G_i+1尺寸小于层级i(G_i)
为了获取层级为 (i+1)的金字塔图像,我们采用如下方法:
将 G_i与高斯内核卷积:

将所有偶数行和列去除,显而易见,结果图像只有原图的四分之一。通过对输入图像G_0 (原始图像) 不停迭代以上步骤就会得到整个金字塔。
Note:我们向下采样缩小图像的时候, 我们实际上丢失了一些信息。
2、拉普拉斯金字塔
在高斯金字塔的运算过程中,图像经过卷积和下采样操作会丢失部分高频细节信息。为描述这些高频信息,人们定义了拉普拉斯金字塔(Laplacian Pyramid, LP)。用高斯金字塔的每一层图像减去其上一层图像上采样并高斯卷积之后的预测图像,得到一系列的差值图像即为 LP 分解图像。
将G_i内插方法得到放大图像G_i,使G_i的尺寸与*G_i - 1的尺寸相同,即放大算子;
该式子实现两个步骤:在偶数行和列插入0,然后使用下采样中的高斯核进行滤波处理,得到和(i - 1)层一样大小的图像。
N为拉普拉斯金字塔顶层的层号,LP_i是拉普拉斯金字塔分解的第L层图像;由LP0,LP1、LP2…LPN构成的金字塔即为拉普拉斯金字塔;它的每一层L_0图像是高斯金字塔本层G_0图像与其高一层图像G_1经内插放大后图像*G_1的差,此过程相当于带通滤波,因此拉普拉斯金字塔又称为带通金字塔分解。
二、OpenCV中的API函数详解
1、高斯金字塔
函数原型
void pyrDown(InputArray src,
OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT);
函数功能
先对图像进行平滑,再进行其下采样!
参数详解
-
第一个参数,InputArray src,输入图像;
-
第二个参数,OutputArray dst,与原图像具有一样尺寸、类型的目标图像;
-
第三个参数,const Size& dstsize = Size(), 这个参数指的是降采样之后的目标图像的大小,我们可以看出它是有默认值的,如果我们调用函数的时候不指定第三个参数,那么这个值是按照 Size((src.cols+1)/2, (src.rows+1)/2) 计算的。
而且不管你自己如何指定这个参数,一定必须保证满足以下关系式:
|dstsize.width * 2 - src.cols| ≤ 2;
|dstsize.height * 2 - src.rows| ≤ 2;
也就是说降采样的意思其实是把图像的尺寸缩减一半,行和列同时缩减一半。所以你指定的大小,无非就是多一行少一列的区别而已。在大多数情况下使用默认值就可了,因为这个函数不是缩减图像至任意尺寸,就只是缩减一半,所以没必要搞得那么复杂;
- 第四个参数,int类型的borderType,边界模式,一般我们不用去管它。
实例
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
//载入原始图
Mat srcImage = imread("3.png");
if (srcImage.empty())
{
printf("image error!");
return -1;
}
Mat tmpImage, dstImage;
tmpImage = srcImage;
//显示原始图
imshow("【原始图】", srcImage);
//进行向下取样操作
pyrDown(tmpImage, dstImage,
Size(tmpImage.cols / 2,
tmpImage.rows / 2));
//显示效果图
imshow("【效果图】", dstImage);
waitKey(0);
return 0;
}
实验结果:


2、拉普拉斯金字塔
函数原型
void pyrUp(InputArray src,
OutputArray dst,
const Size& dstsize = Size(),
int borderType = BORDER_DEFAULT);
函数功能
先对对图像上采样,在对图像进行平滑处理!
参数详解
-
第一个参数,InputArray src,输入图像;
-
第二个参数,OutputArray dst,与原图像具有一样尺寸、类型的目标图像;
-
第三个参数,const Size&类型的dstsize,输出图像的大小;有默认值Size(),即默认情况下,由Size Size((src.cols+1)/2, (src.rows+1)/2)来进行计算,且一直需要满足下列条件:
上采样
- 第四个参数,int类型的borderType,边界模式,一般我们不用去管它。
实例
实验结果:


三、综合实例
实现按下u键对图像进行放大(拉普拉斯金字塔),按下d键对图像缩小(高斯金字塔),按下esc键退出!
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
/// 全局变量
Mat src, dst, tmp;
char* window_name = "Pyramids Demo";
int main(int argc, char** argv)
{
/// 指示说明
printf("\n Zoom In-Out demo \n ");
printf("------------------ \n");
printf(" * [u] -> Zoom in \n");
printf(" * [d] -> Zoom out \n");
printf(" * [ESC] -> Close program \n \n");
/// 测试图像 - 尺寸必须能被 2^{n} 整除
src = imread("lena.png");
if (!src.data)
{
printf(" No data! -- Exiting the program \n");
return -1;
}
tmp = src;
dst = tmp;
/// 创建显示窗口
namedWindow(window_name, WINDOW_AUTOSIZE);
imshow(window_name, dst);
/// 循环
while (true)
{
int c;
c = waitKey(10);
if ((char)c == 27) break;
// 向上采样
if ((char)c == 'u')
{
pyrUp(tmp, dst,
Size(tmp.cols * 2, tmp.rows * 2));
printf("** Zoom In: Image x 2 \n");
}
// 向下采样
else if ((char)c == 'd')
{
pyrDown(tmp, dst,
Size(tmp.cols / 2, tmp.rows / 2));
printf("** Zoom Out: Image / 2 \n");
}
imshow(window_name, dst);
tmp = dst;
}
return 0;
}
好了,今天的OpenCV图像处理 --- 【图像金字塔】学到这里就结束了,喜欢的朋友可以给我点个赞哦!!