學習OpenCV範例(十三)——圖像金字塔

以多個分辨率來表示圖像的一種有效且概念簡單的結構是圖像金字塔,一個圖像金字塔是一系列以金子塔形狀排列的、分辨率逐漸降低的圖像集合。——《數字圖像處理》。

圖像金字塔可用於圖像的縮小和放大,在後期的講解中還會涉及到利用圖像金字塔對圖像進行分割。

1、原理

一個圖像金字塔是一系列圖像的集合 - 所有圖像來源於同一張原始圖像 - 通過梯次向下採樣獲得,直到達到某個終止條件才停止採樣。
有兩種類型的圖像金字塔常常出現在文獻和應用中:
高斯金字塔(Gaussian pyramid): 用來向下採樣,主要的圖像金字塔
拉普拉斯金字塔(Laplacian pyramid): 用來從金字塔低層圖像重建上層未採樣圖像,在數字圖像處理中也即是預測殘差,可以對圖像進行最大程度的還原,配合高斯金字塔一起使用。

高斯金字塔

想想金字塔爲一層一層的圖像,層級越高,圖像越小,分辨率越低。

Pyramid figure

每一層都按從下到上的次序編號, 層級 G(i+1) (表示爲 G(i+1) 尺寸小於第i層G(i))。

爲了獲取層級爲 G(i+1) 的金字塔圖像,我們採用如下方法:

①、對圖像G(i)進行高斯內核卷積

②、將所有偶數行和列去除

得到的圖像即爲G(i+1)的圖像,顯而易見,結果圖像只有原圖的四分之一。通過對輸入圖像G(i)(原始圖像)不停迭代以上步驟就會得到整個金字塔。同時我們也可以看到,向下取樣會逐漸丟失圖像的信息。

以上就是對圖像的向下取樣操作,縮小圖像,如果想放大圖像,則需要通過向上取樣操作得到,具體做法如下:

①、將圖像在每個方向擴大爲原來的兩倍,新增的行和列以0填充

②、使用先前同樣的內核(乘以4)與放大後的圖像卷積,獲得 “新增像素” 的近似值

得到的圖像即爲放大後的圖像,但是與原來的圖像相比會發覺比較模糊,因爲在縮放的過程中已經丟失了一些信息,如果想在縮小和放大整個過程中減少信息的丟失,那麼就需要用到拉普拉斯金字塔。

拉普拉斯金字塔

拉普拉斯金字塔第i層的數學定義爲:


UP()操作是對源圖像進行向上取樣,符號叉表示卷積,G爲高斯內核。也即是說拉普拉斯金字塔是通過源圖像減去縮小後再放大的圖像。

整個過程可以由下圖看出:


          圖1、高斯金字塔及其逆形式—拉普拉斯金子塔(圖片來自學習OpenCV)

2、代碼實現

#include "stdafx.h"

#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( "chicky_512.png" );
  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;
}

3、運行結果


                             圖2、原圖


圖3、縮小


                         圖4、放大

4、用到的類和函數

pyrDown:

功能:圖像的下采樣

結構:

void pyrDown(InputArray src, OutputArray dst, const Size& dstsize=Size())
src :源圖像
dst :目標圖像,和源圖像有同樣的size和type
dstsize :目標圖像的Size,默認爲Size((src.cols+1)/2, (src.rows+1)/2),但在任何情況下,下面的條件必須滿足:

\begin{array}{l}| \texttt{dstsize.width} *2-src.cols| \leq  2  \\ | \texttt{dstsize.height} *2-src.rows| \leq  2 \end{array}
高斯內核結構爲:

\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}

首先它對輸入圖像用指定濾波器進行卷積,然後通過拒絕偶數的行與列來下采樣圖像。

pyrUp:

功能:圖像的上採樣

結構:

void pyrUp(InputArray src, OutputArray dst, const Size& dstsize=Size())
src :源圖像
dst :目標圖像,和源圖像有同樣的size和type
dstsize :目標圖像的Size,默認爲
Size(src.cols*2, (src.rows*2),但在任何情況下,下面的條件必須滿足:
\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}

首先通過在圖像中插入 0 偶數行和偶數列,然後對得到的圖像用指定的濾波器進行高斯卷積,其中濾波器乘以4做插值。所以輸出圖像是輸入圖像的 4 倍大小。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章