參考博客,我也是看這篇文章入門的。
單線性插值就好像初高中的兩點法求函數的表達式,利用y0和y1的加權表示y
從兩個方向分別插值:
合並上式:
雙線型內插值算法就是一種比較好的圖像縮放算法,它充分的利用了源圖中虛擬點四周的四個真實存在的像素值來共同決定目標圖中的一個像素值,因此縮放效果比簡單的最鄰近插值要好很多。由於圖像雙線性插值只會用相鄰的4個點,因此以下公式的分母都是1。算法描述:對於一個目的像素,設置坐標通過反向變換得到的浮點坐標為(i+u,j+v) (其中i、j均為浮點坐標的整數部分,u、v為浮點坐標的小數部分,是取值[0,1)區間的浮點數),則這個像素得值 f(i+u,j+v) 可由原圖像中坐標為 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所對應的周圍四個像素的值決定,即:
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
其中f(i,j)表示源圖像(i,j)處的的像素值,以此類推。單線性插值:已知數據 (x0, y0) 與 (x1, y1),要計算 [x0, x1] 區間內某一位置 x 在直線上的y值。雙線性插值:已知函數 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四個點的值。求未知函數 f 在點 P = (x, y) 的值。
from PIL import Image
from datetime import datetime
import matplotlib.pyplot as plt
import numpy as np
import math
import os
img_path = r'D:\jupyter_py\in50.jpg' #源圖的地址
target_size = (600,800, 3) #目標圖像的尺寸
img_arr = np.array(Image.open(img_path), np.uint8)
source_img = Image.fromarray(img_arr.astype(np.uint8)) #源圖編碼
plt.imshow(source_img)
plt.show()
source_size = img_arr.shape #源圖尺寸
print(source_size)
ratio_x, ratio_y = source_size[0]/target_size[0], source_size[1]/target_size[1] #源圖和目標圖像長寬之比
def cal(x, y, c): #傳入的是從目標圖像轉化為原圖像中的坐標值,但是並不是整數
x, y = math.modf(x), math.modf(y) #得到輸入值得整數部分和小數部分
mod_x, int_x, mod_y, int_y = round(x[0],4),int(x[1]),round(y[0],4),int(y[1]) #小數部分保留4位,索引必須為整數
#print(int_x, int_y)
if int_x<source_size[0]-1 and int_y<source_size[1]-1: #如果不加該條件,索引值會溢出
p1 = (1-mod_x)*(1-mod_y)*img_arr[int_x, int_y, c] + mod_x*(1-mod_y)*img_arr[int_x+1, int_y, c]
p2 = (1-mod_x)*mod_y*img_arr[int_x, int_y+1, c] + mod_x*mod_y*img_arr[int_x+1, int_y+1, c]
else:
p1 = (1-mod_x)*(1-mod_y)*img_arr[int_x, int_y, c] + mod_x*(1-mod_y)*img_arr[int_x, int_y, c]
p2 = (1-mod_x)*mod_y*img_arr[int_x, int_y, c] + mod_x*mod_y*img_arr[int_x, int_y, c]
p = p1 + p2 #原理公式
return p #上述處理比較草率,x,y分別溢出嚴格應進行三次條件判斷
if __name__ == '__main__':
start = datetime.now() #計算運算時間
resized_img = [cal(i*ratio_x, j*ratio_y, c) for i in range(target_size[0]) for j in range(target_size[1]) for c in range(target_size[2])] #從三個維度依次計算
resized_img = np.array(resized_img).reshape((target_size[0], target_size[1], target_size[2]))
end = datetime.now()
seconds = (end-start).seconds
print('process cost {}s'.format(seconds)) #輸出計算時間
resized_show = Image.fromarray(resized_img.astype(np.uint8))
resized_show.save(r"./1.jpg") #保存目標圖像
plt.imshow(resized_show) #顯示目標圖像
plt.show()