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

图像金字塔

      图像处理中,通常需将一幅图像转换成不同大小进行处理。在OpenCV中,主要提供了两种方式:1)resize();2)图像金字塔。这次主要总结OpenCV中图像金字塔的相关知识。

       图像金字塔是一系列图像的集合,由一个原始图像依次向下采样获得。常见的图像金字塔主要有:Gaussian和Laplacian金字塔。高斯金字塔是向下采样图像,Laplacian金字塔则是向上采样重建图像。在OpenCV中,pyrDown ()和 pyrUp()则分别用于实现向下采样和向上采样二个功能。

 

一、图像金字塔原理

1、Guassian金字

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

 

2、Laplacian金字塔

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

 

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

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

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

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

 

     注: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()。

猜你喜欢

转载自blog.csdn.net/angl129/article/details/32714169
今日推荐