一,圖像金字塔
解釋:
圖像金字塔是圖像中多尺度表達的一種,最主要用於圖像的分割,是一種以多分辨率來解釋圖像的有效但概念簡單的結構。
圖像金字塔最初用於機器視覺和圖像壓縮,一幅圖像的金字塔是一系列以金字塔形狀排列的分辨率逐步降低,且來源於同一張原始圖的圖像集合。其通過梯次向下採樣獲得,直到達到某個終止條件才停止採樣。
金字塔的底部是待處理圖像的高分辨率表示,而頂部是低分辨率的近似。
我們將一層一層的圖像比喻成金字塔,層級越高,則圖像越小,分辨率越低。
一般情況下有兩種類型的圖像金字塔常常出現在文獻和以及實際運用中。他們分別是:
-
高斯金字塔(Gaussianpyramid): 用來向下採樣,高斯金字塔的頂部是通過將底部圖像中的連續的行和列(一般爲偶數)去除得到的。頂部圖像中的每個像素值等於下一層圖像中 5 個像素的高斯加權平均值。這樣 操作一次一個 MxN 的圖像就變成了一個 M/2xN/2 的圖像。所以這幅圖像的面積就變爲原來圖像面積的四分之一。這被稱爲an Octave(一個八度)。連續進行這樣的操作就會得到一個分辨率不斷下降的圖像金字塔。
-
拉普拉斯金字塔(Laplacianpyramid): 用來從金字塔低層圖像重建上層未採樣圖像,在數字圖像處理中也即是預測殘差,可以對圖像進行最大程度的還原,配合高斯金字塔一起使用。
下式是拉普拉斯金字塔第i層的數學定義:
式中的表示第i層的圖像。而UP()操作是將源圖像中位置爲(x,y)的像素映射到目標圖像的(2x+1,2y+1)位置,即在進行向上取樣。符號表示卷積,爲5x5的高斯內核。
我們下文將要介紹的pryUp,就是在進行上面這個式子的運算。
因此,我們可以直接用OpenCV進行拉普拉斯運算:
也就是說,拉普拉斯金字塔是通過源圖像減去先縮小後再放大的圖像的一系列圖像構成的。
整個拉普拉斯金字塔運算過程可以通過下圖來概括:
所以,我們可以將拉普拉斯金字塔理解爲高斯金字塔的逆形式。
另外再提一點,關於圖像金字塔非常重要的一個應用就是實現圖像分割。圖像分割的話,先要建立一個圖像金字塔,然後在G_i和G_i+1的像素直接依照對應的關係,建立起”父與子“關係。而快速初始分割可以先在金字塔高層的低分辨率圖像上完成,然後逐層對分割加以優化。
高斯金字塔的作用(通俗):
整個高斯金字塔,或者說是差分高斯金字塔是我們確定SIFT特徵的基礎,讓我們首先想想高斯金字塔到底幹了一件什麼事情,他到底模仿的是什麼?答案很容易確定,高斯金字塔模仿的是圖像的不同的尺度,尺度應該怎樣理解?對於一副圖像,你近距離觀察圖像,與你在一米之外觀察,看到的圖像效果是不同的,前者比較清晰,後者比較模糊,前者比較大,後者比較小,通過前者能看到圖像的一些細節信息,通過後者能看到圖像的一些輪廓的信息,這就是圖像的尺度,圖像的尺度是自然存在的,並不是人爲創造的。好了,到這裏我們明白了,其實以前對一幅圖像的處理還是比較單調的,因爲我們的關注點只落在二維空間,並沒有考慮到“圖像的縱深”這樣一個概念,如果將這些內容考慮進去我們是不是會得到更多以前在二維空間中沒有得到的信息呢?於是高斯金字塔橫空出世了,它就是爲了在二維圖像的基礎之上,榨取出圖像中自然存在的另一個維度:尺度。因爲高斯核是唯一的線性核,也就是說使用高斯覈對圖像模糊不會引入其他噪聲,因此就選用了高斯核來構建圖像的尺度
對圖像的向下取樣
爲了獲取層級爲 G_i+1 的金字塔圖像,我們採用如下方法:
<1>對圖像G_i進行高斯內核卷積
<2>將所有偶數行和列去除
得到的圖像即爲G_i+1的圖像,顯而易見,結果圖像只有原圖的四分之一。通過對輸入圖像G_i(原始圖像)不停迭代以上步驟就會得到整個金字塔。同時我們也可以看到,向下取樣會逐漸丟失圖像的信息。
以上就是對圖像的向下取樣操作,即縮小圖像。
pyrUp(img, dst, Size(img.cols*2, img.rows*2)); //放大一倍
對圖像的向上取樣
如果想放大圖像,則需要通過向上取樣操作得到,具體做法如下:
<1>將圖像在每個方向擴大爲原來的兩倍,新增的行和列以0填充
<2>使用先前同樣的內核(乘以4)與放大後的圖像卷積,獲得 “新增像素”的近似值
得到的圖像即爲放大後的圖像,但是與原來的圖像相比會發覺比較模糊,因爲在縮放的過程中已經丟失了一些信息,如果想在縮小和放大整個過程中減少信息的丟失,這些數據形成了拉普拉斯金字塔。
pyrDown(img, dst2, Size(img.cols * 0.5, img.rows * 0.5)); //縮小爲原來的一半
二,圖像縮放
兩種標準使用方法:
Mat dst = Mat::zeros(512, 512, CV_8UC3); //我要轉化爲512*512大小的
resize(img, dst, dst.size());
Mat dst;
resize(img, dst, Size(),0.5,0.5);//我長寬都變爲原來的0.5倍
三,代碼展示
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src1, src2, dst;
src1 = imread("C:\\Users\\馬迎偉\\Desktop\\douyin.jpg");
if (src1.empty())
{
cout << "could not find src1" << endl;
}
namedWindow("input",CV_WINDOW_AUTOSIZE);
imshow("input",src1);
//上採樣(高斯模糊-->填0 高斯填充)
pyrUp(src1,src2,Size(2*src1.cols,2*src1.rows));
imshow("上採樣",src2);
//下采樣 (刪除偶數行列)
pyrDown(src1,dst,Size(src1.cols/2,src1.rows/2));
imshow("下采樣",dst);
//DOG
Mat DOGimg,g1,g2 ;
GaussianBlur(src1,g1,Size(3,3),0,0);
GaussianBlur(g1,g2,Size(3,3),0,0);
subtract(g1,g2,DOGimg,Mat());
//對DOGimg進行歸一化操作
normalize(DOGimg, DOGimg, 255, 0, NORM_MINMAX);
imshow("DOG image", DOGimg);
waitKey(0);
return 0;
}