一、介绍
图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。
图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。
金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。
我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。
一般情况下有两种类型的图像金字塔常常出现在文献和以及实际运用中。他们分别是:
- 高斯金字塔(Gaussianpyramid): 用来向下采样,主要的图像金字塔
- 拉普拉斯金字塔(Laplacianpyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用。
两者的简要区别:高斯金字塔用来向下降采样图像,而拉普拉斯金字塔则用来从金字塔底层图像中向上采样重建一个图像。
要从金字塔第i层生成第i+1层(我们表示第i+1层为G_i+1),我们先要用高斯核对G_1进行卷积,然后删除所有偶数行和偶数列。当然的是,新得到图像面积会变为源图像的四分之一。按上述过程对输入图像G_0执行操作就可产生出整个金字塔。
当图像向金字塔的上层移动时,尺寸和分辨率就降低。OpenCV中,从金字塔中上一级图像生成下一级图像的可以用PryDown。而通过PryUp将现有的图像在每个维度都放大两遍。
图像金字塔中的向上和向下采样分别通过OpenCV函数 pyrUp 和 pyrDown 实现。
概括起来就是:
- 对图像向上采样:pyrUp函数
- 对图像向下采样:pyrDown函数
- resize函数。这是最直接的方式
这里的向下与向上采样,是对图像的尺寸而言的(和金字塔的方向相反),向上就是图像尺寸加倍,向下就是图像尺寸减半。而如果我们按上图中演示的金字塔方向来理解,金字塔向上图像其实在缩小,这样刚好是反过来了。
但需要注意的是,PryUp和PryDown不是互逆的,即PryUp不是降采样的逆操作。这种情况下,图像首先在每个维度上扩大为原来的两倍,新增的行(偶数行)以0填充。然后给指定的滤波器进行卷积(实际上是一个在每个维度都扩大为原来两倍的过滤器)去估计“丢失”像素的近似值。
PryDown( )是一个会丢失信息的函数。为了恢复原来更高的分辨率的图像,我们要获得由降采样操作丢失的信息,这些数据就和拉普拉斯金字塔有关系了。
二、具体介绍(高斯、拉普拉斯金字塔):
三、函数详解:
resize( )函数:
resize( )为OpenCV中专职调整图像大小的函数。
此函数将源图像精确地转换为指定尺寸的目标图像。如果源图像中设置了ROI(Region Of Interest ,感兴趣区域),那么resize( )函数会对源图像的ROI区域进行调整图像尺寸的操作,来输出到目标图像中。若目标图像中已经设置ROI区域,不难理解resize( )将会对源图像进行尺寸调整并填充到目标图像的ROI中。
很多时候,我们并不用考虑第二个参数dst的初始图像尺寸和类型(即直接定义一个Mat类型,不用对其初始化),因为其尺寸和类型可以由src,dsize,fx和fy这其他的几个参数来确定。
看看函数原型:
C++: void resize(InputArray src,
OutputArray dst,
Size dsize,
double fx=0,
double fy=0,
int interpolation=INTER_LINEAR )
参数解释:
- 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。
- 第二个参数,OutputArray类型的dst,输出图像,当其非零时,有着dsize(第三个参数)的尺寸,或者由src.size()计算出来。
- 第三个参数,Size类型的dsize,输出图像的大小;如果它等于零,由下式进行计算:
其中,dsize,fx,fy都不能为0。
- 第四个参数,double类型的fx,沿水平轴的缩放系数,有默认值0,且当其等于0时,由下式进行计算:
- 第五个参数,double类型的fy,沿垂直轴的缩放系数,有默认值0,且当其等于0时,由下式进行计算:
- 第六个参数,int类型的interpolation,用于指定插值方式,默认为INTER_LINEAR(线性插值)。
可选的插值方式如下:
- INTER_NEAREST - 最近邻插值
- INTER_LINEAR - 线性插值(默认值)
- INTER_AREA - 区域插值(利用像素区域关系的重采样插值)
- INTER_CUBIC –三次样条插值(超过4×4像素邻域内的双三次插值)
- INTER_LANCZOS4 -Lanczos插值(超过8×8像素邻域的Lanczos插值)
若要缩小图像,一般情况下最好用CV_INTER_AREA来插值,而若要放大图像,一般情况下最好用CV_INTER_CUBIC(效率不高,慢,不推荐使用)或CV_INTER_LINEAR(效率较高,速度较快,推荐使用)。
pyrUP( )函数:作用是向上采样并模糊一张图像,说白了就是放大一张图片。
C++: void pyrUp(InputArray src,
OutputArraydst,
const Size& dstsize=Size(),
int borderType=BORDER_DEFAULT )
- 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。
- 第二个参数,OutputArray类型的dst,输出图像,和源图片有一样的尺寸和类型。
- 第三个参数,const Size&类型的dstsize,输出图像的大小;有默认值Size(),即默认情况下,由Size(src.cols*2,src.rows*2)来进行计算,且一直需要满足下列条件:
- 第四个参数,int类型的borderType,又来了,边界模式,一般我们不用去管它。
pyrUp函数执行高斯金字塔的采样操作,其实它也可以用于拉普拉斯金字塔的。
首先,它通过插入可为零的行与列,对源图像进行向上取样操作,然后将结果与pyrDown()乘以4的内核做卷积,就是这样。
pyrDown( )函数:作用是向下采样并模糊一张图像,说白了就是缩小一张图片。
C++: void pyrDown(InputArray src,
OutputArray dst,
const Size& dstsize=Size(),
int borderType=BORDER_DEFAULT)
- 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。
- 第二个参数,OutputArray类型的dst,输出图像,和源图片有一样的尺寸和类型。
- 第三个参数,const Size&类型的dstsize,输出图像的大小;有默认值Size(),即默认情况下,由Size Size((src.cols+1)/2, (src.rows+1)/2)来进行计算,且一直需要满足下列条件:
该pyrDown函数执行了高斯金字塔建造的向下采样的步骤。首先,它将源图像与如下内核做卷积运算:
接着,它便通过对图像的偶数行和列做插值来进行向下采样操作。
综合代码实现:
//添加头文件
#include<opencv2/core/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<iostream>
# define name_Window "原图"
using namespace std;
using namespace cv;
Mat Img_scr,Img_dst,Img_tmp;
void show_help();
void show_help()
{
system("color 5F");
cout<<"欢迎来到图像金字塔处理程序"<<endl<<endl;
cout<<"按键 【0】——退出程序 "<<endl;
cout<<"按键 【1】——进行基于resize函数的图像放大 "<<endl;
cout<<"按键 【2】——进行基于resize函数的图像缩小 "<<endl;
cout<<"按键 【3】——进行基于pyrUP函数的图像放大 "<<endl;
cout<<"按键 【4】——进行基于pyrDown函数的图像缩小 "<<endl;
}
int main()
{
int key=0;
//显示帮助信息
show_help();
Img_scr=imread("lenna.jpg");
Img_tmp=Img_scr;
if (!Img_scr.data)//
{
cout<<"没有读取到图像...........请检查!"<<endl;
system("pause");
}
namedWindow(name_Window);
imshow(name_Window , Img_scr);
while(1)
{
//等待按键
key=waitKey(0);
switch(key)
{
case '0':
return 0;
break;
case '1':
resize(Img_tmp,Img_dst,Size( Img_tmp.cols*2, Img_tmp.rows*2 ) ,CV_INTER_LINEAR);
break;
case '2':
resize(Img_tmp,Img_dst,Size( Img_tmp.cols/2, Img_tmp.rows/2 ) , CV_INTER_AREA);
break;
case '3':
pyrUp(Img_tmp,Img_dst,Size( Img_tmp.cols*2, Img_tmp.rows*2 ));
break;
case '4':
pyrDown(Img_tmp,Img_dst,Size( Img_tmp.cols/2, Img_tmp.rows/2 ));
break;
}
imshow("效果图",Img_dst);
//将Img_dst赋给Img_tmp,方便下一次循环
Img_tmp=Img_dst;
}
return 0;
}
效果:1-4依次