雙線性插值法(bilinear interpolation)


前面講解了最近鄰插值法縮放圖像以及不足之處,本篇介紹另外一種插值法,介紹雙線性插值法之前先介紹線性插值。

1.   線性插值

  線性插值是指插值函數為一次多項式的插值方式,其在插值節點上的插值誤差為零。線性插值可以用來近似代替原函數,也可以用來計算得到查表過程中表中沒有的數值。如圖所示現在已知y=f(x)的兩個點坐標分別是(x0,y0),(x1,y1),現在在區間(x0,x1)內給定任意x,如何求y,線性插值法采用圖中紅點的y值代替f(x)的y值。假設x處的直線上的紅點坐標為(x,Y),那么Y約等於y。根據圖可以得到公式:

 

 

 

 y0y1表示得到

公式很好記,將分式看做權重系數。

 

2.   雙線性插值法

 

  雙線性插值法也叫雙線性內插,其核心思想是在兩個方向分別進行一次線性插值。雙線性插值作為數值分析中的一種插值算法,廣泛應用在信號處理,數字圖像和視頻處理等方面。

 

  如坐標圖所示,用橫縱坐標代表圖像像素的位置,f(x,y)代表該像素點(x,y)的彩色值或灰度值。

 

 

  將圖像放大或縮小,目的像素dst對應的原像素src中的坐標轉換公式如下,公式很好理解,可參考上一章最近鄰插值法。

  srcX=dstX*(srcWidth/dstWidth)

 

   srcY=dstY*(srcHeight/dstHeight)

 

  上式中,dstXdstY為目標圖像的某個像素的橫縱坐標,dstWidthdstHeight為目標圖像的長與寬;srcWidthsrcHeight為原圖像的寬度與高度。srcXsrcY為目標圖像在該點(dstXdstY)對應的原圖像的坐標。

  現在假設目標圖像的像素點(x’y’)映射到原圖像中是(x,y),也就是圖中的P點。設Q11 = (x1, y1)Q12 = (x1, y2)Q21 = (x2, y1) Q22 = (x2, y2),圖中Q11,Q12,Q21,Q22分別為距離P點的最近的四個點。分別在X方向進行兩次插值,最后在y方向進行插值即可得到目標圖像的像素值。公式如下:

 

先計算X方向(也可以先計算Y方向,再計算X方向)的線性插值:

 

 

 再在y方向進行線性插值得到f(P)

 

 

經過公式的進一步化簡可以得到:

 

 

 

 

由於是最近的點,所以Q的四個點的坐標之間相差1,故進一步化簡為:

 

 

 

 

 

現假設x=i+uy=j+vij為整數,u,v為小數。得到下式:

 

下面為本人自己設計的例子與具體計算過程:

  將圖像放大兩倍(對像素數擴大2倍),以?處的像素為例:

  右邊圖中問號的坐標為(5,4),映射到原圖像的像素點的坐標為

  srcX=dstX*(srcWidth/dstWidth)=5*(4/8)=2.5

  srcY=dstY*(srcHeight/dstHeight)=4*(4/8)=2

  (srcX,srcY)=(2+0.5,2+0)u=0.5v=0映射的src坐標及對應的最近的四個Q點下如圖所示。若x=i+u,y=j+v。則可以得到紅色框的像素及其周圍四個Q(i,j)(i+1,j)(i,j+1)(i+1,j+1),即可以得到?處的像素值。

 

 

 

 

 

 

  每個像素點的RGB對應如下:

  204,255,153  153,255,153   102,255,153   0,255,153

  204,255,102  153,255,102   102,255,102   0,255,0

  204,255,51   153,255,51    102,255,51    51,204,51

  204,204,0    153,204,0     102,153,0     0,153,0

   Q11(2,2)Q21(2,3)Q12(3,2)Q22(3,3)P(2.5,2)

采用雙線性插值法得到紅色框處的像素值:

 

  R=0.5*102+0.5*51=51+25.5=76.5

 

  G=0.5*255+0.5*204=127.5+102=229.5

  B=0.5*51+0.5*51=25.5+25.5=51

 

  由於顏色表示范圍為0-255整數,R可以用127代替或128代替,B也是。所以問號處的顏色應該為:

 

 

 

  然后以同樣的方式計算得到所有的像素值,放大后的圖像對比如下:

 

 

 

 

 

  當出現ij為邊界坐標時,會出現(i+1,j)(i,j+1)(i+1,j+1)的點在實際的圖中不存在,此時可以用(i,j)(i-1,j)(i,j-1)(i-1,j-1)。如果srcXsrcY是整數,則其中一個點是(i,j),剩余的3個點其實無所謂,因為u,v0f(p)=f(i,j)

 

 

 

3.   代碼實現

 

  python實現:

from matplotlib import pyplot as plt
import numpy as np

def bilinear_interpolation(srcimage_vector,dstwidthtimes ,dstheighttimes ):
    print("原始圖像",srcimage_vector)
    srcHeight=srcimage_vector.shape[0]
    srcWidth=srcimage_vector.shape[1]
    print("srcHeight",srcHeight)
    print("srcWidth",srcWidth)
    dstWidth, dstHeight=int(dstwidthtimes*srcWidth),int(dstheighttimes*srcHeight)
    # 定義一個三維矩陣存儲目標圖像,每個像素由RGB三種顏色組成,shape接受一個元組,可以創建多維矩陣
    dstVector = np.zeros(shape=(dstHeight, dstWidth, 3), dtype=int)  # 默認是float64
    # 遍歷目標圖像的每一個像素
    for dstY in range(0,dstHeight):
        for dstX in range(0,dstWidth):
            Q = [(0, 0)] * 4  # Q11=Q12=Q21=Q22=0
            Qdict = {}
            # 坐標換算
            dstX_srcX = dstX * (srcWidth / dstWidth)  # python中/表示除法,//表示整除
            dstY_srcY = dstY * (srcHeight / dstHeight)
            u = round(dstX_srcX % 1, 2)
            v = round(dstY_srcY % 1, 2)
            if int(dstX_srcX)==srcWidth-1:
                positionX = [int(dstX_srcX)-1, int(dstX_srcX)]  # 左右范圍
            else:
                positionX=[int(dstX_srcX),int(dstX_srcX)+1]#左右范圍
            if int(dstY_srcY)==srcHeight-1:
                positionY = [int(dstY_srcY)-1, int(dstY_srcY)]  # 上下范圍
            else:
                positionY = [int(dstY_srcY), int(dstY_srcY) + 1]  #上下范圍
            k=0
            for m in range(0, 2):  # 得到Q的四個點坐標,分別是Q11,Q12,Q21,Q22
                for n in range(0, 2):
                    Q[k] = (positionX[m], positionY[n])
                    Qdict[Q[k]] = srcimage_vector[positionY[n], positionX[m]]
                    k = k + 1
            # 通過四個點計算得到dst的像素值
            dstVector[dstY][dstX] = Qdict[Q[0]] * (1 - u) * (1 - v) + Qdict[Q[1]] * (1 - u) * (v) + Qdict[Q[2]] * (u) * (
                        1 - v) + Qdict[Q[3]] * (u) * (v)
    print(dstVector)
    ax = plt.gca()  # 獲取到當前坐標軸信息
    ax.xaxis.set_ticks_position('top')  # 將X坐標軸移到上面
    plt.imshow(dstVector)  # 顯示數組
    plt.show()
    plt.imsave('shaungxianxing.jpg', dstVector.astype(np.uint8))  # matplotlib保存圖像的時候,只接受浮點數或者unit8的整數類型

if __name__=="__main__":
    # imagePath = r'songshu.jpg'
    imagePath = r'cup.jpg'
    # imagePath = r'aoyunwuhuan.jpg'
    image_vector = plt.imread(imagePath)
    # dstwidth,dstheight用倍數表示,表示是src圖像的多少倍
    # dstwidth, dstheight=1.5,1.5
    dstwidth, dstheight=0.2,0.2
    bilinear_interpolation(image_vector,dstwidth,dstheight)

 

  C++實現:后面補充。

4.效果

自己制作的奧運五環

原圖雙線性插值法放大2倍后的圖像

 

 

  鄰近法放大2倍后的圖像

 

 

 

  網上找的松鼠:

  原圖 

 

放大2倍后

 

 

縮小0.2倍后

手機拍的圖

 

 

原圖

 

縮小0.2

 

 

 結論:通過圖可以看出,雙線性插值法,鋸齒狀比鄰近法效果好多了,但是也會伴隨着圖片的變模糊。

5.存在問題及改進:

 

  關於中心問題,后面補充

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM