关于插值的相关理解
內(nèi)插是數(shù)學領(lǐng)域數(shù)值分析中的通過已知的離散數(shù)據(jù)求未知數(shù)據(jù)的過程或方法。
根據(jù)若干離散的數(shù)據(jù)數(shù)據(jù),得到一個連續(xù)的函數(shù)(也就是曲線)或者更加密集的離散方程與已知數(shù)據(jù)相吻合。這個過程叫做擬合。內(nèi)插是曲線必須通過已知點的擬合。
1.線性插值
已知坐標(x0,y0)與(x1,y1),要得到[x0,x1]區(qū)間內(nèi)某一位置x在直線上的值。
由于x值已知,所以可以從公式得到y(tǒng)的值
已知y求x的過程與以上過程相同,只是x與y要進行交換。
例如,
原來的數(shù)值序列:0,10,20,30,40
線性插值一次為:0,5,10,15,20,25,30,35,40
即認為其變化(增減)是線形的,可以在坐標圖上畫出一條直線。
線性插值經(jīng)常用于補充表格中的間隔部分。
兩值之間的線性插值基本運算在計算機圖形學中的應(yīng)用非常普遍,以至于在計算機圖形學領(lǐng)域的行話中人們將它稱為lerp。所有當今計算機圖形處理器的硬件中都集成了線性插值運算,并且經(jīng)常用來組成更為復(fù)雜的運算:
例如,可以通過三步線性插值完成一次雙線性插值運算。由于這種運算成本較低,所以對于沒有足夠數(shù)量條目的光滑函數(shù)來說,它是實現(xiàn)精確快速查找表的一種非常好的方法。
在一些要求較高的場合,線性插值經(jīng)常無法滿足要求。在這種場合,可以使用多項式插值或者樣條插值來代替。
線性插值可以擴展到有兩個變量的函數(shù)的雙線性插值。
雙線性插值經(jīng)常作為一種粗略的抗混疊濾波器使用,三線性插值用于三個變量的函數(shù)的插值。線性插值的其它擴展形勢可以用于三角形與四面體等其它類型的網(wǎng)格運算。
2.雙線性插值
在地球物理中,會經(jīng)常用到雙線性插值(Bilinear interpolation)。比
如,模擬生成的地表均勻網(wǎng)格上的速度場或者同震位移場。要與GPS觀測點上的觀測同震位移場進行比較。就必須將均勻網(wǎng)格點的值插值到GPS太站上。這就需要用到雙線性插值。
雙線性插值。
Inmathematics,bilinear interpolationis anextension oflinear interpolationforinterpolatingfunctions of two variables(e.g,xandy) on aregular grid. The interpolated function should not use the term ofx2ory2, butxy, which is thebilinear formofxandy.
其核心思想是在兩個方向分別進行一次線性插值。
Thekey ideais to perform linear interpolation first in one direction, and then again in the other direction.Although each step is linear in the sampled values and in the position, the interpolation as a whole is not linear but rather quadratic in the sample location (details below).
紅色的數(shù)據(jù)點與待插值得到的綠色點
假如我們想得到未知函數(shù) f 在點 P = (x, y) 的值,假設(shè)我們已知函數(shù) f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四個點的值。
首先在 x 方向進行線性插值,得到
然后在 y 方向進行線性插值,得到
這樣就得到所要的結(jié)果 f(x, y),
如果選擇一個坐標系統(tǒng)使得 f 的四個已知點坐標分別為 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化簡為
或者用矩陣運算表示為
與這種插值方法名稱不同的是,這種插值方法并不是線性的,它的形式是
它是兩個線性函數(shù)的乘積。看到了吧,雙線性插值并不是線性。
Contrary to what the name suggests, the bilinear interpolant isnotlinear
另外,插值也可以表示為
對于單位正方形,
在這兩種情況下,常數(shù)的數(shù)目都對應(yīng)于給定的 f 的數(shù)據(jù)點數(shù)目。
線性插值的結(jié)果與插值的順序無關(guān)。首先進行 y 方向的插值,然后進行 x 方向的插值,所得到的結(jié)果是一樣的。
雙線性插值的一個顯然的三維空間延伸是三線性插值。
3.三線性插值
三線性插值是在三維離散采樣數(shù)據(jù)的張量積網(wǎng)格上進行線性插值的方法。
這個張量積網(wǎng)格可能在每一維度上都有任意不重疊的網(wǎng)格點,但并不是三角化的有限元分析網(wǎng)格。這種方法通過網(wǎng)格上數(shù)據(jù)點在局部的矩形棱柱上線性地近似計算點(x,y,z)的值。
三線性插值在一次n=1三維D=3(雙線性插值的維數(shù):D=2,線性插值:D=1)的參數(shù)空間中進行運算,這樣需要(1 + n)D = 8個與所需插值點相鄰的數(shù)據(jù)點。
三線性插值等同于三維張量的一階B樣條插值。
三線性插值運算是三個線性插值運算的張量積。
實例
在一個步距為1的周期性立方網(wǎng)格上,取xd,yd,zd 為待計算點,距離小于 x,y,z, 的最大整數(shù)的差值,即,
首先沿著z軸插值,得到:
然后,沿著y軸插值,得到:
w1 = i1(1 − yd) + i2yd
w2 = j1(1 − yd) + j2yd
最后,沿著x軸插值,得到:
IV = w1(1 − xd) + w2xd
這樣就得到該點的預(yù)測值。
三線性插值的結(jié)果與插值計算的順序沒有關(guān)系,也就是說,按照另外一種維數(shù)順序進行插值,例如沿著 x、 y、z 順序插值將會得到同樣的結(jié)果。這也與張量積的交換律完全一致。
4. 雙線性插值算法性能效果優(yōu)化
一般用在二維圖像插值領(lǐng)域
假設(shè)源圖像大小為mxn,目標圖像為axb。那么兩幅圖像的邊長比分別為:m/a和n/b。注意,通常這個比例不是整數(shù),編程存儲的時候要用浮點型。
目標圖像的第(i,j)個像素點(i行j列)可以通過邊長比對應(yīng)回源圖像。其對應(yīng)坐標為(i*m/a,j*n/b)。顯然,這個對應(yīng)坐標一般來說不是整數(shù),而非整數(shù)的坐標是無法在圖像這種離散數(shù)據(jù)上使用的。
雙線性插值通過尋找距離這個對應(yīng)坐標最近的四個像素點,來計算該點的值(灰度值或者RGB值)。
如果你的對應(yīng)坐標是(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)為各點相應(yīng)權(quán)值。關(guān)于權(quán)值的計算,在維基百科和百度百科上寫的很明白。
存在的問題
這部分的前提是,你已經(jīng)明白什么是雙線性插值并且在給定源圖像和目標圖像尺寸的情況下,可以用筆計算出目標圖像某個像素點的值。
當然,最好的情況是你已經(jīng)用某種語言實現(xiàn)了網(wǎng)上一大堆博客上原創(chuàng)或轉(zhuǎn)載的雙線性插值算法,然后發(fā)現(xiàn)計算出來的結(jié)果和matlab、openCV對應(yīng)的resize()函數(shù)得到的結(jié)果完全不一樣。
那這個究竟是怎么回事呢?
其實答案很簡單,就是坐標系的選擇問題,或者說源圖像和目標圖像之間的對應(yīng)問題。
按照網(wǎng)上一些博客上寫的,源圖像和目標圖像的原點(0,0)均選擇左上角,然后根據(jù)插值公式計算目標圖像每點像素,假設(shè)你需要將一幅5x5的圖像縮小成3x3,那么源圖像和目標圖像各個像素之間的對應(yīng)關(guān)系如下:
只畫了一行,用做示意,從圖中可以很明顯的看到,如果選擇左上角為原點(0,0),那么最右邊和最下邊的像素實際上并沒有參與計算,而且目標圖像的每個像素點計算出的灰度值也相對于源圖像偏左偏上。
只要在計算對應(yīng)坐標的時候改為以下公式即可,
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
利用上述公式,將得到正確的雙線性插值結(jié)果
總結(jié):
總結(jié)一下,我得到的教訓有這么幾條。
1.網(wǎng)上的一些資料有的時候并不靠譜,自己還是要多做實驗。
2.不要小瞧一些簡單的、基本的算法,讓你寫你未必會寫,而且其中可能還藏著一些玄妙。
3.要多動手編程,多體會算法,多看大牛寫的源碼(雖然有的時候很吃力,但是要堅持看)。
在圖像處理中,雙線性插值算法的使用頻率相當高,比如在圖像的縮放中,在所有的扭曲算法中,都可以利用該算法改進處理的視覺效果。
用一個簡單的數(shù)學表達式可以表示如下:
f(x,y)=f(0,0)(1-x)(1-y)+f(1,0)x(1-y)+f(0,1)(1-x)y+f(1,1)xy
合并有關(guān)項,可寫為:f(x,y)=( f(0,0)(1-x)+ f(1,0) x ) (1-y) + ( f(0,1)(1-x) + f(1,1)x ) y
由上式可以看出,這個過程存在著大量的浮點數(shù)運算,對于圖像這樣大的計算用戶來說,是一個較為耗時的過程。
考慮到圖像的特殊性,他的像素值的計算結(jié)果需要落在0到255之間,最多只有256種結(jié)果,由上式可以看出,一般情況下,計算出的f(x,y)是個浮點數(shù),我們還需要對該浮點數(shù)進行取整。
因此,我們可以考慮將該過程中的所有類似于1-x、1-y的變量放大合適的倍數(shù),得到對應(yīng)的整數(shù),最后再除以一個合適的整數(shù)作為插值的結(jié)果。
如何取這個合適的放大倍數(shù)呢,要從三個方面考慮,
第一:精度問題,如果這個數(shù)取得過小,那么經(jīng)過計算后可能會導(dǎo)致結(jié)果出現(xiàn)較大的誤差。
第二,這個數(shù)不能太大,太大會導(dǎo)致計算過程超過長整形所能表達的范圍。
第三:速度考慮。假如放大倍數(shù)取為12,那么算式在最后的結(jié)果中應(yīng)該需要除以12*12=144,但是如果取為16,則最后的除數(shù)為16*16=256,這個數(shù)字好,我們可以用右移來實現(xiàn),而右移要比普通的整除快多了。
綜合考慮上述三條,我們選擇2048這個數(shù)比較合適。
NewX = Int(PosX) '向下取整,NewX=25
NewY = Int(PosY) '向下取整,NewY=58PartX = (PosX - NewX) * 2048 '對應(yīng)表達式中的X
PartY = (PosY - NewY) * 2048 '對應(yīng)表達式中的Y
InvX = 2048 - PartX '對應(yīng)表達式中的1-X
InvY = 2048 - PartY '對應(yīng)表達式中的1-Y
Index1 = SamStride * NewY + NewX * 3 '計算取樣點左上角鄰近的那個像素點的內(nèi)存地址
Index2 = Index1 + SamStride '左下角像素點地址
ImageData(Speed + 2) = ((Sample(Index1 + 2) * InvX + Sample(Index1 + 5) * PartX) * InvY + (Sample(Index2 + 2) * InvX +
Sample(Index2 + 5) * PartX) * PartY) 4194304 '處理紅色分量
ImageData(Speed + 1) = ((Sample(Index1 + 1) * InvX + Sample(Index1 + 4) * PartX) * InvY + (Sample(Index2 + 1) * InvX +
Sample(Index2 + 4) * PartX) * PartY) 4194304 '處理綠色分量
ImageData(Speed) = ((Sample(Index1) * InvX + Sample(Index1 + 3) * PartX) * InvY + (Sample(Index2) * InvX +
Sample(Index2 + 3) * PartX) * PartY) 4194304 '處理藍色分量
以上代碼中涉及到的變量都為整型(PosX及PosY當然為浮點型)。
代碼中Sample數(shù)組保存了從中取樣的圖像數(shù)據(jù),SamStride為該圖像的掃描行大小。
觀察上述代碼,除了有2句涉及到了浮點計算,其他都是整數(shù)之間的運算。
在Basic語言中,編譯時如果勾選所有的高級優(yōu)化,則4194304會被編譯為>>22,即右移22位,如果使用的是C語言,則直接寫為>>22。
需要注意的是,在進行這代代碼前,需要保證PosX以及PosY在合理的范圍內(nèi),即不能超出取樣圖像的寬度和高度范圍。
通過這樣的改進,速度較直接用浮點類型快至少100%以上,而處理后的效果基本沒有什么區(qū)別。
endl;
總結(jié)
- 上一篇: leetcode56. 合并区间
- 下一篇: 夸克技术负责人蒋冠军:夸克大模型已将问答