图像处理 金字塔

2020-02-24 00:41:15 qq_38299170 阅读数 281
  • 图像金字塔

    学完本课程,可以牢固掌握人工智能计算机视觉的基础知识与常见算法,对图像处理、图像分析可以理解与应用 掌握python opencv框架编程与相关算法原理与函数使用,可以完成基础的图像处理与图像分析项目任务 为进一步...

    165人学习 贾志刚
    免费试看

返回主目录

返回 图像处理的一些方法 目录

上一章:深度篇——图像处理的一些方法(三)  细说 HOG 特征 与 bag-of-word

 

本小节,细说 图像金字塔

 

七. 图像金字塔

图像金字塔是一种以多分类分辨率来解释图像的有效但概念简单的结构。应用于图像分割,机器视觉和图像压缩。一幅图像的金字塔是一系列以金字塔形状 排列的分辨率逐步降低,且来源于同一张原始的图像集合。通过梯次向下采样获得,直到达到某个终止条件才停止采样。金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。这里将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

     深度: \large J = log_{2} N\large N 表示宽度或长度。

1. 常见的两类图像金字塔

    (1). Gaussian pyramind 高斯金字塔

          用来向下采样,主要的图像金字塔

    (2). Laplacian pyramind 拉普拉斯金字塔

          用来从金字塔低层图像重建上层来采样图像,在数字图像处理中,也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用。

    (3). 两者的区别

           高斯金字塔用来向下降采样图像,而拉普拉斯金字塔则可以用来从金字塔底层图像中向上采样重建一个图像。

    (4). 这里的向下与向上采样,是对图像的尺寸而言的(和金字塔的方向相反),向上就是图像尺寸加倍,向下就是图像尺寸减半。

    (5). 当图像向金字塔的上层移动时,尺寸和分辨率就降低。在 opencv 中,从金字塔中上一级图像生成下一级图像的可以用 pyrDown。而通过 pyrUp 将现有的图像在每个维度都放大两倍。金字塔中的向上和向下采样分别通过 opencv 函数 pyrUp 和 pyrDown 实现。

    (6). 需要注意的是,pyrUp 和 pyrDown 不是互逆的,即 pyrUp 不是降采样的逆操作。这种情况下,图像首先在每个维度上扩大为原来的两倍,新增的行(偶数行) 以 零 填充。然后给指定的滤波器进行卷积(实际上是一个在每个维度都扩大为原来两倍的过滤器) 去估计 “丢失” 像素的近似值。pyrDown() 是一个会丢失信息的函数。为了恢复原来更高的分辨率的图像,需要获得由降采样操作丢失的信息,这些数据就和拉普拉斯金字塔有关系了。

 

2. 高斯金字塔

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

   (2). 对图像的向下采样

         为了获得层级为 \large G_{i + 1} 的金字塔图像,采用如下方法:

          ①. 对图像 \large G_{i} 层进行高斯内核卷积

          ②. 将所有偶数行和列去除

           得到的图像即为 \large G_{i + 1} 层的图像,其图像面积为 \large G_{i} 层的 \large \frac{1}{4} 大小。通过对图像 \large G_{i} (原始图像) 不停地迭代以上步骤就可以得到整个金字塔。向下取样会逐渐丢失图像的信息。

   (3). 对图像的向上采样

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

         ①. 将图像在每个方向扩大为原来的两倍,新增的行和列以 零填充

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

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

 

3. 拉普拉斯金字塔 (应用于图像融合)

   (1). 拉普拉斯金字塔是高斯金字塔的修正版,为了还原到原图。通过 计算残差图来达到还原。

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

           opencv 可用:\large L_{i} = G_{i} - pyrUp(G_{i+1})

          将降采样之后的图像再进行上采样的操作,然后与之前还没降采样的原图进行做差得到残差图。这是为了还原图像做信息准备。也就是说,拉普拉斯金字塔是通过原图像减去缩小再放大的图像的一系列图像构成的。保留的是残差,为图像还原做准备。

 

 

                  

 

返回主目录

返回 图像处理的一些方法 目录

上一章:深度篇——图像处理的一些方法(三)  细说 HOG 特征 与 bag-of-word

2017-12-31 18:51:52 u013162035 阅读数 926
  • 图像金字塔

    学完本课程,可以牢固掌握人工智能计算机视觉的基础知识与常见算法,对图像处理、图像分析可以理解与应用 掌握python opencv框架编程与相关算法原理与函数使用,可以完成基础的图像处理与图像分析项目任务 为进一步...

    165人学习 贾志刚
    免费试看

1.6图像金字塔

1.6.1关于图像金字塔

图像金字塔是图像中多尺度表达的一种,最主要用于图像的分割,是一种以多分辨率来解释图像的有效但概念简单的结构。
图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。其通过梯次向下采样获得,直到达到某个终止条件才停止采样。
金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。我们将一层一层的图像比喻成金字塔,层级越高,则图像越小,分辨率越低。

这里写图片描述

图1

一般情况下有两种类型的图像金字塔常常出现在文献和以及实际运用中。他们分别是:
•高斯金字塔(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( )是一个会丢失信息的函数。为了恢复原来更高的分辨率的图像,我们要获得由降采样操作丢失的信息,这些数据就和拉普拉斯金字塔有关系了。

1.6.1.1高斯金字塔

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

这里写图片描述

图2

另外,每一层都按从下到上的次序编号, 层级 G_i+1 (表示为 G_i+1尺寸小于第i层G_i)。
1)对图像的向下取样
为了获取层级为 G_i+1 的金字塔图像,我们采用如下方法:
1>对图像G_i进行高斯内核卷积;
2>将所有偶数行和列去除。
得到的图像即为G_i+1的图像,显而易见,结果图像只有原图的四分之一。通过对输入图像G_i(原始图像)不停迭代以上步骤就会得到整个金字塔。同时我们也可以看到,向下取样会逐渐丢失图像的信息。以上就是对图像的向下取样操作,即缩小图像。
2)对图像的向上取样
如果想放大图像,则需要通过向上取样操作得到,具体做法如下:
1>将图像在每个方向扩大为原来的两倍,新增的行和列以0填充
2>使用先前同样的内核(乘以4)与放大后的图像卷积,获得 “新增像素”的近似值
得到的图像即为放大后的图像,但是与原来的图像相比会发觉比较模糊,因为在缩放的过程中已经丢失了一些信息,如果想在缩小和放大整个过程中减少信息的丢失,这些数据形成了拉普拉斯金字塔。
那么,我们接下来一起看一看拉普拉斯金字塔的概念吧。

1.6.1.2拉普拉斯金字塔

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

这里写图片描述

式中G_i的表示第i层的图像。而UP()操作是将源图像中位置为(x,y)的像素映射到目标图像的(2x+1,2y+1)位置,即在进行向上取样。 符号表示卷积,g_(5×5)为5x5的高斯内核。
我们下文将要介绍的pryUp,就是在进行上面这个式子的运算。
因此,我们可以直接用OpenCV进行拉普拉斯运算:
Li=GiPyrUp(Gi+1)

也就是说,拉普拉斯金字塔是通过源图像减去先缩小后再放大的图像的一系列图像构成的。个拉普拉斯金字塔运算过程可以通过下图来概括:
这里写图片描述

图3

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

1.6.2 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(效率较高,速度较快,推荐使用)。
关于插值,我们看几张图就能更好地理解。先看原图:

这里写图片描述

图4

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

图5

效果很明显,第一张全是一个个的像素,非常影响美观。另外一张却有雾化的朦胧美感,所以插值方式的选择,对经过多次放大缩小的图片最终得到的效果是有很大影响的。
接着我们来看两种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);  

接着我们看看完整的示例程序。
代码参看附件【demo1】,程序运行截图。

这里写图片描述

图6

1.6.3 pyrUp()函数剖析

/*【pyrUp ( )函数源代码】**********************************************************
 * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)  
 * @源码路径:…\opencv\sources\modules\imgproc\src\pyramids.cpp
 * @起始行数:1246行   
********************************************************************************/
void cv::pyrUp( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
{
    CV_Assert(borderType == BORDER_DEFAULT);

    CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
               ocl_pyrUp(_src, _dst, _dsz, borderType))

    Mat src = _src.getMat();
    Size dsz = _dsz.area() == 0 ? Size(src.cols*2, src.rows*2) : _dsz;
    _dst.create( dsz, src.type() );
    Mat dst = _dst.getMat();
    int depth = src.depth();

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

#if IPP_VERSION_X100 >= 801 && 0
    CV_IPP_CHECK()
    {
        bool isolated = (borderType & BORDER_ISOLATED) != 0;
        int borderTypeNI = borderType & ~BORDER_ISOLATED;
        if (borderTypeNI == BORDER_DEFAULT && (!src.isSubmatrix() || isolated) && dsz == Size(src.cols*2, src.rows*2))
        {
            typedef IppStatus (CV_STDCALL * ippiPyrUp)(const void* pSrc, int srcStep, void* pDst, int dstStep, IppiSize srcRoi, Ipp8u* buffer);
            int type = src.type();
            CV_SUPPRESS_DEPRECATED_START
            ippiPyrUp pyrUpFunc = type == CV_8UC1 ? (ippiPyrUp) ippiPyrUp_Gauss5x5_8u_C1R :
                                  type == CV_8UC3 ? (ippiPyrUp) ippiPyrUp_Gauss5x5_8u_C3R :
                                  type == CV_32FC1 ? (ippiPyrUp) ippiPyrUp_Gauss5x5_32f_C1R :
                                  type == CV_32FC3 ? (ippiPyrUp) ippiPyrUp_Gauss5x5_32f_C3R : 0;
            CV_SUPPRESS_DEPRECATED_END

            if (pyrUpFunc)
            {
                int bufferSize;
                IppiSize srcRoi = { src.cols, src.rows };
                IppDataType dataType = depth == CV_8U ? ipp8u : ipp32f;
                CV_SUPPRESS_DEPRECATED_START
                IppStatus ok = ippiPyrUpGetBufSize_Gauss5x5(srcRoi.width, dataType, src.channels(), &bufferSize);
                CV_SUPPRESS_DEPRECATED_END
                if (ok >= 0)
                {
                    Ipp8u* buffer = ippsMalloc_8u(bufferSize);
                    ok = pyrUpFunc(src.data, (int) src.step, dst.data, (int) dst.step, srcRoi, buffer);
                    ippsFree(buffer);

                    if (ok >= 0)
                    {
                        CV_IMPL_ADD(CV_IMPL_IPP);
                        return;
                    }
                    setIppErrorStatus();
                }
            }
        }
    }
#endif

    PyrFunc func = 0;
    if( depth == CV_8U )
        func = pyrUp_<FixPtCast<uchar, 6>, PyrUpVec_32s8u >;
    else if( depth == CV_16S )
        func = pyrUp_<FixPtCast<short, 6>, PyrUpVec_32s16s >;
    else if( depth == CV_16U )
        func = pyrUp_<FixPtCast<ushort, 6>, PyrUpVec_32s16u >;
    else if( depth == CV_32F )
        func = pyrUp_<FltCast<float, 6>, PyrUpVec_32f >;
    else if( depth == CV_64F )
        func = pyrUp_<FltCast<double, 6>, PyrUpNoVec<double, double> >;
    else
        CV_Error( CV_StsUnsupportedFormat, "" );

    func( src, dst, borderType );
}

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的内核做卷积,就是这样。直接看完整的示例程序。
代码参看附件【demo2】,程序运行截图。

这里写图片描述

图7

1.6.4 pyrDown()函数剖析

/*【pyrDown ( )函数源代码】**********************************************************
 * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)  
 * @源码路径:…\opencv\sources\modules\imgproc\src\pyramids.cpp
 * @起始行数:1169行   
********************************************************************************/
void cv::pyrDown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
{
    CV_Assert(borderType != BORDER_CONSTANT);

    CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
               ocl_pyrDown(_src, _dst, _dsz, borderType))

    Mat src = _src.getMat();
    Size dsz = _dsz.area() == 0 ? Size((src.cols + 1)/2, (src.rows + 1)/2) : _dsz;
    _dst.create( dsz, src.type() );
    Mat dst = _dst.getMat();
    int depth = src.depth();

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

#if IPP_VERSION_X100 >= 801 && 0
    CV_IPP_CHECK()
    {
        bool isolated = (borderType & BORDER_ISOLATED) != 0;
        int borderTypeNI = borderType & ~BORDER_ISOLATED;
        if (borderTypeNI == BORDER_DEFAULT && (!src.isSubmatrix() || isolated) && dsz == Size((src.cols + 1)/2, (src.rows + 1)/2))
        {
            typedef IppStatus (CV_STDCALL * ippiPyrDown)(const void* pSrc, int srcStep, void* pDst, int dstStep, IppiSize srcRoi, Ipp8u* buffer);
            int type = src.type();
            CV_SUPPRESS_DEPRECATED_START
            ippiPyrDown pyrDownFunc = type == CV_8UC1 ? (ippiPyrDown) ippiPyrDown_Gauss5x5_8u_C1R :
                                      type == CV_8UC3 ? (ippiPyrDown) ippiPyrDown_Gauss5x5_8u_C3R :
                                      type == CV_32FC1 ? (ippiPyrDown) ippiPyrDown_Gauss5x5_32f_C1R :
                                      type == CV_32FC3 ? (ippiPyrDown) ippiPyrDown_Gauss5x5_32f_C3R : 0;
            CV_SUPPRESS_DEPRECATED_END

            if (pyrDownFunc)
            {
                int bufferSize;
                IppiSize srcRoi = { src.cols, src.rows };
                IppDataType dataType = depth == CV_8U ? ipp8u : ipp32f;
                CV_SUPPRESS_DEPRECATED_START
                IppStatus ok = ippiPyrDownGetBufSize_Gauss5x5(srcRoi.width, dataType, src.channels(), &bufferSize);
                CV_SUPPRESS_DEPRECATED_END
                if (ok >= 0)
                {
                    Ipp8u* buffer = ippsMalloc_8u(bufferSize);
                    ok = pyrDownFunc(src.data, (int) src.step, dst.data, (int) dst.step, srcRoi, buffer);
                    ippsFree(buffer);

                    if (ok >= 0)
                    {
                        CV_IMPL_ADD(CV_IMPL_IPP);
                        return;
                    }
                    setIppErrorStatus();
                }
            }
        }
    }
#endif

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

    func( src, dst, borderType );
}

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)来进行计算,且一直需要满足下列条件:

|dstsize.width2src.cols|2|dstsize.height2src.rows|2

该pyrDown函数执行了高斯金字塔建造的向下采样的步骤。首先,它将源图像与如下内核做卷积运算:

12561464141624164624362464162416414641

接着,它便通过对图像的偶数行和列做插值来进行向下采样操作。依然是看看完整的示例程序。
代码参看【demo3】,程序运行截图。

这里写图片描述

图8

1.6.5图像金字塔综合实例

这个示例程序中,分别演示了用resize,pryUp,pryDown来让源图像进行放大缩小的操作,分别用键盘按键1、2、3、4、A、D、W、S来控制图片的放大与缩小。
代码参看附件【demo4】。

这里写图片描述

图9经过多次按键后的效果

参考:
英文:https://docs.opencv.org/master/d4/d1f/tutorial_pyramids.html
中文:
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/pyramids/pyramids.html#pyramids

本章附件:

请点击参考链接

【注意】博主在附件中的代码只有Linux版本的,如何使用Windows使用该代码请参看博主的另一篇博文
Opencv环境搭建(Visual Studio+Windows)- 请点击
有任何问题请联系博主。

2019-05-13 10:38:49 zaishuiyifangxym 阅读数 2714
  • 图像金字塔

    学完本课程,可以牢固掌握人工智能计算机视觉的基础知识与常见算法,对图像处理、图像分析可以理解与应用 掌握python opencv框架编程与相关算法原理与函数使用,可以完成基础的图像处理与图像分析项目任务 为进一步...

    165人学习 贾志刚
    免费试看

目录

1 图像金字塔简介

2 向下取样——pyrDown()

2.1 基础理论

2.2 代码示例

3 向上取样——pyrUp()

3.1 基础理论

3.2 代码示例

4 Laplacian 金字塔

4.1 基础理论

4.2 代码示例

参考资料


 

1 图像金字塔简介

以多个分辨率来表示图像的一种有效且概念简单的结构是图像金字塔图像金字塔最初用于机器视觉和图像压缩,一个图像金字是一系列以金字塔形状排列的、分辨率逐步降低的图像集合。

如图下图所示,它包括了四层图像,将这一层一层的图像比喻成金字塔。图像金字塔可以通过梯次向下采样获得,直到达到某个终止条件才停止采样,在向下采样中,层级越高,则图像越小,分辨率越低。

 

生成图像金字塔主要包括两种方式:向下取样向上取样

如下图所示:

向下取样:将图像从G0转换为G1、G2、G3,图像分辨率不断降低的过程;

向上取样:将图像从G3转换为G2、G1、G0,图像分辨率不断增大的过程。

下面将依次介绍向下取样 和 向上取样

 


2 向下取样——pyrDown()

2.1 基础理论

在图像向下取样中,一般分两步:

(1)对图像Gi进行高斯卷积核(高斯滤波);

(2)删除所有的偶数行和列。

 

其中,高斯核卷积运算(高斯滤波)就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值(权重不同)经过加权平均后得到。常见的 3\times3 和 5\times5 高斯核如下:

                                                                              K(3,3)=\frac{1}{16}\times \left[ \begin{matrix} 1 & 2 & 1 \\ 2 & 4 & 2 \\ 1 & 2 & 1 \\ \end{matrix} \right]

                                                                     K(5,5)=\frac{1}{273}\times \left[ \begin{matrix} 1 & 4 & 7 & 4 & 1 \\ 4 & 16 & 26 & 16 & 4 \\ 7 & 26 & 41 & 26 & 7 \\ 4 & 16 & 26 & 16 & 4 \\ 1 & 4 & 7 & 4 & 1 \\ \end{matrix} \right]

关于高斯滤波的详细过程,可以参见博客:图像平滑 (均值滤波、中值滤波和高斯滤波)

 

如下图所示,向下取样后,原始图像 G_i 具有 M\timesN 个像素,进行向下取样之后,所得到的图像 G_i+1 具有 M/2 \times N/2 个像素,只有原图的四分之一。通过对输入的原始图像不停迭代以上步骤就会得到整个金字塔。

:由于每次向下取样会删除偶数行和列,所以它会不停地丢失图像的信息。

 

下面是向下取样的图像,可以看到图像不断缩小。

 

 

2.2 代码示例

在OpenCV中,向下取样使用的函数为pyrDown(),其函数用法如下所示:

dst = pyrDown(src[, dst[, dstsize[, borderType]]])

其中,参数:

src 表示输入图像;

dst 表示输出图像,和输入图像具有一样的尺寸和类型;

dstsize 表示输出图像的大小,默认值为Size();

borderType 表示像素外推方法,详见cv::bordertypes 。

 

(1)一次向下采样

代码如下所示:

# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt

#读取原始图像
img = cv2.imread('zxp.jpg')

#图像向下取样
r = cv2.pyrDown(img)

#显示图像
cv2.imshow('original', img)
cv2.imshow('PyrDown', r)

cv2.waitKey()
cv2.destroyAllWindows()

 

运行结果如下图所示:

 

(2)多次向下采样

代码如下所示:

# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt

#读取原始图像
img = cv2.imread('zxp.jpg')

#图像向下取样
r1 = cv2.pyrDown(img)
r2 = cv2.pyrDown(r1)
r3 = cv2.pyrDown(r2)

#显示图像
cv2.imshow('original', img)
cv2.imshow('PyrDown1', r1)
cv2.imshow('PyrDown2', r2)
cv2.imshow('PyrDown3', r3)

cv2.waitKey()
cv2.destroyAllWindows()

 

运行结果如下图所示:

 


3 向上取样——pyrUp()

3.1 基础理论

在图像向上取样是由小图像不断放图像的过程。它将图像在每个方向上扩大为原图像的2倍,新增的行和列均用0来填充,并使用与“向下取样”相同的卷积核乘以4,再与放大后的图像进行卷积运算,以获得“新增像素”的新值。

 

如图下图所示,它在原始像素45、123、89、149之间各新增了一行和一列值为0的像素。

 

如下图所示,为图像的向上采样和向下采样的例子。

注:向上取样和向下取样无法互逆的。

 

 

3.2 代码示例

在OpenCV中,向上取样使用 pyrUp() 函数,其函数用法如下所示:

dst = pyrUp(src[, dst[, dstsize[, borderType]]])

其中,参数:

src 表示输入图像;

dst 表示输出图像,和输入图像具有一样的尺寸和类型;

dstsize 表示输出图像的大小,默认值为Size();

borderType 表示像素外推方法,详见cv::bordertypes 。

 

代码如下所示:

# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt

#读取原始图像
img = cv2.imread('zxp_PyrDown2.jpg')

#图像向上取样
r = cv2.pyrUp(img)

#显示图像
cv2.imshow('original', img)
cv2.imshow('PyrUp', r)
cv2.waitKey()
cv2.destroyAllWindows()

 

运行结果如下图所示:

 


4 Laplacian 金字塔

4.1 基础理论

前面提到的均是高斯金字塔(使用高斯核),下面介绍拉普拉斯(Laplacian) 金字塔拉普拉斯(Laplacian) 金字塔是在高斯金字塔的基础上新的金字塔。

如下图所示,拉普拉斯(Laplacian) 金字塔的表达式:

 

拉普拉斯每一层表示如下图所示:

 

下图高斯金字塔和拉普拉斯金字塔 交叉使用得到不同的图像。

 

 

 

4.2 代码示例

 

(1) 拉普拉斯第0层

代码如下所示:

# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt

#读取原始图像
img = cv2.imread('lena.tiff')

#图像向下取样
r1 = cv2.pyrDown(img)

#图像向上取样
r2 = cv2.pyrUp(r1)

# 拉普拉斯第0层
LapPyr0 =img-r2



#显示图像
cv2.imshow('original', img)
cv2.imshow('LapPyr', LapPyr0)
cv2.waitKey()
cv2.destroyAllWindows()

 

运行结果如下图所示:

 

 

(2) 拉普拉斯第0层和拉普拉斯第1层

代码如下所示:

# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt

#读取原始图像
img = cv2.imread('lena.tiff')

#图像向下取样
r1 = cv2.pyrDown(img)

#图像向上取样
r2 = cv2.pyrUp(r1)

# 拉普拉斯第0层
LapPyr0 =img-r2



#图像向下取样
r3 = cv2.pyrDown(r1)

#图像向上取样
r4 = cv2.pyrUp(r3)

# 拉普拉斯第1层
LapPyr1 =r1-r4

#显示图像
cv2.imshow('original', img)
cv2.imshow('LapPyr0', LapPyr0)
cv2.imshow('LapPyr1', LapPyr1)
cv2.waitKey()
cv2.destroyAllWindows()

 

运行结果如下图所示:

 


参考资料

[1] https://blog.csdn.net/Eastmount/article/details/89341077

[2] Python+OpenCV图像处理

[3] 冈萨雷斯. 数字图像处理(第三版) 

2019-07-09 16:26:55 Dillon2015 阅读数 3695
  • 图像金字塔

    学完本课程,可以牢固掌握人工智能计算机视觉的基础知识与常见算法,对图像处理、图像分析可以理解与应用 掌握python opencv框架编程与相关算法原理与函数使用,可以完成基础的图像处理与图像分析项目任务 为进一步...

    165人学习 贾志刚
    免费试看

图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效且概念简单的结构。一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。

高斯金字塔是常见的图像金字塔,如下所示:

高斯金字塔构造过程如下:

  • 对第i层进行高斯滤波,高斯滤波核如下:

     

  • 删除滤波后图像的偶数行和偶数列

经过上面两个步骤得到一个原图1/4大的图像,这便完成了一次降采样。通过反复迭代便可以得到一幅图像的金字塔表示。

可以经过相反步骤完成上采样得到一幅4倍大的图像。

  • 将原图行列都扩大两倍,新增行列用0填充

  • 在扩大后的图像上进行高斯滤波,滤波核为上面的滤波核乘以4

代码

#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
​
int main()
{
    Mat src = imread("G:\\opencvDemo\\lena.jpg");
    Mat dstimage;
    pyrDown(src, dstimage, Size(src.cols / 2, src.rows / 2));
    pyrUp(dstimage, dstimage, Size(dstimage.cols * 2, dstimage.rows * 2));
    imshow("srcImg", src);
    imshow("dstImg", dstimage);
    waitKey(0);
​
    return 0;
}

先将原图缩小然后再放大,结果如下。

原图:

下采样图像:

上采样图像:

OpenCV API

void cv::pyrDown    (   InputArray  src,
                        OutputArray     dst,
                        const Size &    dstsize = Size(),
                        int     borderType = BORDER_DEFAULT 
                        )   
    src : 输入图像
    dst : 输出图像,和输入图像类型相同
    dstsize : 输出图像尺寸,默认为Size((src.cols+1)/2, (src.rows+1)/2),且无论如何设置输出尺寸都必须满足
    |dstsize.width*2-src.cols| ≦ 2
    |dstsize.height*2-src.rows| ≦ 2
    borderType : 边界填充方式
void cv::pyrUp  (   InputArray  src,
                    OutputArray     dst,
                    const Size &    dstsize = Size(),
                    int     borderType = BORDER_DEFAULT 
                    )   
    src : 输入图像
    dst : 输出图像,和输入图像类型相同
    dstsize : 输出图像尺寸,默认为Size((src.cols+1)*2, (src.rows+1)*2),且无论如何设置输出尺寸都必须满足
    |dstsize.width-src.cols*2| ≦ (dstsize.width mod 2)
    |dstsize.height-src.rows*2| ≦ (dstsize.height mod 2)
    borderType : 边界填充方式

总结

可以看出图像降采样后会丢失部分图像信息,上采样的图像和原图比已经产生失真。

对于图像缩放有很多resize()方法和插值方法,图像金字塔主要用于图像的多尺度表示。在图像识别、匹配等方面用的比较多。

 

2013-08-27 09:53:20 taoyanbian1022 阅读数 2868
  • 图像金字塔

    学完本课程,可以牢固掌握人工智能计算机视觉的基础知识与常见算法,对图像处理、图像分析可以理解与应用 掌握python opencv框架编程与相关算法原理与函数使用,可以完成基础的图像处理与图像分析项目任务 为进一步...

    165人学习 贾志刚
    免费试看

以多分辨率来解释图像的一种有效但概念简单的结构就是图像金字塔。一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低的图像集合。金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。当向金字塔的上层移动时,尺寸和分辨率就降低。
对于一幅尺寸为2^J*2^J的图像,则其图像金字塔中间级的尺寸是2^j*2^j,其中j的理论取值返回是0,1,2,...,(J-1),J。但是由于当j很小时,图像将丢失大部分信息,所以一般限制只用P+1级来减少原来图像近似值的尺寸,也就是j的实际取值是(J-P),(J-P+1),...(J-1),J。
而一般处理这种分辨率变化,简单的方法就是隔行取值来生成低分辨率的图像,复杂点的方法就涉及到图像的内插和过滤等步骤了,当然复杂点的方法使得生成的低分辨率下的图像更加平滑和真实。对某幅原始图像生成了一系列的低分辨率图像之后,这些图像和原始图像一起就形成了图像金字塔。
例如,对于512*512的图像,该图像的4级图像金字塔就是:

  1. 金字塔顶层   64*64
  2.     |     128*128
  3.     |     256*256
  4. 金字塔底层 512*512

当然,有时候也会对原图像进行扩展,生成分辨率更高的图像,然后把这个图像放到金字塔的更底层。这时候就需要更多处理,使得生成的图像保持真实性,避免色块和噪声等的产生。

在matlab里面,函数impyramid专门用于生成图像金字塔,直接调用就可以了。
格式:B = impyramid(A, direction)
作用:对A进行Gaussian金字塔变换,生成的图像是B。direction为“reduce”和“expand”,分别对应着分解和扩张。
注:
1.m*n的A“reduce”和“expand”后的维数分别对应ceil(M/2)*ceil(N/2)和(2*M-1)*(2*N-1)。
2.impyramid只对前两维有效。