【OpenCV入门教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

本文深入探讨图像金字塔概念,介绍OpenCV中pyrUp、pyrDown和resize函数的使用方法,以及如何通过高斯金字塔和拉普拉斯金字塔实现图像的向上与向下采样。提供配套示例程序,帮助读者掌握图像尺寸调整技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本系列文章由 @浅墨_毛星云  出品,转载请注明出处。   

文章链接:   http://blog.youkuaiyun.com/poem_qianmo/article/details/26157633

作者:毛星云(浅墨)     微博: http://weibo.com/u/1723155442

http://www.zhihu.com/people/mao-xing-yun

邮箱:   happylifemxy@163.com

写作当前博文时配套使用的OpenCV版本:  2.4.9

这篇文章里,我们将一起探讨图像金字塔的一些基本概念,如何使用OpenCV函数 pyrUp 和 pyrDown 对图像进行向上和向下采样,以及了解了专门用于缩放图像尺寸的resize函数的用法。此博文一共有四个配套的示例程序,他们详细注释过的代码都在文中贴出,且文章最后提供了综合示例程序的下载。

先尝鲜一下其中一个示例程序的运行截图:


一、引言

我们经常会将某种尺寸的图像转换为其他尺寸的图像,如果放大或者缩小图片的尺寸,笼统来说的话,可以使用OpenCV为我提供的如下两种方式:

<1> resize函数。这是最直接的方式,

<2> pyrUp( )、pyrDown( )函数。即图像金字塔相关的两个函数,对图像进行向上采样,向下采样的操作。

pyrUp、pyrDown其实和专门用作放大缩小图像尺寸的resize在功能上差不多,披着图像金字塔的皮,说白了还是在对图像进行放大和缩小操作。另外需要指出的是,pyrUp、pyrDown在OpenCV的imgproc模块中的Image Filtering子模块里。而resize在imgproc 模块的Geometric Image Transformations子模块里。

这篇文章中,我们将先介绍图像金字塔的原理,接着介绍resize函数,然后是pyrUp和pyrDown函数,最后是一个综合示例程序。

二、关于图像金字塔

图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。

图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。

金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。

我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

 


 

 

 

素材图是帅气的美剧《绿箭侠》里面的绿箭侠Oliver Queen。

一般情况下有两种类型的图像金字塔常常出现在文献和以及实际运用中。他们分别是:

  • 高斯金字塔 ( Gaussianpyramid): 用来向下采样,主要的图像金字塔
  • 拉普拉斯金字塔 (Laplacianpyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用。

两者的简要区别:高斯金字塔用来向下降采样图像,而拉普拉斯金字塔则用来从金字塔底层图像中向上采样重建一个图像。

要从金字塔第i层生成第i+1层(我们表示第i+1层为G_i+1),我们先要用高斯核对G_1进行卷积,然后删除所有偶数行和偶数列。当然的是,新得到图像面积会变为源图像的四分之一。按上述过程对输入图像G_0执行操作就可产生出整个金字塔。

当图像向金字塔的上层移动时,尺寸和分辨率就降低。OpenCV中,从金字塔中上一级图像生成下一级图像的可以用PryDown。而通过PryUp将现有的图像在每个维度都放大两遍。

图像金字塔中的向上和向下采样分别通过OpenCV函数 pyrUp 和 pyrDown 实现。

概括起来就是:

  • 对图像向上采样:pyrUp函数
  • 对图像向下采样:pyrDown函数

这里的向下与向上采样,是对图像的尺寸而言的(和金字塔的方向相反),向上就是图像尺寸加倍,向下就是图像尺寸减半。而如果我们按上图中演示的金字塔方向来理解,金字塔向上图像其实在缩小,这样刚好是反过来了。

但需要注意的是,PryUp和PryDown不是互逆的,即PryUp不是降采样的逆操作。这种情况下,图像首先在每个维度上扩大为原来的两倍,新增的行(偶数行)以0填充。然后给指定的滤波器进行卷积(实际上是一个在每个维度都扩大为原来两倍的过滤器)去估计“丢失”像素的近似值。

PryDown( )是一个会丢失信息的函数。为了恢复原来更高的分辨率的图像,我们要获得由降采样操作丢失的信息,这些数据就和拉普拉斯金字塔有关系了。

2.1 高斯金字塔

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

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

2.1.1 对图像的向下取样

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

<1> 对图像G_i进行高斯内核卷积

<2> 将所有偶数行和列去除

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

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

2.1.2 对图像的向上取样

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

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

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

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

那么,我们接下来一起看一看拉普拉斯金字塔的概念吧。

2.2 拉普拉斯金字塔

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

 

式中的  表示第i层的图像。而UP()操作是将源图像中位置为(x,y)的像素映射到目标图像的(2x+1,2y+1)位置,即在进行向上取样。符号  表示卷积,  为5x5的高斯内核。

我们下文将要介绍的pryUp,就是在进行上面这个式子的运算。

因此,我们可以直接用OpenCV进行拉普拉斯运算:

 

也就是说,拉普拉斯金字塔是通过源图像减去先缩小后再放大的图像的一系列图像构成的。

整个拉普拉斯金字塔运算过程可以通过下图来概括:

 

所以,我们可以将拉普拉斯金字塔理解为高斯金字塔的逆形式。

另外再提一点,关于图像金字塔非常重要的一个应用就是实现图像分割。图像分割的话,先要建立一个图像金字塔,然后在G_i和G_i+1的像素直接依照对应的关系,建立起”父与子“关系。而快速初始分割可以先在金字塔高层的低分辨率图像上完成,然后逐层对分割加以优化。

三、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(效率较高,速度较快,推荐使用)。

关于插值,我们看几张图就能更好地理解。先看原图:

当进行6次图像缩小接着6次图像放大操作后,两种不同的插值方式得到的效果图:

         

效果很明显,第一张全是一个个的像素,非常影响美观。另外一张却有雾化的朦胧美感,所以插值方式的选择,对经过多次放大缩小的图片最终得到的效果是有很大影响的。

接着我们来看两种resize的调用范例。

方式一,调用范例:

Mat dst=Mat::zeros(512 ,512, CV_8UC3 );//新建一张512x512尺寸的图片
Mat src=imread(“1.jpg”);
//显式指定dsize=dst.size(),那么fx和fy会其计算出来,不用额外指定。
resize(src, dst, dst.size());

方式二、调用范例:

Mat dst;
Mat src=imread(“1.jpg”)
 //指定fx和fy,让函数计算出目标图像的大小。
resize(src, dst, Size(), 0.5, 0.5);

接着我看看完整的示例程序:

//-----------------------------------【头文件包含部分】---------------------------------------
//		描述:包含程序所依赖的头文件
//---------------------------------------------------------------------------------------------- 
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>

//-----------------------------------【命名空间声明部分】---------------------------------------
//		描述:包含程序所使用的命名空间
//----------------------------------------------------------------------------------------------- 
using namespace cv;
//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main( )
{
  //载入原始图   
  Mat srcImage = imread("1.jpg");  //工程目录下应该有一张名为1.jpg的素材图
  Mat tmpImage,dstImage1,dstImage2;//临时变量和目标图的定义
  tmpImage=srcImage;//将原始图赋给临时变量

  //显示原始图  
  imshow("【原始图】", srcImage);  

  //进行尺寸调整操作
  resize(tmpImage,dstImage1,Size( tmpImage.cols/2, tmpImage.rows/2 ),(0,0),(0,0),3);
  resize(tmpImage,dstImage2,Size( tmpImage.cols*2, tmpImage.rows*2 ),(0,0),(0,0),3);

  //显示效果图  
  imshow("【效果图】之一", dstImage1);  
  imshow("【效果图】之二", dstImage2);  

  waitKey(0);  
  return 0;  
}

程序运行截图:

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值