OpenCV2馬拉松第7圈——圖像金字塔

收入囊中

  • 高斯金字塔
  • 拉普拉斯金字塔
葵花寶典

圖像金字塔是一系列的圖像集合,都是從單張圖片獲得的,連續做下采樣(downsample)直到預設停止條件.最常用的是兩種,高斯金字塔和拉普拉斯金字塔。[當然還有其他的金字塔,比如小波金字塔]

高斯金字塔

對一張圖像不斷的模糊之後向下採樣,得到不同分辨率的圖像,同時每次得到的新的圖像寬與高是原來圖像的1/2, 最常見就是基於高斯的模糊之後採樣,得到的

一系列圖像稱爲高斯金字塔。


原圖來自http://blog.csdn.net/jia20003/article/details/9116931


最底層我們成爲G0,往上分別是G1,G2...

如何對圖片作下采樣呢?
  1. 高斯模糊[用如下卷積,注意要除以256,用上之前的知識,這是一個可分離的濾波,所以只需要2K次計算,不需要K^2]                                                    
    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
  2. 去掉所有的偶數行和偶數列
提到下采樣,就不得不提上採樣(構建拉普拉斯金字塔也會用到)

如何對圖片作上採樣呢?
我們看看OpenCV是如何做的吧
  1. 每個維度都擴大兩倍並插入0,也就是f(2i,2j) = f(i,j) , f(2i+1,2j+1) = 0
  2. 再用相同的高斯核進行高斯卷積,結果再乘4

拉普拉斯金字塔
高斯金字塔不同(DoG)又稱爲拉普拉斯金字塔,給出計算方式前,先加強一下定義
記得在上面我們定義了G0,G1,G2
G0下采樣獲得G1
G1上採樣獲得Upsample(G1),注意Upsample(G1)不等於G0,上採樣和下采樣不是可逆過程,這是因爲下采樣損失了圖片信息
在此,給出計算拉普拉斯金字塔(DOG)的公式:L(i) = G(i) – Upsample(G(i+1))

DOG有很多用處,非常流行的SIFT特徵第一步就是DOG

初識API
C++: void pyrDown(InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT )
 
  • src – 輸入圖像
  • dst – 輸出圖像
  • dstsize – 輸出圖像的size


C++: void pyrUp(InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT )
 
  • src – 輸入圖像
  • dst – 輸出圖像
  • dstsize – 輸出圖像的size


還有一個很方便的函數,直接幫你構建了高斯金字塔

C++: void buildPyramid(InputArray src, OutputArrayOfArrays dst, int maxlevel, int borderType=BORDER_DEFAULT )
 
  • src – 輸入圖像
  • dst – 這是一個存儲(maxlevel+1)的向量,dst[0]和源圖像一樣,dst[1]是第一次下采樣
  • maxlevel – 指定採樣級數,必須爲非負數

內部實現是不斷call pyrDown() 


荷槍實彈
第一個例子就是OpenCV自己的sample,使用PyrDown和PyrUp
#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;
const char* window_name = "Pyramids Demo";
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" );

  src = imread(argv[1]);
  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 );

  for(;;)
  {
    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;
}

下面我們就用buildPyramid和PyrUp來建立DOG(拉普拉斯金字塔)
先看一下我們的源圖片


再看一下獲得的DOG,請仔細看


代碼也非常簡單,完全不用解釋
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <sstream>

using namespace cv;
using namespace std;

Mat src,tmp;
vector<Mat>gaussPyrs;
vector<Mat>DOG;
int maxLevel = 3;

int main(int argc,char **argv)
{
  	src = imread(argv[1]);
  	if( !src.data ){ 
  		printf(" No data! -- Exiting the program \n");
      	return -1; 
	}

	buildPyramid(src, gaussPyrs, maxLevel);
	
	for(int i = 0;i < maxLevel;i++){
		Size ss;
		pyrUp( gaussPyrs[i+1], tmp, ss); 
		Mat dst = gaussPyrs[i] - tmp;
		DOG.push_back(dst);
	}
	
	for(int i = 0;i < maxLevel;i++){
		stringstream ss;
		ss << i;
		string s;
		ss >> s;
		namedWindow( s, CV_WINDOW_AUTOSIZE );
  		imshow( s, DOG[i] );
	}
	
	waitKey(0);
  	return 0;
}


舉一反三
拉普拉斯金字塔也用於圖像融合,CVAA的第三章有練習題就是用拉普拉斯金字塔進行融合,addWeighted這個函數在邊界上沒有過渡,效果不好,而拉普拉斯金字塔則有很好的效果
具體請見http://blog.csdn.net/abcjennifer/article/details/7628655


計算機視覺討論羣:162501053
轉載請註明:http://blog.csdn.net/abcd1992719g


發佈了63 篇原創文章 · 獲贊 15 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章