這篇已經寫得很好,真心給做者點個贊。題目都是直接轉過來的,直接去看吧。python
Reference Link : http://blog.csdn.net/poem_qianmo/article/details/26157633app
In case:函數
這篇文章裏,咱們將一塊兒探討圖像金字塔的一些基本概念,如何使用OpenCV函數 pyrUp 和 pyrDown 對圖像進行向上和向下採樣,以及瞭解了專門用於縮放圖像尺寸的resize函數的用法。此博文一共有四個配套的簡短的示例程序,其詳細註釋過的代碼都在文中貼出,且文章最後提供了綜合示例程序的下載。測試
先嚐鮮一下其中一個示例程序的運行截圖:字體
![]()
咱們常常會將某種尺寸的圖像轉換爲其餘尺寸的圖像,若是放大或者縮小圖片的尺寸,籠統來講的話,可使用OpenCV爲咱們提供的以下兩種方式:優化
<1>resize函數。這是最直接的方式,ui
<2>pyrUp( )、pyrDown( )函數。即圖像金字塔相關的兩個函數,對圖像進行向上採樣,向下採樣的操做。spa
pyrUp、pyrDown其實和專門用做放大縮小圖像尺寸的resize在功能上差很少,披着圖像金字塔的皮,說白了仍是在對圖像進行放大和縮小操做。另外須要指出的是,pyrUp、pyrDown在OpenCV的imgproc模塊中的Image Filtering子模塊裏。而resize在imgproc 模塊的Geometric Image Transformations子模塊裏。.net
這篇文章中,咱們將先介紹圖像金字塔的原理,接着介紹resize函數,而後是pyrUp和pyrDown函數,最後是一個綜合示例程序。rest
2、關於圖像金字塔
圖像金字塔是圖像中多尺度表達的一種,最主要用於圖像的分割,是一種以多分辨率來解釋圖像的有效但概念簡單的結構。
圖像金字塔最初用於機器視覺和圖像壓縮,一幅圖像的金字塔是一系列以金字塔形狀排列的分辨率逐步下降,且來源於同一張原始圖的圖像集合。其經過梯次向下採樣得到,直到達到某個終止條件才中止採樣。
金字塔的底部是待處理圖像的高分辨率表示,而頂部是低分辨率的近似。
咱們將一層一層的圖像比喻成金字塔,層級越高,則圖像越小,分辨率越低。
![]()
![]()
![]()
素材圖是帥氣的美劇《綠箭俠》裏面的綠箭俠Oliver Queen。
通常狀況下有兩種類型的圖像金字塔經常出如今文獻和以及實際運用中。他們分別是:
- 高斯金字塔Gaussianpyramid): 用來向下採樣,主要的圖像金字塔
- 拉普拉斯金字塔(Laplacianpyramid): 用來從金字塔低層圖像重建上層未採樣圖像,在數字圖像處理中也便是預測殘差,能夠對圖像進行最大程度的還原,配合高斯金字塔一塊兒使用。
二者的簡要區別:高斯金字塔用來向降低採樣圖像,而拉普拉斯金字塔則用來從金字塔底層圖像中向上採樣重建一個圖像。
要從金字塔第i層生成第i+1層(咱們表示第i+1層爲G_i+1),咱們先要用高斯覈對G_1進行卷積,而後刪除全部偶數行和偶數列。固然的是,新獲得圖像面積會變爲源圖像的四分之一。按上述過程對輸入圖像G_0執行操做就可產生出整個金字塔。
當圖像向金字塔的上層移動時,尺寸和分辨率就下降。OpenCV中,從金字塔中上一級圖像生成下一級圖像的能夠用PryDown。而經過PryUp將現有的圖像在每一個維度都放大兩遍。
圖像金字塔中的向上和向下採樣分別經過OpenCV函數 pyrUp 和 pyrDown 實現。
歸納起來就是:
- 對圖像向上採樣:pyrUp函數
- 對圖像向下採樣:pyrDown函數
這裏的向下與向上採樣,是對圖像的尺寸而言的(和金字塔的方向相反),向上就是圖像尺寸加倍,向下就是圖像尺寸減半。而若是咱們按上圖中演示的金字塔方向來理解,金字塔向上圖像其實在縮小,這樣恰好是反過來了。
但須要注意的是,PryUp和PryDown不是互逆的,即PryUp不是降採樣的逆操做。這種狀況下,圖像首先在每一個維度上擴大爲原來的兩倍,新增的行(偶數行)以0填充。而後給指定的濾波器進行卷積(其實是一個在每一個維度都擴大爲原來兩倍的過濾器)去估計「丟失」像素的近似值。
PryDown( )是一個會丟失信息的函數。爲了恢復原來更高的分辨率的圖像,咱們要得到由降採樣操做丟失的信息,這些數據就和拉普拉斯金字塔有關係了。
高斯金字塔
高斯金字塔是經過高斯平滑和亞採樣得到一些列下采樣圖像,也就是說第K層高斯金字塔經過平滑、亞採樣就能夠得到K+1層高斯圖像,高斯金字塔包含了一系列低通濾波器,其截至頻率從上一層到下一層是以因子2逐漸增長,因此高斯金字塔能夠跨越很大的頻率範圍。金字塔的圖像以下:
這裏增長一個註解: 在數字圖像處理教材當中是從塔尖到塔底定義爲0,1,2...J 層,而opencv是相反的。
![]()
另外,每一層都按從下到上的次序編號, 層級 G_i+1 (表示爲 G_i+1尺寸小於第i層G_i)。
2.1.1 對圖像的向下取樣
爲了獲取層級爲 G_i+1 的金字塔圖像,咱們採用以下方法:
<1>對圖像G_i進行高斯內核卷積
<2>將全部偶數行和列去除
獲得的圖像即爲G_i+1的圖像,顯而易見,結果圖像只有原圖的四分之一。經過對輸入圖像G_i(原始圖像)不停迭代以上步驟就會獲得整個金字塔。同時咱們也能夠看到,向下取樣會逐漸丟失圖像的信息。
以上就是對圖像的向下取樣操做,即縮小圖像。
2.1.2 對圖像的向上取樣
若是想放大圖像,則須要經過向上取樣操做獲得,具體作法以下:
<1>將圖像在每一個方向擴大爲原來的兩倍,新增的行和列以0填充
<2>使用先前一樣的內核(乘以4)與放大後的圖像卷積,得到 「新增像素」的近似值 此處乘以4是由於在Mask(5*5)中只有6個位置是有值的,*4是一種近似,接近25個值。
獲得的圖像即爲放大後的圖像,可是與原來的圖像相比會發覺比較模糊,由於在縮放的過程當中已經丟失了一些信息,若是想在縮小和放大整個過程當中減小信息的丟失,這些數據造成了拉普拉斯金字塔。
那麼,咱們接下來一塊兒看一看拉普拉斯金字塔的概念吧。
拉普拉斯金字塔
下式是拉普拉斯金字塔第i層的數學定義:
式中的
表示第i層的圖像。而UP()操做是將源圖像中位置爲(x,y)的像素映射到目標圖像的(2x+1,2y+1)位置,即在進行向上取樣。符號
表示卷積,
爲5x5的高斯內核。
咱們下文將要介紹的pryUp,就是在進行上面這個式子的運算。
所以,咱們能夠直接用OpenCV進行拉普拉斯運算:
也就是說,拉普拉斯金字塔是經過源圖像減去先縮小後再放大的圖像的一系列圖像構成的。
整個拉普拉斯金字塔運算過程能夠經過下圖來歸納:
![]()
因此,咱們能夠將拉普拉斯金字塔理解爲高斯金字塔的逆形式。
另外再提一點,關於圖像金字塔很是重要的一個應用就是實現圖像分割。圖像分割的話,先要創建一個圖像金字塔,而後在G_i和G_i+1的像素直接依照對應的關係,創建起」父與子「關係。而快速初始分割能夠先在金字塔高層的低分辨率圖像上完成,而後逐層對分割加以優化。
3、resize( )函數剖析
resize( )爲OpenCV中專職調整圖像大小的函數。
此函數將源圖像精確地轉換爲指定尺寸的目標圖像。若是源圖像中設置了ROI(Region Of Interest ,感興趣區域),那麼resize( )函數會對源圖像的ROI區域進行調整圖像尺寸的操做,來輸出到目標圖像中。若目標圖像中已經設置ROI區域,不難理解resize( )將會對源圖像進行尺寸調整並填充到目標圖像的ROI中。
不少時候,咱們並不用考慮第二個參數dst的初始圖像尺寸和類型(即直接定義一個Mat類型,不用對其初始化),由於其尺寸和類型能夠由src,dsize,fx和fy這其餘的幾個參數來肯定。
看一下它的函數原型:
- resize(InputArray src,OutputArray dst, Size dsize, double fx=0, double fy=0, interpolation=INTER_LINEAR )
C++: void resize(InputArray src,OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR )
- 第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象便可。
- 第二個參數,OutputArray類型的dst,輸出圖像,當其非零時,有着dsize(第三個參數)的尺寸,或者由src.size()計算出來。
- 第三個參數,Size類型的dsize,輸出圖像的大小;若是它等於零,由下式進行計算:
其中,dsize,fx,fy都不能爲0。
- 第四個參數,double類型的fx,沿水平軸的縮放係數,有默認值0,且當其等於0時,由下式進行計算:
- 第五個參數,double類型的fy,沿垂直軸的縮放係數,有默認值0,且當其等於0時,由下式進行計算:
![]()
- 第六個參數,int類型的interpolation,用於指定插值方式,默認爲INTER_LINEAR(線性插值)。
可選的插值方式以下:
- INTER_NEAREST - 最近鄰插值
- INTER_LINEAR - 線性插值(默認值)
- INTER_AREA - 區域插值(利用像素區域關係的重採樣插值)
- INTER_CUBIC –三次樣條插值(超過4×4像素鄰域內的雙三次插值)
- INTER_LANCZOS4 -Lanczos插值(超過8×8像素鄰域的Lanczos插值)
若要縮小圖像,通常狀況下最好用CV_INTER_AREA來插值,
而若要放大圖像,通常狀況下最好用CV_INTER_CUBIC(效率不高,慢,不推薦使用)或CV_INTER_LINEAR(效率較高,速度較快,推薦使用)。
關於插值,咱們看幾張圖就能更好地理解。先看原圖:
![]()
當進行6次圖像縮小接着6次圖像放大操做後,兩種不一樣的插值方式獲得的效果圖:
效果很明顯,第一張全是一個個的像素,很是影響美觀。另一張卻有霧化的朦朧美感,因此插值方式的選擇,對通過屢次放大縮小的圖片最終獲得的效果是有很大影響的。
接着咱們來看兩種resize的調用範例。
方式一,調用範例: Mat dst=Mat::zeros(512 ,512, CV_8UC3 );//新建一張512x512尺寸的圖片 Mat src=imread(「1.jpg」); //顯式指定dsize=dst.size(),那麼fx和fy會其計算出來,不用額外指定。 resize(src, dst, dst.size()); Mat dst=Mat::zeros(512 ,512, CV_8UC3 );//新建一張512x512尺寸的圖片 Mat src=imread(「1.jpg」); //顯式指定dsize=dst.size(),那麼fx和fy會其計算出來,不用額外指定。 resize(src, dst, dst.size()); 方式2、調用範例: Mat dst; Mat src=imread(「1.jpg」) //指定fx和fy,讓函數計算出目標圖像的大小。 resize(src, dst, Size(), 0.5, 0.5); Mat dst; Mat src=imread(「1.jpg」) //指定fx和fy,讓函數計算出目標圖像的大小。 resize(src, dst, Size(), 0.5, 0.5); 接着咱們看看完整的示例程序: //-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- usingnamespace //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,咱們的程序從這裏開始 //----------------------------------------------------------------------------------------------- main( ) //載入原始圖 Mat srcImage = imread("1.jpg"//工程目錄下應該有一張名爲1.jpg的素材圖 Mat tmpImage,dstImage1,dstImage2;//臨時變量和目標圖的定義 tmpImage=srcImage;//將原始圖賦給臨時變量 //顯示原始圖 imshow("【原始圖】", srcImage); //進行尺寸調整操做 resize(tmpImage,dstImage1,Size( tmpImage.cols/2, tmpImage.rows/2 ),(0,0),(0,0),3); resize(tmpImage,dstImage2,Size( tmpImage.cols*2, tmpImage.rows*2 ),(0,0),(0,0),3); //顯示效果圖 imshow("【效果圖】之一", dstImage1); imshow("【效果圖】之二", dstImage2); waitKey(0); return //-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv; //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,咱們的程序從這裏開始 //----------------------------------------------------------------------------------------------- int main( ) { //載入原始圖 Mat srcImage = imread("1.jpg"); //工程目錄下應該有一張名爲1.jpg的素材圖 Mat tmpImage,dstImage1,dstImage2;//臨時變量和目標圖的定義 tmpImage=srcImage;//將原始圖賦給臨時變量 //顯示原始圖 imshow("【原始圖】", srcImage); //進行尺寸調整操做 resize(tmpImage,dstImage1,Size( tmpImage.cols/2, tmpImage.rows/2 ),(0,0),(0,0),3); resize(tmpImage,dstImage2,Size( tmpImage.cols*2, tmpImage.rows*2 ),(0,0),(0,0),3); //顯示效果圖 imshow("【效果圖】之一", dstImage1); imshow("【效果圖】之二", dstImage2); waitKey(0); return 0; }
程序運行截圖:
![]()
4、pyrUp()函數剖析
pyrUp( )函數的做用是向上採樣並模糊一張圖像,說白了就是放大一張圖片。
- pyrUp(InputArray src, OutputArraydst, const Size& dstsize=Size(), borderType=BORDER_DEFAULT )
C++: void pyrUp(InputArray src, OutputArraydst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT )
- 第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象便可。
- 第二個參數,OutputArray類型的dst,輸出圖像,和源圖片有同樣的尺寸和類型。
- 第三個參數,const Size&類型的dstsize,輸出圖像的大小;有默認值Size(),即默認狀況下,由Size(src.cols*2,src.rows*2)來進行計算,且一直須要知足下列條件:
![]()
- 第四個參數,int類型的borderType,又來了,邊界模式,通常咱們不用去管它。
pyrUp函數執行高斯金字塔的採樣操做,其實它也能夠用於拉普拉斯金字塔的。
首先,它經過插入可爲零的行與列,對源圖像進行向上取樣操做,而後將結果與pyrDown()乘以4的內核作卷積,就是這樣。
直接看完整的示例程序:
//-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- usingnamespace //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,咱們的程序從這裏開始 //----------------------------------------------------------------------------------------------- main( ) //載入原始圖 Mat srcImage = imread("1.jpg"//工程目錄下應該有一張名爲1.jpg的素材圖 Mat tmpImage,dstImage;//臨時變量和目標圖的定義 tmpImage=srcImage;//將原始圖賦給臨時變量 //顯示原始圖 imshow("【原始圖】", srcImage); //進行向上取樣操做 pyrUp( tmpImage, dstImage, Size( tmpImage.cols*2, tmpImage.rows*2 ) ); //顯示效果圖 imshow("【效果圖】", dstImage); waitKey(0); return //-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv; //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,咱們的程序從這裏開始 //----------------------------------------------------------------------------------------------- int main( ) { //載入原始圖 Mat srcImage = imread("1.jpg"); //工程目錄下應該有一張名爲1.jpg的素材圖 Mat tmpImage,dstImage;//臨時變量和目標圖的定義 tmpImage=srcImage;//將原始圖賦給臨時變量 //顯示原始圖 imshow("【原始圖】", srcImage); //進行向上取樣操做 pyrUp( tmpImage, dstImage, Size( tmpImage.cols*2, tmpImage.rows*2 ) ); //顯示效果圖 imshow("【效果圖】", dstImage); waitKey(0); return 0; }
程序運行截圖:
![]()
![]()
5、pyrDown()函數剖析
pyrDown( )函數的做用是向下採樣並模糊一張圖片,說白了就是縮小一張圖片。
- pyrDown(InputArray src,OutputArray dst, const Size& dstsize=Size(), borderType=BORDER_DEFAULT)
C++: void pyrDown(InputArray src,OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT)
- 第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象便可。
- 第二個參數,OutputArray類型的dst,輸出圖像,和源圖片有同樣的尺寸和類型。
- 第三個參數,const Size&類型的dstsize,輸出圖像的大小;有默認值Size(),即默認狀況下,由Size Size((src.cols+1)/2, (src.rows+1)/2)來進行計算,且一直須要知足下列條件:
![]()
該pyrDown函數執行了高斯金字塔建造的向下採樣的步驟。首先,它將源圖像與以下內核作卷積運算:
![]()
接着,它便經過對圖像的偶數行和列作插值來進行向下採樣操做。
依然是看看完整的示例程序:
//-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- usingnamespace //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,咱們的程序從這裏開始 //----------------------------------------------------------------------------------------------- main( ) //載入原始圖 Mat srcImage = imread("1.jpg"//工程目錄下應該有一張名爲1.jpg的素材圖 Mat tmpImage,dstImage;//臨時變量和目標圖的定義 tmpImage=srcImage;//將原始圖賦給臨時變量 //顯示原始圖 imshow("【原始圖】", srcImage); //進行向下取樣操做 pyrDown( tmpImage, dstImage, Size( tmpImage.cols/2, tmpImage.rows/2 ) ); //顯示效果圖 imshow("【效果圖】", dstImage); waitKey(0); return //-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv; //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,咱們的程序從這裏開始 //----------------------------------------------------------------------------------------------- int main( ) { //載入原始圖 Mat srcImage = imread("1.jpg"); //工程目錄下應該有一張名爲1.jpg的素材圖 Mat tmpImage,dstImage;//臨時變量和目標圖的定義 tmpImage=srcImage;//將原始圖賦給臨時變量 //顯示原始圖 imshow("【原始圖】", srcImage); //進行向下取樣操做 pyrDown( tmpImage, dstImage, Size( tmpImage.cols/2, tmpImage.rows/2 ) ); //顯示效果圖 imshow("【效果圖】", dstImage); waitKey(0); return 0; }
程序運行截圖:
![]()
![]()
6、綜合示例篇——在實戰中熟稔
依然是每篇文章都會配給你們的一個詳細註釋的博文配套示例程序,把這篇文章中介紹的知識點以代碼爲載體,展示給你們。
這個示例程序中,分別演示了用resize,pryUp,pryDown來讓源圖像進行放大縮小的操做,分別用鍵盤按鍵一、二、三、四、A、D、W、S來控制圖片的放大與縮小:
![]()
OK,上詳細註釋的代碼吧:
//-----------------------------------【程序說明】---------------------------------------------- // 程序名稱::《 【OpenCV入門教程之十三】OpenCV圖像金字塔:高斯金字塔、拉普拉斯金字塔與圖片尺寸縮放》 博文配套源碼 // 開發所用IDE版本:Visual Studio 2010 // 開發所用OpenCV版本: 2.4.9 // 2014年5月18日 Create by 淺墨 //---------------------------------------------------------------------------------------------- //-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> //-----------------------------------【宏定義部分】-------------------------------------------- // 描述:定義一些輔助宏 //------------------------------------------------------------------------------------------------ #define WINDOW_NAME "【程序窗口】" //爲窗口標題定義的宏 //-----------------------------------【命名空間聲明部分】-------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- usingnamespace usingnamespace //-----------------------------------【全局變量聲明部分】-------------------------------------- // 描述:全局變量聲明 //----------------------------------------------------------------------------------------------- Mat g_srcImage, g_dstImage, g_tmpImage; //-----------------------------------【全局函數聲明部分】-------------------------------------- // 描述:全局函數聲明 //----------------------------------------------------------------------------------------------- static ShowHelpText(); //-----------------------------------【ShowHelpText( )函數】---------------------------------- // 描述:輸出一些幫助信息 //---------------------------------------------------------------------------------------------- static ShowHelpText() //輸出一些幫助信息 printf("\n\n\n\t歡迎來到OpenCV圖像金字塔和resize示例程序~\n\n" printf( "\n\n\t按鍵操做說明: \n\n" "\t\t鍵盤按鍵【ESC】或者【Q】- 退出程序\n" "\t\t鍵盤按鍵【1】或者【W】- 進行基於【resize】函數的圖片放大\n" "\t\t鍵盤按鍵【2】或者【S】- 進行基於【resize】函數的圖片縮小\n" "\t\t鍵盤按鍵【3】或者【A】- 進行基於【pyrUp】函數的圖片放大\n" "\t\t鍵盤按鍵【4】或者【D】- 進行基於【pyrDown】函數的圖片縮小\n" "\n\n\t\t\t\t\t\t\t\t by淺墨\n\n\n" //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,咱們的程序從這裏開始 //----------------------------------------------------------------------------------------------- main( ) //改變console字體顏色 system("color 2F" //顯示幫助文字 ShowHelpText(); //載入原圖 g_srcImage = imread("1.jpg"//工程目錄下須要有一張名爲1.jpg的測試圖像,且其尺寸需被2的N次方整除,N爲能夠縮放的次數 ( !g_srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~! \n"returnfalse // 建立顯示窗口 namedWindow( WINDOW_NAME, CV_WINDOW_AUTOSIZE ); imshow(WINDOW_NAME, g_srcImage); //參數賦值 g_tmpImage = g_srcImage; g_dstImage = g_tmpImage; key =0; //輪詢獲取按鍵信息 while key=waitKey(9) ;//讀取鍵值到key變量中 //根據key變量的值,進行不一樣的操做 switch(key) //======================【程序退出相關鍵值處理】======================= //按鍵ESC return break //按鍵Q return break //======================【圖片放大相關鍵值處理】======================= //按鍵A按下,調用pyrUp函數 pyrUp( g_tmpImage, g_dstImage, Size( g_tmpImage.cols*2, g_tmpImage.rows*2 ) ); printf( ">檢測到按鍵【A】被按下,開始進行基於【pyrUp】函數的圖片放大:圖片尺寸×2 \n" break //按鍵W按下,調用resize函數 resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols*2, g_tmpImage.rows*2 )); printf( ">檢測到按鍵【W】被按下,開始進行基於【resize】函數的圖片放大:圖片尺寸×2 \n" break //按鍵1按下,調用resize函數 resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols*2, g_tmpImage.rows*2 )); printf( ">檢測到按鍵【1】被按下,開始進行基於【resize】函數的圖片放大:圖片尺寸×2 \n" break //按鍵3按下,調用pyrUp函數 pyrUp( g_tmpImage, g_dstImage, Size( g_tmpImage.cols*2, g_tmpImage.rows*2 )); printf( ">檢測到按鍵【3】被按下,開始進行基於【pyrUp】函數的圖片放大:圖片尺寸×2 \n" break //======================【圖片縮小相關鍵值處理】======================= //按鍵D按下,調用pyrDown函數 pyrDown( g_tmpImage, g_dstImage, Size( g_tmpImage.cols/2, g_tmpImage.rows/2 )); printf( ">檢測到按鍵【D】被按下,開始進行基於【pyrDown】函數的圖片縮小:圖片尺寸/2\n" break //按鍵S按下,調用resize函數 resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols/2, g_tmpImage.rows/2 )); printf( ">檢測到按鍵【S】被按下,開始進行基於【resize】函數的圖片縮小:圖片尺寸/2\n" break //按鍵2按下,調用resize函數 resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols/2, g_tmpImage.rows/2 ),(0,0),(0,0),2); printf( ">檢測到按鍵【2】被按下,開始進行基於【resize】函數的圖片縮小:圖片尺寸/2\n" break //按鍵4按下,調用pyrDown函數 pyrDown( g_tmpImage, g_dstImage, Size( g_tmpImage.cols/2, g_tmpImage.rows/2 ) ); printf( ">檢測到按鍵【4】被按下,開始進行基於【pyrDown】函數的圖片縮小:圖片尺寸/2\n" break //通過操做後,顯示變化後的圖 imshow( WINDOW_NAME, g_dstImage ); //將g_dstImage賦給g_tmpImage,方便下一次循環 g_tmpImage = g_dstImage; return //-----------------------------------【程序說明】---------------------------------------------- // 程序名稱::《 【OpenCV入門教程之十三】OpenCV圖像金字塔:高斯金字塔、拉普拉斯金字塔與圖片尺寸縮放》 博文配套源碼 // 開發所用IDE版本:Visual Studio 2010 // 開發所用OpenCV版本: 2.4.9 // 2014年5月18日 Create by 淺墨 //---------------------------------------------------------------------------------------------- //-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> //-----------------------------------【宏定義部分】-------------------------------------------- // 描述:定義一些輔助宏 //------------------------------------------------------------------------------------------------ #define WINDOW_NAME "【程序窗口】" //爲窗口標題定義的宏 //-----------------------------------【命名空間聲明部分】-------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace std; using namespace cv; //-----------------------------------【全局變量聲明部分】-------------------------------------- // 描述:全局變量聲明 //----------------------------------------------------------------------------------------------- Mat g_srcImage, g_dstImage, g_tmpImage; //-----------------------------------【全局函數聲明部分】-------------------------------------- // 描述:全局函數聲明 //----------------------------------------------------------------------------------------------- static void ShowHelpText(); //-----------------------------------【ShowHelpText( )函數】---------------------------------- // 描述:輸出一些幫助信息 //---------------------------------------------------------------------------------------------- static void ShowHelpText() { //輸出一些幫助信息 printf("\n\n\n\t歡迎來到OpenCV圖像金字塔和resize示例程序~\n\n"); printf( "\n\n\t按鍵操做說明: \n\n" "\t\t鍵盤按鍵【ESC】或者【Q】- 退出程序\n" "\t\t鍵盤按鍵【1】或者【W】- 進行基於【resize】函數的圖片放大\n" "\t\t鍵盤按鍵【2】或者【S】- 進行基於【resize】函數的圖片縮小\n" "\t\t鍵盤按鍵【3】或者【A】- 進行基於【pyrUp】函數的圖片放大\n" "\t\t鍵盤按鍵【4】或者【D】- 進行基於【pyrDown】函數的圖片縮小\n" "\n\n\t\t\t\t\t\t\t\t by淺墨\n\n\n" ); } //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,咱們的程序從這裏開始 //----------------------------------------------------------------------------------------------- int main( ) { //改變console字體顏色 system("color 2F"); //顯示幫助文字 ShowHelpText(); //載入原圖 g_srcImage = imread("1.jpg");//工程目錄下須要有一張名爲1.jpg的測試圖像,且其尺寸需被2的N次方整除,N爲能夠縮放的次數 if( !g_srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~! \n"); return false; } // 建立顯示窗口 namedWindow( WINDOW_NAME, CV_WINDOW_AUTOSIZE ); imshow(WINDOW_NAME, g_srcImage); //參數賦值 g_tmpImage = g_srcImage; g_dstImage = g_tmpImage; int key =0; //輪詢獲取按鍵信息 while(1) { key=waitKey(9) ;//讀取鍵值到key變量中 //根據key變量的值,進行不一樣的操做 switch(key) { //======================【程序退出相關鍵值處理】======================= case 27://按鍵ESC return 0; break; case 'q'://按鍵Q return 0; break; //======================【圖片放大相關鍵值處理】======================= case 'a'://按鍵A按下,調用pyrUp函數 pyrUp( g_tmpImage, g_dstImage, Size( g_tmpImage.cols*2, g_tmpImage.rows*2 ) ); printf( ">檢測到按鍵【A】被按下,開始進行基於【pyrUp】函數的圖片放大:圖片尺寸×2 \n" ); break; case 'w'://按鍵W按下,調用resize函數 resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols*2, g_tmpImage.rows*2 )); printf( ">檢測到按鍵【W】被按下,開始進行基於【resize】函數的圖片放大:圖片尺寸×2 \n" ); break; case '1'://按鍵1按下,調用resize函數 resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols*2, g_tmpImage.rows*2 )); printf( ">檢測到按鍵【1】被按下,開始進行基於【resize】函數的圖片放大:圖片尺寸×2 \n" ); break; case '3': //按鍵3按下,調用pyrUp函數 pyrUp( g_tmpImage, g_dstImage, Size( g_tmpImage.cols*2, g_tmpImage.rows*2 )); printf( ">檢測到按鍵【3】被按下,開始進行基於【pyrUp】函數的圖片放大:圖片尺寸×2 \n" ); break; //======================【圖片縮小相關鍵值處理】======================= case 'd': //按鍵D按下,調用pyrDown函數 pyrDown( g_tmpImage, g_dstImage, Size( g_tmpImage.cols/2, g_tmpImage.rows/2 )); printf( ">檢測到按鍵【D】被按下,開始進行基於【pyrDown】函數的圖片縮小:圖片尺寸/2\n" ); break; case 's' : //按鍵S按下,調用resize函數 resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols/2, g_tmpImage.rows/2 )); printf( ">檢測到按鍵【S】被按下,開始進行基於【resize】函數的圖片縮小:圖片尺寸/2\n" ); break; case '2'://按鍵2按下,調用resize函數 resize(g_tmpImage,g_dstImage,Size( g_tmpImage.cols/2, g_tmpImage.rows/2 ),(0,0),(0,0),2); printf( ">檢測到按鍵【2】被按下,開始進行基於【resize】函數的圖片縮小:圖片尺寸/2\n" ); break; case '4': //按鍵4按下,調用pyrDown函數 pyrDown( g_tmpImage, g_dstImage, Size( g_tmpImage.cols/2, g_tmpImage.rows/2 ) ); printf( ">檢測到按鍵【4】被按下,開始進行基於【pyrDown】函數的圖片縮小:圖片尺寸/2\n" ); break; } //通過操做後,顯示變化後的圖 imshow( WINDOW_NAME, g_dstImage ); //將g_dstImage賦給g_tmpImage,方便下一次循環 g_tmpImage = g_dstImage; } return 0; }
放一些程序運行截圖。
![]()
通過屢次按鍵後的效果圖:
![]()
![]()
![]()
![]()
另外,還能夠放大圖像到很大的尺寸,上圖的話會很兇殘並且不美觀。因此就不放出超過原圖尺寸的截圖了。
好的,就放出這些效果圖,具體更多的運行效果你們就本身下載示例程序回去玩~
本篇文章的配套源代碼請點擊這裏下載:
![]()
# -*- coding: utf-8 -*- import cv2 import numpy as np A = cv2.imread('../burn image/case3-burn-to-head-showing-healing-0.jpg',0) # generate Gaussian pyramid for A G = A.copy() gpA = [G] lpA = [] for i in xrange(3): cv2.imshow('1',G) image_o = G G = cv2.pyrDown(G) GE = cv2.pyrUp(G) L = np.subtract(image_o,GE) gpA.append(G) lpA.append(L) cv2.imshow('lpA',L ) cv2.imshow('上採樣+拉普拉斯',L+GE ) cv2.imshow('upsample',GE ) MSE(image_o,L+GE) cv2.waitKey(0)
注:拉普拉斯金子塔是每層的原圖減去該圖的下采樣後的上採樣圖(通常用高斯下采樣), 因此也叫預測殘差金字塔。 經過預測殘差金字塔能夠100%還原圖像,對麼?