插值法是一种根据原图(source)图片信息构造目标图像(destination)的方法。而其中的双线性插值法是一种目前使用较多的插值方法,他在效果和计算量之间有较好的权衡,所以使用较为广泛。
给定一个矩阵(图片本身就是一种矩阵),将1个 3 ∗ 3 3*3 3∗3尺寸的矩阵使用最近邻插值法到 4 ∗ 4 4*4 4∗4
[ 234 38 22 67 44 12 89 65 63 ] ⟹ [ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ] \left[ \begin{matrix} 234 & 38 & 22 \\ 67 & 44 & 12 \\ 89 & 65 & 63 \\ \end{matrix} \right] \Longrightarrow \left[ \begin{matrix} ? & ? & ? & ? \\ ? & ? & ? & ? \\ ? & ? & ? & ? \\ ? & ? & ? & ? \\ \end{matrix} \right] ⎣⎡2346789384465221263⎦⎤⟹⎣⎢⎢⎡????????????????⎦⎥⎥⎤
对于des中的[0, 0],该坐标对应的src中坐标可由下公式得出:
src_x = dst_x * (src_width/dst_width)
src_y = dst_y * (src_heght/dst_height)
dst[0][0]对应的src位置如下:
src_x = 0 * (3 / 4) = 0
src_y = 0 * (3 / 4) = 0
所以dst[0][0] = src[src_x][src_y] = src[0][0] = 234
dst[0][1]对应的src位置如下:
src_x = 0 * (3 / 4) = 0
src_y = 1 * (3 / 4) = 0.75
所以dst[0][0] = src[src_x][src_y] = src[0][0.75]
由于图片像素最小单位是1,所以四舍五入dst[0][1] = src[0][1] = 38
根据以上公式最终结果如下:
[ 234 38 22 22 67 44 12 12 89 65 63 63 89 65 63 63 ] \left[ \begin{matrix} 234 & 38 & 22 & 22 \\ 67 & 44 & 12 & 12 \\ 89 & 65 & 63 & 63 \\ 89 & 65 & 63 & 63 \\ \end{matrix} \right] ⎣⎢⎢⎡234678989384465652212636322126363⎦⎥⎥⎤
缺点:放大后有马赛克,缩小后有严重失真。
在双线性插值中,我们考虑到dst图像中某个像素点对应回src图像中是在几个像素点之间。例如dst某个像素点对应回src中的坐标为(x, y),x, y如果不是整数的话,那么相关的像素点就有四个,(x, y), (x+1, y), (x+1, y+1), (x, y+1)。
具体公式如下:
d s t [ x , y ] = s r c [ x ′ , y ′ ] = ( 1 − a ) ( 1 − b ) s r c [ x ′ + 1 , y ′ + 1 ] + ( 1 − a ) b ∗ s r c [ x ′ + 1 , y ′ ] + ( 1 − b ) a ∗ s r c [ x ′ , y ′ + 1 ] + a b ∗ s r c [ x ′ ] [ y ′ ] dst[x, y] = src[x', y'] = (1-a)(1-b)src[x'+1, y'+1]+(1-a)b*src[x'+1,y'] + (1-b)a*src[x',y'+1]+ab*src[x'][y'] dst[x,y]=src[x′,y′]=(1−a)(1−b)src[x′+1,y′+1]+(1−a)b∗src[x′+1,y′]+(1−b)a∗src[x′,y′+1]+ab∗src[x′][y′]
PS:x’, y’是对最近邻插值得到的值取整,a为对于src_x的余数, b为src_y的余数。
[ 234 38 22 67 44 12 89 65 63 ] ⟹ [ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ] \left[ \begin{matrix} 234 & 38 & 22 \\ 67 & 44 & 12 \\ 89 & 65 & 63 \\ \end{matrix} \right] \Longrightarrow \left[ \begin{matrix} ? & ? & ? & ? \\ ? & ? & ? & ? \\ ? & ? & ? & ? \\ ? & ? & ? & ? \\ \end{matrix} \right] ⎣⎡2346789384465221263⎦⎤⟹⎣⎢⎢⎡????????????????⎦⎥⎥⎤
dst[0][1]对应的src位置如下:
src_x = 0 * (3 / 4) = 0
src_y = 1 * (3 / 4) = 0.75
a= 0, b = 0.75
d s t [ 0 ] [ 1 ] = ( 1 − 0 ) ( 1 − 0.75 ) ∗ s r c [ 1 ] [ 1 ] + ( 1 − 0 ) ∗ 0.75 ∗ s r c [ 1 ] [ 0 ] + 0 ∗ ( 1 − 0.75 ) ∗ s r c [ 0 ] [ 1 ] + 0 ∗ 0.75 ∗ s r c [ 0 ] [ 0 ] dst[0][1] = (1-0)(1-0.75)*src[1][1] + (1-0)*0.75*src[1][0] + 0*(1-0.75)*src[0][1] + 0 *0.75*src[0][0] dst[0][1]=(1−0)(1−0.75)∗src[1][1]+(1−0)∗0.75∗src[1][0]+0∗(1−0.75)∗src[0][1]+0∗0.75∗src[0][0]
= 11 + 50 = 61 =11+50=61 =11+50=61
import numpy as np
import cv2
def bilinear(org_img, org_shape, dst_shape):
print(org_shape)
dst_img = np.zeros((dst_shape[0], dst_shape[1], 3))
dst_h, dst_w = dst_shape
org_h, org_w = org_shape
for i in range(dst_h):
for j in range(dst_w):
src_x = j * float(org_w / dst_w)
src_y = i * float(org_h / dst_h)
src_x_int = j * org_w // dst_w
src_y_int = i * org_h // dst_h
a = src_x - src_x_int
b = src_y - src_y_int
if src_x_int+1 == org_w or src_y_int+1 == org_h:
dst_img[i, j, :] = org_img[src_y_int, src_x_int, :]
continue
# print(src_x_int, src_y_int)
dst_img[i, j, :] = (1. - a) * (1. - b) * org_img[src_y_int+1, src_x_int+1, :] + \
(1. - a) * b * org_img[src_y_int, src_x_int+1, :] + \
a * (1. - b) * org_img[src_y_int+1, src_x_int, :] + \
a * b * org_img[src_y_int, src_x_int, :]
return dst_img
if __name__ == '__main__':
img_path = './428_487626.jpg'
img = cv2.imread(img_path, cv2.IMREAD_COLOR)
img_shape = (img.shape[0], img.shape[1])
dst_shape = (2*img_shape[0], 2*img_shape[1])
dst_img = bilinear(img, img_shape, dst_shape)
cv2.imwrite('./428_487626_bilinear.jpg', dst_img)