[图像处理]双线性插值法及python实现

双线性插值法及python实现

插值法是一种根据原图(source)图片信息构造目标图像(destination)的方法。而其中的双线性插值法是一种目前使用较多的插值方法,他在效果和计算量之间有较好的权衡,所以使用较为广泛。

最近邻插值法

给定一个矩阵(图片本身就是一种矩阵),将1个 3 ∗ 3 3*3 33尺寸的矩阵使用最近邻插值法到 4 ∗ 4 4*4 44

[ 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]=(1a)(1b)src[x+1,y+1]+(1a)bsrc[x+1,y]+(1b)asrc[x,y+1]+absrc[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]=(10)(10.75)src[1][1]+(10)0.75src[1][0]+0(10.75)src[0][1]+00.75src[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)

参考

  1. https://blog.csdn.net/xiaqunfeng123/article/details/17362881
  2. https://zhuanlan.zhihu.com/p/22882367

你可能感兴趣的:(图像处理)