opencv图像的金字塔

目标:在本文中你将学到怎么样使用opencv的pyrUp和pyrDown函数,对图像进行向上采样和向下采样。

参考:http://docs.opencv.org/2.4/doc/tutorials/imgproc/pyramids/pyramids.html#pyramids

参考:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/pyramids/pyramids.html#pyramids

pyrUp

Upsamples an image and then blurs it.

C++: void pyrUp(InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT )
Python: cv2.pyrUp(src[, dst[, dstsize[, borderType]]]) → dst
C: cvPyrUp(const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 )
Parameters:
  • src – input image.
  • dst – output image. It has the specified size and the same type as src .
  • dstsize – size of the output image.
  • borderType – Pixel extrapolation method (only BORDER_DEFAULT supported). SeeborderInterpolate for details.

By default, size of the output image is computed as Size(src.cols*2, (src.rows*2), but in any case, the following conditions should be satisfied:

\begin{array}{l}| \texttt{dstsize.width} -src.cols*2| \leq  ( \texttt{dstsize.width}   \mod  2)  \\ | \texttt{dstsize.height} -src.rows*2| \leq  ( \texttt{dstsize.height}   \mod  2) \end{array}

The function performs the upsampling step of the Gaussian pyramid construction, though it can actually be used to construct the Laplacian pyramid. First, it upsamples the source image by injecting even zero rows and columns and then convolves the result with the same kernel as in pyrDown() multiplied by 4.

Note

  • (Python) An example of Laplacian Pyramid construction and merging can be found at opencv_source_code/samples/python2/lappyr.py

pyrDown

Blurs an image and downsamples it.

C++: void pyrDown(InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT )
Python: cv2.pyrDown(src[, dst[, dstsize[, borderType]]]) → dst
C: void cvPyrDown(const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 )
Parameters:
  • src – input image.
  • dst – output image; it has the specified size and the same type as src.
  • dstsize – size of the output image.
  • borderType – Pixel extrapolation method (BORDER_CONSTANT don’t supported). SeeborderInterpolate for details.

By default, size of the output image is computed as Size((src.cols+1)/2, (src.rows+1)/2), but in any case, the following conditions should be satisfied:

\begin{array}{l}| \texttt{dstsize.width} *2-src.cols| \leq  2  \\ | \texttt{dstsize.height} *2-src.rows| \leq  2 \end{array}

The function performs the downsampling step of the Gaussian pyramid construction. First, it convolves the source image with the kernel:

\frac{1}{256} \begin{bmatrix} 1 & 4 & 6 & 4 & 1  \\ 4 & 16 & 24 & 16 & 4  \\ 6 & 24 & 36 & 24 & 6  \\ 4 & 16 & 24 & 16 & 4  \\ 1 & 4 & 6 & 4 & 1 \end{bmatrix}

Then, it downsamples the image by rejecting even rows and columns.

原理

  • 当我们需要将图像转换到另一个尺寸的时候, 有两种可能:
    1. 放大 图像 
    2. 缩小 图像。
  • 尽管OpenCV 几何变换 部分提供了一个真正意义上的图像缩放函数(resize, 在以后的教程中会学到),不过在本篇我们首先学习一下使用 图像金字塔 来做图像缩放, 图像金字塔是视觉运用中广泛采用的一项技术。

图像金字塔

  • 一个图像金字塔是一系列图像的集合 - 所有图像来源于同一张原始图像 - 通过梯次向下采样获得,直到达到某个终止条件才停止采样。
  • 有两种类型的图像金字塔常常出现在文献和应用中:
    • 高斯金字塔(Gaussian pyramid): 用来向下采样
    • 拉普拉斯金字塔(Laplacian pyramid): 用来从金字塔低层图像重建上层未采样图像
高斯金字塔
  • 想想金字塔为一层一层的图像,层级越高,图像越小。

    Pyramid figure
  • 每一层都按从下到上的次序编号, 层级 (i+1) (表示为 G_{i+1} 尺寸小于层级 i (G_{i}))。

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

    • 将 G_{i} 与高斯内核卷积:

      \frac{1}{256} \begin{bmatrix} 1 & 4 & 6 & 4 & 1  \\ 4 & 16 & 24 & 16 & 4  \\ 6 & 24 & 36 & 24 & 6  \\ 4 & 16 & 24 & 16 & 4  \\ 1 & 4 & 6 & 4 & 1 \end{bmatrix}

    • 将所有偶数行和列去除。

  • 显而易见,结果图像只有原图的四分之一。通过对输入图像 G_{0} (原始图像) 不停迭代以上步骤就会得到整个金字塔。

  • 以上过程描述了对图像的向下采样,如果将图像变大呢?:

    • 首先,将图像在每个方向扩大为原来的两倍,新增的行和列以0填充(0)
    • 使用先前同样的内核(乘以4)与放大后的图像卷积,获得 “新增像素” 的近似值。
  • 这两个步骤(向下和向上采样) 分别通过OpenCV函数 pyrUp 和 pyrDown 实现, 我们将会在下面的示例中演示如何使用这两个函数。

Note

 

我们向下采样缩小图像的时候, 我们实际上 丢失 了一些信息。

源码

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"


using namespace cv;

/// 全局变量
Mat src, dst, tmp;
char* window_name = "Pyramids Demo";


/**
 * @函数 main
 */
int main( int argc, char** argv )
{
  /// 指示说明
  printf( "\n Zoom In-Out demo  \n " );
  printf( "------------------ \n" );
  printf( " * [u] -> Zoom in  \n" );
  printf( " * [d] -> Zoom out \n" );
  printf( " * [ESC] -> Close program \n \n" );

  /// 测试图像 - 尺寸必须能被 2^{n} 整除
  src = imread( "../images/chicky_512.jpg" );
  if( !src.data )
    { printf(" No data! -- Exiting the program \n");
      return -1; }

  tmp = src;
  dst = tmp;

  /// 创建显示窗口
  namedWindow( window_name, CV_WINDOW_AUTOSIZE );
  imshow( window_name, dst );

  /// 循环在图片上按u.d或esc会得到结果
  while( true )
  {
    int c;
    c = waitKey(10);

    if( (char)c == 27 )
      { break; }
    if( (char)c == 'u' )
      { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
        printf( "** Zoom In: Image x 2 \n" );
      }
    else if( (char)c == 'd' )
     { pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );
       printf( "** Zoom Out: Image / 2 \n" );
     }

    imshow( window_name, dst );
    tmp = dst;
  }
  return 0;
}

解释

  1. 让我们来回顾一下本程序的总体流程:

    • 装载图像(此处路径由程序设定,用户无需将图像路径当作参数输入)

      /// 测试图像 - 尺寸必须能被 2^{n} 整除
      src = imread( "../images/chicky_512.jpg" );
      if( !src.data )
        { printf(" No data! -- Exiting the program \n");
          return -1; }
      
    • 创建两个Mat实例, 一个用来储存操作结果(dst), 另一个用来存储零时结果(tmp)。

      Mat src, dst, tmp;
      /* ... */
      tmp = src;
      dst = tmp;
      
    • 创建窗口显示结果

      namedWindow( window_name, CV_WINDOW_AUTOSIZE );
      imshow( window_name, dst );
      
    • 执行无限循环,等待用户输入。

      while( true )
      {
        int c;
        c = waitKey(10);
      
        if( (char)c == 27 )
          { break; }
        if( (char)c == 'u' )
          { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
            printf( "** Zoom In: Image x 2 \n" );
          }
        else if( (char)c == 'd' )
         { pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );
           printf( "** Zoom Out: Image / 2 \n" );
         }
      
        imshow( window_name, dst );
        tmp = dst;
      }
      

      如果用户按 ESC 键程序退出。 此外,它还提供两个选项:

      • 向上采样 (按 ‘u’)

        pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 )
        

        函数 pyrUp 接受了3个参数:

        • tmp: 当前图像, 初始化为原图像 src 。
        • dst: 目的图像( 显示图像,为输入图像的两倍)
        • Size( tmp.cols*2, tmp.rows*2 ) : 目的图像大小, 既然我们是向上采样, pyrUp 期待一个两倍于输入图像( tmp )的大小。
      • 向下采样(按 ‘d’)

        pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 )
        

        类似于 pyrUp, 函数 pyrDown 也接受了3个参数:

        • tmp: 当前图像, 初始化为原图像 src 。
        • dst: 目的图像( 显示图像,为输入图像的一半)
        • Size( tmp.cols/2, tmp.rows/2 ) :目的图像大小, 既然我们是向下采样, pyrDown 期待一个一半于输入图像( tmp)的大小。
      • 注意输入图像的大小(在两个方向)必须是2的冥,否则,将会显示错误。

      • 最后,将输入图像 tmp 更新为当前显示图像, 这样后续操作将作用于更新后的图像。

        tmp = dst;
        

结果

  • 在编译上面的代码之后, 我们可以运行结果。 程序调用了图像 chicky_512.jpg ,你可以在 tutorial_code/image 文件夹找到它。 注意图像大小是 512 \times 512, 因此向下采样不会产生错误(512 = 2^{9})。 原图像如下所示:

    Pyramids: Original image
  • 首先按两次 ‘d’ 连续两次向下采样 pyrDown ,结果如图:

    Pyramids: PyrDown Result
  • 由于我们缩小了图像,我们也因此丢失了一些信息。通过连续按两次 ‘u’ 向上采样两次 pyrUp ,很明显图像有些失真:

    Pyramids: PyrUp Result


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值