一文搞懂常用的插值算法

導讀

做圖像處理的同學應該經常都會用到

圖像的縮放,我們都知道圖片存儲的時候其實就是一個矩陣,所以在對圖像進行縮放操作的時候,也就是在對矩陣進行操作,如果想要將圖片放大,這裡我們就需要用到過採樣算法來擴大矩陣,如果想要縮小圖片就使用欠採樣

一文搞懂常用的插值算法

如上圖所示,左圖是原圖像矩陣,右圖是擴大後的圖像矩陣,右圖中的橙色點表示的是矩陣擴大之後通過插值算法填充的像素值。所以,這篇文章我們主要探討的就是如何來通過插值算法來填充像素值

相關函數介紹

在opencv中提供了一個resize函數用來調整圖像的大小,裡面提供了好幾種不同的插值算法,如下圖所示

一文搞懂常用的插值算法

這裡我們主要介紹最常用的前5中插值算法,最後兩種插值算法主要是應用在仿射變換,cv.WARP_FILL_OUTLIERS在從srcdst變換的時候可能會出現異常值,通過這個設定可以將異常值的像素置0。而cv.WARP_INVERSE_MAP是應用在仿射變換的逆變換,從dstsrc的變換,關於仿射變換的更多資料可以參考我的上篇文章

插值算法效果對比

一文搞懂常用的插值算法


我們通過隨機生成一個5×5的圖片,然後通過不同的插值算法將其放大10倍之後,來對比最終圖片的效果。

一文搞懂常用的插值算法

如果大家覺得灰度圖不方便觀察,我們可以通過設置plt.imshow

cmap參數來控制顏色,matplotlib提供了幾種不同的類別的色彩映射方式

cmap的類別

  • Sequential
    通常使用單一的色調逐漸增加亮度和顏色,可以用來表示有序的信息
一文搞懂常用的插值算法

  • Diverging
    通過改變兩種不同的顏色的亮度和飽和度,在中間以不飽和的顏色相遇,通常來用繪製具有關鍵的中間值或者數據偏離零的信息
  • 一文搞懂常用的插值算法


  • Cyclic

    改變兩種不同顏色的亮度,在中間和開始/結束以不飽和的顏色相遇,應用於在端點出環繞的信息。
  • 一文搞懂常用的插值算法

  • Qualitative
    用於表示沒有關係排序的信息
  • 一文搞懂常用的插值算法

  • Miscellaneous
    同上
  • 一文搞懂常用的插值算法

    這裡我們為了方便觀察不同插值算法之間的區別,我們可以選用雜色來來觀察,這裡我就隨機選用了Set1,只需要將上面代碼中的cmap改成了Set1即可

    一文搞懂常用的插值算法

    通過初步觀察不同插值算法後的效果圖片我們可以發現,

    最近鄰插值區域插值算法的效果,而線性插值三次樣條插值Lanczos插值整體效果看起來差不多,不過細節部分還是有所差別,接下來我們就從這幾種插值算法來分析一下。

    最近鄰插值(Nearest Interpolation)

    最近鄰插值也稱近端插值,是一種在一維或多維空間上進行多變元插值的簡單方法。插值是一種通過已知的、離散的數據點,在範圍內推求新數據點的過程或方法。最近鄰插值算法選擇距離所求數據點最近點的值,並且根本不考慮其他相鄰點的值,從而產生一個分段常數的內插值來作為所求數據點的值。

    一文搞懂常用的插值算法

    如上圖所示,黑色的×表示需要插入的值,它會選擇距離它最近的P(x+1,y)的值來作為它的值。
    如果距離四個點的距離都相等,最近鄰插值會如何選擇?

    一文搞懂常用的插值算法

    通過上圖不難發現,當插入的值距離四個點都相等時,會選擇距離最近的左上角的值,這是

    因為圖像座標系的原點位於左上角。

    線性插值(Linear interpolation)

    這裡的線性插值其實是指雙線性插值,這種插值算法也是resize函數中默認使用的插值算法
    雙線性插值,也被稱為雙線性內插。雙線插值是對線性插值在二維座標系上的擴展,用於對雙變量函數進行插值,其核心思想是在兩個方向上分別進行一次線性插值。為了幫助大家更好的理解雙線性插值算法,我們先來看線性插值
    假設我們已知座標(x0,y0)與(x1,y1),我們想要得到該區間[x0,x1上任意位置x所對應y的值,如下圖所示

    一文搞懂常用的插值算法

    我們可以求出直線的方程,然後將x座標代入到方程就可以求出對應的y值,通過直線方程的兩點式可以得到

    一文搞懂常用的插值算法

    然後我們根據已知的x,將其代入上式可得

    一文搞懂常用的插值算法

    在瞭解線性插值以後,我們再來看看雙線性插值
    假如我們想得到未知函數fff在點P=(x,y)的值,假設我們已知函數f在Q11=(x1,y1),Q12=(x1,y2),Q21=(x2,y1)及Q22=(x2,y2)四個點的值

    一文搞懂常用的插值算法

    首先在x方向進行線性插值,利用Q11​和Q21​可以求得R1的y值,利用Q12​和Q22​可以求得R2的y值


    一文搞懂常用的插值算法

    細心的同學也許發現了,這個插值好像與線性插值並不是一模一樣的,所以我們用的是≈而非=,這裡其實採用的是一種加權平均算法結合兩點來計算其中一點的y值,主要是根據計算點距離兩個端點在x方向上的距離來計算計算點y值所佔的比例。

    接下來,我們再利用已經計算出來的R1和R2​來P點的插值,可得

    一文搞懂常用的插值算法

    仔細觀察上面的公式不難發現,其實PPP點的值等於周圍四個點與P點所構成的四個對角矩形面積的加權平均

    一文搞懂常用的插值算法

    一文搞懂常用的插值算法

    雙三次插值(Bicubic interpolation)

    雙三次插值是一種更加複雜的插值算法,是二維空間中最常用的插值算法,相對雙線性插值的圖像邊緣更加平滑,函數f在點(x,y)的值可以通過矩形網格中最近的十六個採樣點的加權平均得到,這裡需要使用兩個多項式插值三次函數,每個方向使用一個。


    雙三次插值通過以下公式進行計算:

    一文搞懂常用的插值算法

    計算係數aij​的過程依賴於插值數據的特性。如果已知插值函數的導數,常用的方法就是使用四個頂點的高度以及每個頂點的三個導數。一階導數h′x與h′y表示x與y方向的表面斜率,二階相互導數h''xy表示同時在x與y方向的斜率。這些值可以通過分別對x與y向量取微分得到。對於網格單元的每個頂點,將局部座標(0,0)、(1,0)、(0,1)、(1,1)代入這些方程,再解這16個方程。

    看了上面這段話之後,貌似還是不太好理解,接下來我們看一個例子,雙三次插值常用的BiCubic函數如下圖

    一文搞懂常用的插值算法

    上式中的a取-0.5即可,函數圖像如下

    一文搞懂常用的插值算法

    對待插值的像素點(x,y)(x,y可為浮點數),取其附近的4×4領域點(xi,yi)其中i,j=0,1,2,3。按下面的公式進行插值計算:

    一文搞懂常用的插值算法

    例如,我們需要求解P點值,在P點周圍有16個點

    一文搞懂常用的插值算法

    首先,我們要求出當前像素與PPP點的距離,比如a00​距離P(x+u,y+v)的距離為(1+u,1+v),那麼我們可以得到a00對應的係數為(W(1+u),W(1+v)),所以a11​的係數為(W(u),W(v)),a22的係數為(W(1−u),W(1−v)),a33的係數為W(2−u),W(2−v),同理可以得到剩下點的係數,再根據上面的函數就可以求出P點的值。
    關於雙三次插值函數更加詳細介紹可以參考:論文http://www.ncorr.com/download/publications/keysbicubic.pdf

    區域插值(Area interpolation)

    區域插值算法主要分兩種情況,縮小圖像和放大圖像的工作原理並不相同。

    • 縮小圖像
      如果圖像縮小的比例是整數倍,在調用INTER_LINEAR_EXACT插值算法時,如果圖像的寬和高的縮小比例都是2,而且圖像的通道數不是2,實際上會調用INTER_AREA。在調用INTER_LINEAR時,如果圖像的寬和高的縮小比例都是2,實際上是會調用INTER_AREA
      INTER_AREA實際上是個
      box filter,類似於均值濾波器
    • 放大圖像
      如果放大圖像的比例是整數倍,與最近鄰插值相似。如果放大的比例不是整數倍,則會採用線性插值

    Lanczos插值

    Lanczos插值屬於一種模板算法,需要通過計算模板中的權重信息來計算x對應的值。對於一維信息,假如我們輸入的點集為X,那麼,Lanczos對應有個窗口模板Window,窗口中每個位置的權重計算如下:

    一文搞懂常用的插值算法

    一文搞懂常用的插值算法

    通常a取2或者3,當a=2時,該算法適應於圖像縮小的插值。當a=3時,算法適用於圖像放大的插值。根據計算出來的權重信息,然後再根據xxx即可求出對應的加權平均:

    一文搞懂常用的插值算法

    插值算法耗時比較

    對於不同的插值算法,在縮放因子不同的時候,耗時會有所區別,具體對照如下表所示

    一文搞懂常用的插值算法

    總結

    如果要縮小圖像,推薦使用INTER_AREA

    插值效果最好,如果要放大圖像INTER_CUBIC效果最好,但是速度較慢,可以考慮使用INTER_LINEAR速度較快,效果也還不錯。

    參考:
    1.http://www.1zlab.com/wiki/python-opencv-tutorial/opencv-interpolation-algrithm/
    2.https://zh.wikipedia.org/wiki/%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC
    3.https://zh.wikipedia.org/wiki/%E5%8F%8C%E4%B8%89%E6%AC%A1%E6%8F%92%E5%80%BC
    4.https://blog.csdn.net/nandina179/article/details/85330552
    5.https://blog.csdn.net/qq_29058565/article/details/52769497
    6.https://blog.csdn.net/u010555688/article/details/24352343
    7.https://zhuanlan.zhihu.com/p/38493205


    分享到:


    相關文章: