最近在學習tensorflow時對於圖像的縮放有疑惑,決定重新抽絲剝繭搞懂。在tf.image.resize(image,(256,256),method=0)中,mehod是默認為0,也就是雙線性插值法,本篇先講解method=1的情況,也就是最近鄰插值法。
1.原理與應用
最近鄰插值法nearest_neighbor是最簡單的灰度值插值。也稱作零階插值,就是令變換后像素的灰度值等於距它最近的輸入像素的灰度值。最近鄰插值法可應用於圖像的縮放,因為簡單的變換與計算,效果一般不好。舉例說明其變換過程:
先假設一個2X2像素的圖片采用最近鄰插值法需要放大到4X4像素的圖片,右邊?該為多少。
2. 公式及計算
最近鄰插值法坐標變換計算公式:
srcX=dstX*(srcWidth/dstWidth)
srcY=dstY*(srcHeight/dstHeight)
上式中,dstX與dstY為目標圖像的某個像素的橫縱坐標,dstWidth與dstHeight為目標圖像的長與寬;srcWidth與srcHeight為原圖像的寬度與高度。srcX,srcY為目標圖像在該點(dstX,dstY)對應的原圖像的坐標。至於公式為啥是這個樣,和容易理解,如果是放大圖像,(srcWidth/dstWidth)值小於1,同樣將dstX同比例映射到原圖像的srcX中,如果srcWidth/dstWidth=1,就相當於復制了圖片。
與opencv一樣,以左上角為(0,0)坐標。
右圖為經過放大后的目標圖像,?處的坐標為(3,2),根據公式計算得到
srcX=3*(2/4)=1.5,srcY=2*(2/4)=1;故?處的像素應該為原圖像中的(1.5,1)像素的值,但是像素坐標沒有小數,一般采用四舍五入取最鄰,所以最終的結果為(2,1),對應原圖像的橙色。其他類比得到放大后的圖像:
3.代碼及實現
Python實現:
from matplotlib import pyplot as plt import numpy as np from PIL import Image #1.首先得到原圖像的寬度、高度 def get_image_information(image_path): vector=plt.imread(image_path) # print(vector)#得到圖像的三維矩陣 # print(type(vector)) # print(vector.shape)#得到(高,寬,通道數) height=vector.shape[0] width=vector.shape[1] return height,width,vector def getdst_image_vector(srcHeight,srcWidth,srcVector,dstHeight,dstWidth): #定義一個三維矩陣存儲目標圖像,每個像素由RGB三種顏色組成,shape接受一個元組,可以創建多維矩陣 dstVector=np.zeros(shape=(dstHeight,dstWidth,3),dtype=int)#默認是float64 # print(dstVector) #遍歷目標圖像的每一個像素 for dstX in range(1,dstWidth+1):#[0,dstWid-1],#矩陣從0開始,不是從1開始 for dstY in range(1,dstHeight+1):#[0,dstHeight-1] #坐標換算 dstX_srcX=dstX*(srcWidth/dstWidth)#python中/表示除法,//表示整除 dstY_srcY=dstY*(srcHeight/dstHeight) # print(dstX_srcX,dstY_srcY) #最近鄰四舍五入,采用round函數實現 dstX_srcX_round=int(round(dstX_srcX)) dstY_srcY_round=int(round(dstY_srcY)) # print(srcVector[dstX_srcX_round][dstY_srcY_round]) # print(dstX_srcX_round,dstY_srcY_round) dstVector[dstY-1][dstX-1]=srcVector[dstY_srcY_round-1][dstX_srcX_round-1]#這個地方要認真琢磨,x,y也不能搞反了 # dstVector[dstX][dstY]=srcVector[dstX_srcX_round][dstY_srcY_round] print(dstVector) # pic=Image.fromarray(dstVector, "RGB") # pic.show() plt.imshow(dstVector) # 顯示數組 plt.show() plt.imsave('鄰近法得到的圖像.jpg',dstVector.astype(np.uint8))#matplotlib保存圖像的時候,只接受浮點數或者unit8的整數類型 # plt.imsave('鄰近法得到的圖像.jpg',dstVector/255) return dstVector if __name__=='__main__': imagePath=r'songshu.jpg' srcHeight,srcWidth,srcVector=get_image_information(imagePath) dstHeight=int(0.5*srcHeight) dstWidth =int(0.5*srcWidth) # print(dstHeight,dstWidth) dstVector=getdst_image_vector(srcHeight,srcWidth,srcVector,dstHeight,dstWidth) # print("srcVector",srcVector) # print("dstVector",dstVector)
C++實現:后面再補充。
4.效果展示
對自己用畫圖面板制作的奧運五環圖及網上的圖對圖像采用最近鄰插值法進行擴大與縮放,效果如下:
上圖左邊為自己畫的100X80P的奧運圖,右圖為長寬不等比例擴大后的圖像
左圖為松鼠的原圖,中間圖為像素等比例擴大1.5倍后的圖,最右邊為0.2倍原圖像。可以看到圖像縮放后,效果並不理想,很多鋸齒馬賽克。