OpenCV圖像金字塔

圖像金字塔

目標

本文檔嘗試解答以下問題:html

  • 如何使用OpenCV函數 pyrUp 和 pyrDown 對圖像進行向上和向下採樣。

原理

Noteide

 

如下內容來自於Bradski和Kaehler的大做: Learning OpenCV 。svn

  • 當咱們須要將圖像轉換到另外一個尺寸的時候, 有兩種可能:
    1. 放大 圖像 或者
    2. 縮小 圖像。
  • 儘管OpenCV 幾何變換 部分提供了一個真正意義上的圖像縮放函數(resize, 在之後的教程中會學到),不過在本篇咱們首先學習一下使用 圖像金字塔來作圖像縮放, 圖像金字塔是視覺運用中普遍採用的一項技術。

圖像金字塔

  • 一個圖像金字塔是一系列圖像的集合 - 全部圖像來源於同一張原始圖像 - 經過梯次向下採樣得到,直到達到某個終止條件才中止採樣。
  • 有兩種類型的圖像金字塔經常出如今文獻和應用中:
    • 高斯金字塔(Gaussian pyramid): 用來向下採樣
    • 拉普拉斯金字塔(Laplacian pyramid): 用來從金字塔低層圖像重建上層未採樣圖像
  • 在這篇文檔中咱們將使用 高斯金字塔 。

高斯金字塔

  • 想一想金字塔爲一層一層的圖像,層級越高,圖像越小。函數

    Pyramid figure
  • 每一層都按從下到上的次序編號, 層級 (i+1) (表示爲 G_{i+1} 尺寸小於層級 i (G_{i}))。學習

  • 爲了獲取層級爲 (i+1) 的金字塔圖像,咱們採用以下方法:測試

    • 將 G_{i} 與高斯內核卷積:ui

      \frac{1}{16} \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}

    • 將全部偶數行和列去除。spa

  • 顯而易見,結果圖像只有原圖的四分之一。經過對輸入圖像 G_{0} (原始圖像) 不停迭代以上步驟就會獲得整個金字塔。code

  • 以上過程描述了對圖像的向下採樣,若是將圖像變大呢?:orm

    • 首先,將圖像在每一個方向擴大爲原來的兩倍,新增的行和列以0填充(0)
    • 使用先前一樣的內核(乘以4)與放大後的圖像卷積,得到 「新增像素」 的近似值。
  • 這兩個步驟(向下和向上採樣) 分別經過OpenCV函數 pyrUp 和 pyrDown 實現, 咱們將會在下面的示例中演示如何使用這兩個函數。

Note

 

咱們向下採樣縮小圖像的時候, 咱們實際上 丟失 了一些信息。

源碼

本教程的源碼以下,你也能夠從 這裏 下載

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

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 );

  /// 循環
  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
相關文章
相關標籤/搜索