图像金字塔

理论

 - 通常我们会把图像转换为不同的大小。通常存在两种不同的选择:

 1. 放大
 2. 缩小
- 尽管在OpenCV中存在函数来进行几何转换(cv::resize,在后面会用到),在这一部分我们首先分析使用图像金字塔,它在视觉应用中被广泛应用。

图像金字塔

  • 图像金字塔是一系列图像,所有的这些图像都来源于原始图像,连续降低采样得到。
  • 有两种常见的图像金字塔

    • Gaussian 金字塔:来进行降低采样
    • Laplacian 金字塔:来进行上采样
  • 在本部分介绍Gaussian 金字塔

Gaussian 金字塔

  • 设想金字塔是一系列的图层,越向上层尺寸越小。


  • 图层的序号从底到上递增,所以 (i+1) 代表 Gi+1 ,它比 Gi 小 。
  • 为了得到Gaussian 金字塔中的 (i+1) 层,我们需要:

    • 使用Gaussian 核对 Gi 进行卷积。

      1161464141624164624362464162416414641
    • 移除每一个偶数行和列
  • 你会很容易的发现,得到的结果是前一个图像的四分之一,这样迭代下去,原始图像 G0 产生出整个金字塔。

  • 以上是进行降低采样的程序,如果我们要对图像进行扩大怎么办?难道将整个列填充为0?
    • 首先,将图像每个维度扩大为原来的二倍。
    • 使用同样的卷积核,计算出丢失的值。
  • 这两个过程,加降低采样和上采样,在OpenCV中使用 cv::pyrUp 和cv::pyrDown 实现,我们在后面的代码中会用到。

代码

下面是示例代码,你可以从这里下载

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
Mat src, dst, tmp;
const char* window_name = "Pyramids Demo";
int main( void )
{
  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" );
  src = imread( "../data/chicky_512.png" ); // Loads the test image
  if( src.empty() )
    { printf(" No data! -- Exiting the program \n");
      return -1; }
  tmp = src;
  dst = tmp;
  imshow( window_name, dst );
  for(;;)
  {
    char c = (char)waitKey(0);
    if( c == 27 )
      { break; }
    if( c == 'u' )
      { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
        printf( "** Zoom In: Image x 2 \n" );
      }
    else if( 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;
}

代码说明

我们来看一看代码结构:

  • 加载图像
 src = imread( "../data/chicky_512.png" ); // Loads the test image
  if( src.empty() )
    { printf(" No data! -- Exiting the program \n");
      return -1; }
  • 创建Mat 对象dst来保存操作结果,tmp对象保存临时结果
Mat src, dst, tmp;
/* ... */
tmp = src;
dst = tmp;
  • 创建窗口来显示结果
imshow( window_name, dst );
  • 创建一个无限循环等待用户输入
 for(;;)
  {
    char c = (char)waitKey(0);
    if( c == 27 )
      { break; }
    if( c == 'u' )
      { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
        printf( "** Zoom In: Image x 2 \n" );
      }
    else if( 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’执行升采样
if( c == 'u' )
      { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
        printf( "** Zoom In: Image x 2 \n" );
      }

我们使用的 cv::pyrUp函数有三个参数:

tmp:当前对象,由原始图像初始化。
dst:输出对象,默认是输入图像的二倍。
Size( tmp.cols*2, tmp.rows*2 ) :目标对象大小,这里是上升采样,所以 cv::pyrUp 期望的输出是输入的二倍。

  • 按下’d’执行降采样
 else if( c == 'd' )
      { pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );
        printf( "** Zoom Out: Image / 2 \n" );
      }

与上面类似cv::pyrDown 也有三个参数:
tmp:当前对象,由原始图像初始化。
dst:输出对象,默认是输入图像的一半
Size( tmp.cols/, tmp.rows/2 ) :目标对象大小,这里是上升采样,所以 cv::pyrUp 期望的输出是输出的一半。

  • 注意到输入图像必须能够被2整除,否则会报错。

  • 我们使用输出结果更新tmp,这样它可以作为下一轮操作的输入。

结果

  • 在编译之后,图像chicky_512.jpg位于 samples/data文件夹下。这个图像大小 512×512 ,因此进行降采样不会产生错误。原始图像如下。


  • 现在我们进行连续两次的cv::pyrDown操作结果如下。


  • 我们在执行两次cv::pyrUp操作,会发现我们丢失了一些信息。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值