假设我们已知坐标(x0,y0)与(x1,y1),要得到[x0,x1]区间内某一位置x在直线上的值。根据图中所示可得:
通过斜率比,可以得到下面的等式。
如图所示:所谓双线性插值,也就是连续使用三次一维线性插值,最终求得g(u0,v0)。
第一次:由g(u’,v’)和g(u’+1,v’)一维线性插值求g(u0,v’).
第二次:由g(u’,v’+1)和g(u’+1,v’+1)一维线性插值求g(u0,v’+1).
第三次:由g(u0,v’)和g(u0,v’+1)一维线性插值求g(u0,v0).
我们只需要做两件事:
f(x,y)表示输出图像,g(u,v)表示输入图像。图像放大或缩小的几何运算可定义为: f ( x , y ) = g ( u 0 , v 0 ) = g [ a ( x , y ) , b ( x , y ) ] f(x,y)=g(u_0,v_0)=g[a(x,y),b(x,y)] f(x,y)=g(u0,v0)=g[a(x,y),b(x,y)].如果令 u 0 = a ( x , y ) = x c , v 0 = b ( x , y ) = y d u_0=a(x,y)=\frac{x}{c},v_0=b(x,y)=\frac{y}{d} u0=a(x,y)=cx,v0=b(x,y)=dy.我们知道 u 0 , v 0 u_0,v_0 u0,v0的坐标其实就是原图x轴方向放大c倍,y轴方向放大d被。
举个例子,将一副200×200的图像 g ( u , v ) g(u,v) g(u,v)放大1.5倍,那么将得到300×300的新图像 f ( x , y ) f(x,y) f(x,y)。产生新图像的过程,实际就是为300×300的像素赋值的过程。
假如为 f ( 150 , 150 ) f(150,150) f(150,150)赋值:
f ( 150 , 150 ) = g ( 150 / 1.5 , 150 / 1.5 ) = g ( 100 , 100 ) ; f(150,150)=g(150/1.5,150/1.5)=g(100,100); f(150,150)=g(150/1.5,150/1.5)=g(100,100);
假如为f(100,100)赋值:
f ( 100 , 100 ) = g ( 100 / 1.5 , 100 / 1.5 ) = g ( 66.7 , 66.7 ) . f(100,100)=g(100/1.5,100/1.5)=g(66.7,66.7). f(100,100)=g(100/1.5,100/1.5)=g(66.7,66.7).
对于 g ( 100 , 100 ) g(100,100) g(100,100),坐标值为整数,可直接赋值。而对于 g ( 66.7 , 66.7 ) g(66.7,66.7) g(66.7,66.7),坐标值为小数,也即 ( u 0 , v 0 ) (u_0,v_0) (u0,v0)不一定在坐标点上,这种情况就需要用到前言中所提到的双线性插值。 f ( 100 , 100 ) = g ( 66.7 , 66.7 ) = ( 0.3 ∗ 0.3 ) g ( 66 , 66 ) + ( 0.3 ∗ 0.7 ) g ( 66 , 67 ) + ( 0.3 ∗ 0.7 ) g ( 67 , 66 ) + ( 0.7 ∗ 0.7 ) g ( 67 , 67 ) f(100,100)=g(66.7,66.7)=(0.3*0.3)g(66,66)+(0.3*0.7)g(66,67)+(0.3*0.7)g(67,66)+(0.7*0.7)g(67,67) f(100,100)=g(66.7,66.7)=(0.3∗0.3)g(66,66)+(0.3∗0.7)g(66,67)+(0.3∗0.7)g(67,66)+(0.7∗0.7)g(67,67)
# --*-- encoding: utf-8 --*--
'''
Date: 2018.09.13
Content: python3 实现双线性插值图像缩放算法
'''
import numpy as np
import cv2
import math
def bi_linear(src, dst, target_size):
pic = cv2.imread(src) # 读取输入图像
th, tw = target_size[0], target_size[1]
emptyImage = np.zeros(target_size, np.uint8)
for k in range(3):
for i in range(th):
for j in range(tw):
# 首先找到在原图中对应的点的(X, Y)坐标
corr_x = (i+0.5)/th*pic.shape[0]-0.5
corr_y = (j+0.5)/tw*pic.shape[1]-0.5
# if i*pic.shape[0]%th==0 and j*pic.shape[1]%tw==0: # 对应的点正好是一个像素点,直接拷贝
# emptyImage[i, j, k] = pic[int(corr_x), int(corr_y), k]
point1 = (math.floor(corr_x), math.floor(corr_y)) # 左上角的点
point2 = (point1[0], point1[1]+1)
point3 = (point1[0]+1, point1[1])
point4 = (point1[0]+1, point1[1]+1)
fr1 = (point2[1]-corr_y)*pic[point1[0], point1[1], k] + (corr_y-point1[1])*pic[point2[0], point2[1], k]
fr2 = (point2[1]-corr_y)*pic[point3[0], point3[1], k] + (corr_y-point1[1])*pic[point4[0], point4[1], k]
emptyImage[i, j, k] = (point3[0]-corr_x)*fr1 + (corr_x-point1[0])*fr2
cv2.imwrite(dst, emptyImage)
# 用 CV2 resize函数得到的缩放图像
new_img = cv2.resize(pic, (200, 300))
cv2.imwrite('pic/1_cv_img.png', new_img)
def main():
src = 'pic/raw_1.jpg'
dst = 'pic/new_1.png'
target_size = (300, 200, 3) # 变换后的图像大小
bi_linear(src, dst, target_size)
if __name__ == '__main__':
main()