在進行數字圖像處理時,我們可能會需要將某種尺寸的圖像轉換爲其他尺寸的圖像,這樣會存在放大圖像核縮小圖像兩種可能。opencv提供了一個真正意義上的圖像所方函數resize(),但在本篇中主要學習以下使用圖像金字塔進行圖像的所方,圖像金字塔是視覺運用較爲廣泛的一項技術。
一個圖像金字塔是一系列圖像的集合,所有圖像來源於同一張原始圖像,通過梯次向下採樣獲得,直到達到某個終止條件才停止採樣。通常有兩種類型的圖像金字塔
. 高斯金字塔(Gaussian pyramid): 用來向下採樣
. 拉普拉斯金字塔(Laplacian pyramid): 用來從金字塔底層圖像重建上層未採樣圖像,可以對圖像進行最大程度的還原.
之所以稱圖像金字塔是因爲激昂一層一層的圖像比喻成金字塔,層級越高,則圖像越小,分辨率越低,有如下兩種形式:
1.高斯金字塔
高斯金字塔是圖像處理、計算機視覺、信號處理上所使用的一項技術,高斯金字塔本質上爲信號的多尺度表示法,亦即將同一信號或圖片進行多次高斯模糊並且向下取樣以產生不同尺度下的多組信號或圖片進行後續的處理。如下圖所示:
. 每一層都按從下到上的次序編號,層級(i+1)尺寸G(i+1)小於層級i的圖像尺寸G(i)
. 高斯金字塔是用來向下採樣,爲了由第i層圖像向下採樣得到i+1層的圖像,我們採用如下方法
(1)對圖像進行高斯內核卷積,高斯內核爲:
(2)將所有偶數行和列去除。
得到的圖像即爲第i+1層的圖像,相較於第i層圖像,其尺寸是第i層圖像的1/2.通過對原圖像不斷的迭代就會得到整個金字塔,同時由第二步我們也可以看出向下採樣會逐漸丟失圖像的信息,達到縮小圖像的目的。opencv提供了pyrDown函數來實現圖像的向下採樣,其原型爲:
void cv::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)計算得到並且還要滿足以下條件
|dstsize.width*2-src.cols|<=2
|dstsize.height*2-src.rows|<=2
. int borderType=BORDER_DEFAULT: 用於推斷圖像外部像素的某種邊界模式,有默認值BORDER_DEFAULT
2.拉普拉斯金字塔
拉普拉斯金字塔是向上採樣,重建上層未採樣圖像,在圖像處理中預測殘差。得到的圖像比原來圖像的尺寸大。向上採樣如下:
(1)將圖像在每個方向上擴大爲原來的兩倍,新增的行和列以0填充
(2)使用先前同樣的內核(乘以4)與放大後的圖像卷積,或得”新增像素”的近似值
得到的圖像即爲放大後的圖像,但所與原來的圖像相比會比較模糊,因爲在向下採樣過程中丟失了一些信息。opencv中提供了pyrUp()實現圖像的向上採樣,函數原型如下:
void cv::pyrUp ( InputArray src,
OutputArray dst,
const Size & dstsize = Size(),
int borderType = BORDER_DEFAULT
)
參數解釋:
. InputArray src: 輸入圖像
. OutputArray dst: 輸出圖像
. const Size & dstsize=Size(): 輸出圖像尺寸,有默認值Size(),在使用默認值的情況下,輸出圖像的尺寸由Size((src.cols*2),(src.rows*2))計算得到,但是必須滿足以下條件
|dstsize.width - src.cols*2|<=(dstsize.width mod 2)
|dstsize.height - src.rows*2|<=(dstsize.height mod 2)
其中mod時求餘函數,即dstsize.width mod 2是dstsize.width除以2的餘數。
. int borderType=BORDER_DEFAULT: 用於推斷圖像外部像素的某種邊界模式,有默認值BORDER_DEFAULT,具體可以查看函數BorderTypes獲取詳細信息(需要注意的是與膨脹腐蝕不同,這裏不支持BORDER_CONSTANT模式)
該函數與高斯金字塔有相同的步長,可以用來構建拉普拉斯金字塔。其核如下:
示例程序如下:
/*
*程序首先對加載的圖像執行向下採樣操作形成高斯金字塔
*之後再利用向下採樣得到的圖像進行向上採樣形成拉普拉斯金字塔
*/
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage = imread("pyramid.jpg");
//判斷圖像是否加載成功
if(srcImage.empty())
{
cout << "圖像加載失敗!" << endl;
return -1;
}
else
cout << "圖像加載成功!" << endl << endl;
namedWindow("原圖像", WINDOW_AUTOSIZE);
imshow("原圖像", srcImage);
//兩次向下採樣操作分別輸出
Mat pyrDownImage_1, pyrDownImage_2;
pyrDown(srcImage, pyrDownImage_1);
namedWindow("向下採樣-1", WINDOW_AUTOSIZE);
imshow("向下採樣-1", pyrDownImage_1);
pyrDown(pyrDownImage_1, pyrDownImage_2);
namedWindow("向下採樣-2", WINDOW_AUTOSIZE);
imshow("向下採樣-2", pyrDownImage_2);
//利用向下採樣的結果進行向上採樣操作
Mat pyrUpImage_1, pyrUpImage_2;
pyrUp(pyrDownImage_2, pyrUpImage_1);
namedWindow("向上採樣-1", WINDOW_AUTOSIZE);
imshow("向上採樣-1", pyrUpImage_1);
pyrUp(pyrUpImage_1, pyrUpImage_2);
namedWindow("向上採樣-2", WINDOW_AUTOSIZE);
imshow("向上採樣-2", pyrUpImage_2);
waitKey(0);
return 0;
}
程序運行結果