雙線性插值原理
連結:https://zhuanlan.zhihu.com/p/110754637
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
目錄
1.什麼是插值
2.常用的插值演算法
3.最近鄰法(Nearest Interpolation)
4.單線性插值
5.雙線性插值
6.雙線性插值的優化
7.程式碼
1.什麼是插值
Interpolation is a method of constructing new data points within the range of a discrete set of known data points. Image interpolation refers to the“guess”of intensity values at missing locations.
圖片放大是影象處理中的一個特別基礎的操作。在幾乎每一個圖片相關的專案中,從傳統影象處理到深度學習,都有應用。生活裡,和朋友通過微信傳張圖片,從圖片發出,到朋友收到圖片,檢視圖片,都會數次的的改變影象的尺寸,從而用到這個演算法。但是大家只是在用這個演算法,很少關注這個演算法的實現細節:插值演算法是如何工作的。
簡單來說,插值指利用已知的點來“猜”未知的點,影象領域插值常用在修改影象尺寸的過程,由舊的影象矩陣中的點計算新影象矩陣中的點並插入,不同的計算過程就是不同的插值演算法。
下圖是自己實現雙線性插值的效果
2.常用的插值演算法
插值演算法有很多種,這裡列出關聯比較密切的三種:
最近鄰法(Nearest Interpolation):計算速度最快,但是效果最差。
雙線性插值(Bilinear Interpolation):雙線性插值是用原影象中4(2*2)個點計算新影象中1個點,效果略遜於雙三次插值,速度比雙三次插值快,屬於一種平衡美,在很多框架中屬於預設演算法。
雙三次插值(Bicubic interpolation):雙三次插值是用原影象中16(4*4)個點計算新影象中1個點,效果比較好,但是計算代價過大。
3.最近鄰法(Nearest Interpolation)
雙線性插值法由原圖中4個點計算新圖中的1個點,在介紹計算過程前,需要先了解如何找到這4個點,雙線性插值法找尋4個點的方式和最近鄰法相似,這裡順帶的瞭解下最近鄰法的計算流程。
最近鄰法實際上是不需要計算新影象矩陣中點的數值的,直接找到原影象中對應的點,將數值賦值給新影象矩陣中的點,根據對應關係找到原影象中的對應的座標,這個座標可能不是整數,這時候找最近的點進行插值。對應關係如下:
變數含義如下:
3.1總結
上圖效果是最近鄰法的計算過程示意圖,由上圖可見,最近鄰法不需要計算只需要尋找原圖中對應的點,所以最近鄰法速度最快,但是會破壞原影象中畫素的漸變關係,原影象中的畫素點的值是漸變的,但是在新影象中區域性破壞了這種漸變關係。
3.2雙線性插值對應關係
雙線性插值的對應公式和前面的最近鄰法一樣,不一樣的是根據對應關係不再是找最近的1個點,而是找最近的4個點,如下圖所示。
這裡可能還會有點小疑問,如果根據對應關係找到原圖中的點不是在不同的點之間,而是跟原影象中的點重合,那該如何找4個點?關於這個問題要看一下雙線性插值的計算公式,雙線性插值實際上是從2個方向一共進行了3次單線性插值,咱們先了解單線性插值的計算方式。
4.單線性插值
已知中P1點和P2點,座標分別為(x1, y1)、(x2, y2),要計算 [x1, x2] 區間內某一位置 x 在直線上的y值
根據初中的知識,2點求一條直線公式(這是雙線性插值所需要的唯一的基礎公式)
經過簡單整理成下面的格式:
這裡沒有寫成經典的AX+B的形式,因為這種形式從權重的角度更好理解。
首先看分子,分子可以看成x與x1和x2的距離作為權重,這也是很好理解的,P點與P1、P2點符合線性變化關係,所以P離P1近就更接近P1,反之則更接近P2。
現在再把公式中的分式看成一個整體,原式可以理解成y1與y2是加權係數,如何理解這個加權,要返回來思考一下,咱們先要明確一下根本的目的:咱們現在不是在求一個公式,而是在影象中根據2個點的畫素值求未知點的畫素值。這樣一個公式是不滿足咱們寫程式碼的要求的。
現在根據實際的目的理解,就很好理解這個加權了,y1與y2分別代表原影象中的畫素值,上面的公式可以寫成如下形式:
5.雙線性插值
已知Q11(x1,y1)、Q12(x1,y2)、Q21(x2,y1)、Q22(x2,y2),求其中點P(x,y)的值。
前面介紹過雙線性插值是分別在兩個方向計算了共3次單線性插值,如圖所示,先在x方向求2次單線性插值,獲得R1(x, y1)、R2(x, y2)兩個臨時點,再在y方向計算1次單線性插值得出P(x, y)(實際上調換2次軸的方向先y後x也是一樣的結果)。
1.x方向單線性插值 直接帶入前一步單線性插值最後的公式
2.y方向單線性插值
將第一步結果帶入第二步
回顧一下上面雙線性插值對應關係的圖,不難發現,在計算中有這樣的關係:
那麼上面的公式中的分母全都為0,如下:
在有些資料中,會寫成權重的形式,上面的展開式是下面的權重表示式的正確求法
這種權重的表示式也不難理解,觀察一下可以發現每個點的權重都和待求點和對角點的距離有關,比如
的座標有關
5.1遺留問題
上面遺留了個小問題,就是當對應關係公式帶入後跟原影象中的點發生重合後怎麼選取剩下3個點,根據上面的公式可以發現,無論我們怎麼選取,其實其餘3點的權重都至少1項為0,所以不論我們怎麼取剩下的3個點,對最終的結果都不會產生影響。
5.2總結
到此雙線性插值的計算已經完成了,但是我們現在只能說是勉強的完成雙線性插值演算法,為什麼這麼說,現在的計算方式有比較大的問題,看下面的內容。
6.雙線性插值的優化
原始公式:
雙線性插值的對應關係看似比較清晰,但還是有2個問題,我畫圖片進行說明。
根據座標系的不同,產生的結果不同 這張圖是左上角為座標系原點的情況,我們可以發現最左邊x=0的點都會有概率直接複製到目標影象中(至少原點肯定是這樣),而且就算不不和原影象中的點重合,也相當於進行了1次單線性插值(仔細想想為什麼,帶入到權重公式中會發現結果)
現在這張圖是右上角為座標系原點的情況,我們可以發現最右面的點都會有概率直接複製到目標影象中(至少原點肯定是這樣),而且就算不不和原影象中的點重合,也相當於進行了1次單線性插值。這樣如果我們採用不用的座標系產生的結果是不一樣的,而且無論我們採用什麼座標系,最左側和最右側(最上側和最下側)的點是不“公平的”,這是第一個問題。
整體的影象相對位置會發生變化看下面這張圖,左側是原影象(33),右側是目標影象(55),原影象的幾何中心點是(1, 1),目標影象的幾何中心點是(2, 2),根據對應關係,目標影象的幾何中心點對應的原影象的位置是(1.2, 1.2),如圖所示,那麼問題來了,目標影象的原點(0, 0)點和原始影象的原點是重合的,但是目標影象的幾何中心點相對於原始影象的幾何中心點偏右下,那麼整體影象的位置會發生偏移,為什麼這樣說,其實影象是由1個個的畫素點組成,單純說1個畫素點是沒有太大的意義的,1個畫素點跟相鄰畫素點的值的漸變或者突變形成影象顏色的漸變或者邊界,所以參與計算的點相對都往右下偏移會產生相對的位置資訊損失。這是第二個問題。
6.1計算機視覺中的蝴蝶效應
其實對於咱們人眼,上面的2個問題都不會產生太大的結果,但是對於現在的基於學習的學習類演算法,計算機通過卷積神經網路提取影象中的深層資訊,在這個過程中,我們人眼難以發現的變化也許會發生想象之外的變化,所以不要小看這兩個問題
6.2解決方案
幾何中心點重合對應公式:
再帶入到上面的情況,可以發現問題解決了,到此,才算完成完整的雙線性插值法,當然如果這樣計算髮現結果跟OpenCV的結果不一樣,是因為OpenCV還進行了很多速度上的優化,比如用整形計算代替浮點數計算。
對以上解釋的補充
1.雙線性插值
假設源影象大小為mxn,目標影象為axb。那麼兩幅影象的邊長比分別為:m/a和n/b。注意,通常這個比例不是整數,程式設計儲存的時候要用浮點型。目標影象的第(i,j)個畫素點(i行j列)可以通過邊長比對應回源影象。其對應座標為(i*m/a,j*n/b)。
顯然,這個對應座標一般來說不是整數,而非整數的座標是無法在影象這種離散資料上使用的。雙線性插值通過尋找距離這個對應座標最近的四個畫素點,來計算該點的值(灰度值或者RGB值)。如果你的對應座標是(2.5,4.5),那麼最近的四個畫素是(2,4)、(2,5)、(3,4),(3,5)。
若影象為灰度影象,那麼(i,j)點的灰度值可以通過一下公式計算:
f(i,j)=w1*p1+w2*p2+w3*p3+w4*p4;
其中,pi(i=1,2,3,4)為最近的四個畫素點,wi(i=1,2,3,4)為各點相應權值。關於權值的計算,在維基百科和百度百科上寫的很明白。
2.存在的問題
這部分的前提是,你已經明白什麼是雙線性插值並且在給定源影象和目標影象尺寸的情況下,可以用筆計算出目標影象某個畫素點的值。當然,最好的情況是你已經用某種語言實現了網上一大堆部落格上原創或轉載的雙線性插值演算法,然後發現計算出來的結果和matlab、openCV對應的resize()函式得到的結果完全不一樣。
那這個究竟是怎麼回事呢?
其實答案很簡單,就是座標系的選擇問題,或者說源影象和目標影象之間的對應問題。
按照網上一些部落格上寫的,源影象和目標影象的原點(0,0)均選擇左上角,然後根據插值公式計算目標影象每點畫素,假設你需要將一幅5x5的影象縮小成3x3,那麼源影象和目標影象各個畫素之間的對應關係如下:
只畫了一行,用做示意,從圖中可以很明顯的看到,如果選擇右上角為原點(0,0),那麼最右邊和最下邊的畫素實際上並沒有參與計算,而且目標影象的每個畫素點計算出的灰度值也相對於源影象偏左偏上。
那麼,讓座標加1或者選擇右下角為原點怎麼樣呢?很不幸,還是一樣的效果,不過這次得到的影象將偏右偏下。
最好的方法就是,兩個影象的幾何中心重合,並且目標影象的每個畫素之間都是等間隔的,並且都和兩邊有一定的邊距,這也是matlab和openCV的做法。如下圖:
如果你不懂我上面說的什麼,沒關係,只要在計算對應座標的時候改為以下公式即可,
int x=(i+0.5)*m/a-0.5
int y=(j+0.5)*n/b-0.5
instead of
int x=i*m/a
int y=j*n/b
利用上述公式,將得到正確的雙線性插值結果
部落格園:will_w 覺得有用就點個贊吧!~