您的位置:首页 > 运维架构

OpenCV学习总结2-图像金字塔

2014-06-20 15:55 232 查看
图像金字塔
      图像处理中,通常需将一幅图像转换成不同大小进行处理。在OpenCV中,主要提供了两种方式:1)resize();2)图像金字塔。这次主要总结OpenCV中图像金字塔的相关知识。
       图像金字塔是一系列图像的集合,由一个原始图像依次向下采样获得。常见的图像金字塔主要有:Gaussian和Laplacian金字塔。高斯金字塔是向下采样图像,Laplacian金字塔则是向上采样重建图像。在OpenCV中,pyrDown ()和 pyrUp()则分别用于实现向下采样和向上采样二个功能。
 
一、图像金字塔原理

1、Guassian金字塔

       Gaussian金字塔是是通过依次地向下迭代采样获得整个金字塔,如下图,随着依次地采样,图像越来越小。第(i+1)层Gi+1,是由第i层Gi 和高斯核进行卷积,然后去除每个偶数行和列,得到的采样图像是前一层的(1/4)。由其实现过程可知,向下采样是有损的操作,会丢弃了部分信息;图像的层次越高,对应的图像越小,分辨率也越低。

 



[align=left] [/align]

2、Laplacian金字塔

       在downsampling的过程中,丢失了部分的信息;而为保存原始的图像,我们又需利用这些丢弃的信息,这些丢失的信息就形成了Laplacian金字塔。第i层的金字塔信息定义为:

 


      由底层图像向上采样重建图像,向上取样的具体步骤分为2步:

      1)将原图像在每一维上扩大2倍,将原图像(x,y)处的像素映射到目标图像的(2x+1,2y+1)处,新的偶数行则以0填充;

      2)将其与给定的滤波器进行卷积来近似“丢失”像素的值。

      则Laplacian金字塔可直接定义为:



[align=left] [/align]

     注:Laplacian金字塔利用低层分辨率低的图像重建一个上取样的图像,但pyrUp()和pyrDown()是不可逆的,向下取样时会丢失信息的。详细的描述可参考:

     http://docs.opencv.org/doc/tutorials/imgproc/pyramids/pyramids.html 和《学习OpenCV》。

 

二、pyrUp()和pyrDown()分析

1)pyrUp()

1. 函数定义

void cv::pyrUp( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )

参数:_src - 输入图像

           _dst - 输出图像

          _dsz - 输出图像的大小。默认情况下:size(src.cols*2,src.rows*2)

         borderType - 像素外插的方法,BORDER_DEFAULT,逐步查找得:BORDER_DEFAULT=BORDER_REFLECT_101,  BORDER_REFLECT_101=IPL_BORDER_REFLECT_101,#define IPL_BORDER_REFLECT_101    4  ,额外的边界模式。

 

2. 函数实现

 

void cv::pyrUp( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
{
Mat src = _src.getMat();
Size dsz = _dsz == Size() ? Size(src.cols*2, src.rows*2) : _dsz;   //目标图像的大小
_dst.create( dsz, src.type() );
Mat dst = _dst.getMat();

#ifdef HAVE_TEGRA_OPTIMIZATION
if(borderType == BORDER_DEFAULT && tegra::pyrUp(src, dst))
return;
#endif

int depth = src.depth();
PyrFunc func = 0;
if( depth == CV_8U )  //根据原图像深度进行不同的处理
func = pyrUp_<FixPtCast<uchar, 6>, NoVec<int, uchar> >;
else if( depth == CV_16S )
func = pyrUp_<FixPtCast<short, 6>, NoVec<int, short> >;
else if( depth == CV_16U )
func = pyrUp_<FixPtCast<ushort, 6>, NoVec<int, ushort> >;
else if( depth == CV_32F )
func = pyrUp_<FltCast<float, 6>, NoVec<float, float> >;
else if( depth == CV_64F )
func = pyrUp_<FltCast<double, 6>, NoVec<double, double> >;
else
CV_Error( CV_StsUnsupportedFormat, "" );

func( src, dst, borderType );
}

    pyrUp()的实现主要由pyrUp_()实现,其为一个模板函数,相应的声明如下: 

template<class CastOp, class VecOp> void pyrUp_( const Mat& _src, Mat& _dst, int)

   其中func定义如下: 

typedef void (*PyrFunc)(const Mat&, Mat&, int);

   具体的实现在源代码目录\sources\modules\imgproc\src下的pyramids.cpp文件。

 

2)pyrDown()

1. 函数定义 

void cv::pyrDown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )

参数: _src - 输入图像

           _dst -  输出图像

          _dsz - 输出图像尺寸,默认:Size((src.cols+1)/2,(src.rows+1)/2)。

         borderType - 和pyrUp()中相同。

 

2. 实现代码 

void cv::pyrDown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
{
Mat src = _src.getMat();
Size dsz = _dsz == Size() ? Size((src.cols + 1)/2, (src.rows + 1)/2) : _dsz;
_dst.create( dsz, src.type() );
Mat dst = _dst.getMat();

#ifdef HAVE_TEGRA_OPTIMIZATION
if(borderType == BORDER_DEFAULT && tegra::pyrDown(src, dst))
return;
#endif

int depth = src.depth();
PyrFunc func = 0;
if( depth == CV_8U )
func = pyrDown_<FixPtCast<uchar, 8>, PyrDownVec_32s8u>;
else if( depth == CV_16S )
func = pyrDown_<FixPtCast<short, 8>, NoVec<int, short> >;
else if( depth == CV_16U )
func = pyrDown_<FixPtCast<ushort, 8>, NoVec<int, ushort> >;
else if( depth == CV_32F )
func = pyrDown_<FltCast<float, 8>, PyrDownVec_32f>;
else if( depth == CV_64F )
func = pyrDown_<FltCast<double, 8>, NoVec<double, double> >;
else
CV_Error( CV_StsUnsupportedFormat, "" );

func( src, dst, borderType );
}

 

三、实例分析

实验平台:VS2010 + OpenCV2.4.9

 

#include<iostream>
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\video\background_segm.hpp>

using namespace cv;
using namespace std;

void helpProcess();
int main()
{
helpProcess();
Mat src,tmp,dst;
src=imread("Car.jpg");
if (src.empty()){
cvNamedWindow("图像读取失败,请确认路径是否正确!\n");
waitKey();
return -1;
}

tmp=src;
dst=tmp;
cvNamedWindow("图像金字塔");
imshow("图像金字塔",dst);

while(1)
{
int c;
c=waitKey(10);

switch(c)
{
case 27:
return 1;
break;
case 'u':
pyrUp(tmp,dst,Size(tmp.cols*2,tmp.rows*2));
cout<<"进行图像放大,图像尺寸*2!\n";
break;
case 'd':
pyrDown(tmp,dst,Size(tmp.cols/2,tmp.rows/2));
cout<<"进行图像缩小,图像尺寸/2!\n";
break;
}
imshow("图像金字塔",dst);
tmp=dst;

}
return 1;
}

void helpProcess()
{
cout<<"Opencv中图像金字塔的实例程序!\n";
cout<<"--------------------------------\n";
cout<<"      [u]->向上采样            \n";
cout<<"      [d]->向下采样            \n";
cout<<"      [esc]->退出程序          \n";
cout<<"--------------------------------\n";
}






       向下取样会损失部分信息。图像金字塔在图像处理中应用广泛,主要有图像分割,将金字塔相邻图像层次G(i+1) <--> G(i) 的像素联想成父子关系的系统,在金字塔的高层图像中进行快速分割,然后一级一级精炼进行精准分割。OpenCV中也提供了相应的函数PyrSegmentation()。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息