双线性差值(2)—双线性差值

143 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情

之前介绍了在 1维数组上,通过调整数组大小的做法有点类似,双线性调整 2 维数组主要用到双线性差值方法。那么所谓双线性插值是可以将转为线性差值的问题,假设我们有 A,B,C 和 D 这 4 个点,对应的坐标分别为 (y1,x1)(y_1,x_1)(y1,x2)(y_1,x_2)(y2,x1)(y_2,x_1)(y2,x2)(y_2,x_2)。如下图,问题是我们要根据给出 A、B、C 和 D 点值来求出 Z 的值,其实这里前提是我们认为 Z 的值是由 A、B、C 和 D 值大小,以及他们与 Z 点空间位置相关的。首先我们先 X 和 Y 位置的值。然后在宽度这个维度上我们计算 X 和 Y 值,然后在 X 和 Y 相对于 Z 位置来计算 Z 的值。

bilinear_resize_002.png

根据上面的图,我们可以列出如下

X=A(1wx)+BwxY=C(1wx+DwxX = A(1 - w_{x})+ Bw_{x}\\ Y = C(1 - w_{x} + Dw_{x}
Z=X(1wy)+YwyZ=A(1wx)(1wy)+Bwx(1wy)+C(1wx)wy+Dwxwywx=xx1x2x1wy=yy1y2y1Z = X(1-w_{y}) + Yw_y\\ Z = A(1 - w_x)(1 - w_y) + Bw_x(1-w_y) + C(1-w_x)w_y + Dw_xw_y\\ w_x = \frac{x - x_1}{x_2 - x_1}\\ w_y = \frac{y - y_1}{y_2 - y_1}
ratio_y = (img_height - 1) / (height - 1)
ratio_x = (img_width - 1) / (width - 1)
import math

def bilinear_resize(image, height, width):
  """
  `image` is a 2-D numpy array
  `height` and `width` are the desired spatial dimension of the new 2-D array.
  """
  img_height, img_width = image.shape[:2]

  resized = np.empty([height, width])

  x_ratio = float(img_width - 1) / (width - 1) if width > 1 else 0
  y_ratio = float(img_height - 1) / (height - 1) if height > 1 else 0

  for i in range(height):
    for j in range(width):

      x_l, y_l = math.floor(x_ratio * j), math.floor(y_ratio * i)
      x_h, y_h = math.ceil(x_ratio * j), math.ceil(y_ratio * i)

      x_weight = (x_ratio * j) - x_l
      y_weight = (y_ratio * i) - y_l

      a = image[y_l, x_l]
      b = image[y_l, x_h]
      c = image[y_h, x_l]
      d = image[y_h, x_h]

      pixel = a * (1 - x_weight) * (1 - y_weight) \ 
              + b * x_weight * (1 - y_weight) + \
              c * y_weight * (1 - x_weight) + \
              d * x_weight * y_weight

      resized[i][j] = pixel
  return resized

其中 width 和 height 是新 2 维数组的行和列。假设想计算坐标[i, j] 处的点的内插值,其中0<=i<height0<=j<width。在原有 2 维数组中的映射坐标被计算为[y_ratio * i, x_ratio * j]。那么 [i, j] 周围最近的 4 个点的坐标是[y_l, x_l], [y_l, x_h], [y_h, x_l], [y_h, x_h]