线性插值二:双线性插值

一张图像,如果要放大缩小,特别是放大如何才能不让图片保留更多原图片的性质,更加清晰呢?大部分的处理方式都是线性插值,本文介绍的便是线性插值中最常用的方式之一 – 双线性插值。

理解双线性插值之前,先了解一下最简单的单线插值。

单线性插值

点(x,y)是点( x 0 x_0 x0 y 0 y_0 y0)和点( x 1 x_1 x1 y 1 y_1 y1)之间的一个点,如果下图左边的图形,如果x已知,如何求得y的左边,只需要通过初中的知识线段之间的比例关系便能轻松求解,如右图所示。
线性插值二:双线性插值_第1张图片
最终求得 y = x 1 − x x 1 − x 0 . y 0 + x − x 0 x 1 − x 0 . y 1 y = \frac{x_1 - x}{x_1 - x_0}.y_0 + \frac{x - x_0}{x_1 - x_0}.y_1 y=x1x0x1x.y0+x1x0xx0.y1

双线插值

双线插值和单线插值逻辑接近,只不过是图片平面是二维的,自然坐标也应该是二维的,和一条直线不同的地方是一个点应该由两条直线决定。

如下图,P点便是要插值的点,要求解P点的y左边,则需要求解 R 1 和 R 2 R_1和R_2 R1R2的坐标,所以需要先对 R 1 R_1 R1 R 2 R_2 R2进行插值,然后 R 1 R_1 R1 R 2 R_2 R2进行插值,即先在x方向进行两次线性插值,再在y方向进行一次线性插值。

线性插值二:双线性插值_第2张图片
插值过程如下:
线性插值二:双线性插值_第3张图片
双线插值中, Q 11 、 Q 12 、 Q 21 、 Q 22 Q_{11}、Q_{12}、Q_{21}、Q_{22} Q11Q12Q21Q22是相邻的四个点,所以 x 2 − x 1 = 1 , y 2 − y 1 = 1 x_2-x_1=1,y_2-y_1=1 x2x1=1,y2y1=1
目标图像和原图像之间的关系:
D x = S x ∗ D w S w               D y = S y ∗ D h S h D_x = S_x * \frac{D_w}{S_w} ~~~~~~~~~~~~~D_y = S_y * \frac{D_h}{S_h} Dx=SxSwDw             Dy=SyShDh
∴ S x = D x ∗ S w D w               S y = D y ∗ S h D h \therefore S_x = D_x * \frac{S_w} {D_w}~~~~~~~~~~~~~S_y = D_y * \frac{S_h} {D_h} Sx=DxDwSw             Sy=DyDhSh

但是当前存在一个问题,如果目标图像和原图像的原点均选择左上角或者左下角作为对应重合,整个图像便不会均匀的对应,所以应该选择几何中心作为重合点。

几何中心推导:
设原图像为 M ∗ M M*M MM,目标图像 N ∗ N N*N NN,目标图像在原图像坐标系位置 ( x , y ) (x,y) (x,y),原图像坐标 ( x m , y m ) (x_m, y_m) (xm,ym),几何中心 ( x M − 1 2 , y M − 1 2 ) , (x_{\frac{M-1}{2}},y_{\frac{M-1}{2}}), (x2M1,y2M1),目标图像坐标 ( x n , y n ) (x_n, y_n) (xn,yn)

x = n M N x = n\frac{M}{N} x=nNM
几何中心相同 → M − 1 2 + Z = ( N − 1 2 + Z ) ∗ M N → Z ∗ ( 1 − M N ) = N − 1 2 N ∗ M − M − 1 2 N ∗ N → Z ∗ N − M N = N − M 2 N → Z = 1 2 \rarr \frac{M-1}{2} + Z = (\frac{N-1}{2} + Z) * \frac{M}{N} \\ \rarr Z*(1-\frac{M}{N}) = \frac{N-1}{2N}*M -\frac{M-1}{2N}*N \\ \rarr Z*\frac{N-M}{N} = \frac{N-M}{2N} \rarr Z = \frac{1}{2} 2M1+Z=(2N1+Z)NMZ(1NM)=2NN1M2NM1NZNNM=2NNMZ=21
∴ Z = 1 2 \therefore Z= \frac{1}{2} Z=21时,原图像和目标图像的几何中心重合。
∴ S x = ( D x + 0.5 ) ∗ S w D w − 0.5               S y = ( D y + 0.5 ) ∗ S h D h − 0.5 \therefore S_x = (D_x + 0.5) * \frac{S_w} {D_w} -0.5 ~~~~~~~~~~~~~ S_y = (D_y + 0.5) * \frac{S_h} {D_h} -0.5 Sx=(Dx+0.5)DwSw0.5             Sy=(Dy+0.5)DhSh0.5

双线插值代入,四个点坐标的处理:

Q 11 ( f l o o r ( S x ) , f l o o r ( S y ) ) … … ( x 1 , y 1 ) Q 12 ( f l o o r ( S x ) , c e i l ( S y ) ) … … ( x 1 , y 2 ) Q 21 ( f l o o r ( S x + 1 ) , f l o o r ( S y ) ) … … ( x 2 , y 1 ) Q 22 ( f l o o r ( S x + 1 ) , c e i l ( S y ) ) … … ( x 2 , y 2 ) \begin{array}{l} Q_{11} (floor(S_x), floor(S_y))……(x_1,y_1)\\ Q_{12} (floor(S_x),ceil(S_y))……(x_1,y_2)\\ Q_{21} (floor(S_x+1),floor(S_y))……(x_2,y_1)\\ Q_{22} (floor(S_x+1),ceil(S_y))……(x_2,y_2)\\ \end{array} Q11(floor(Sx),floor(Sy))……(x1,y1)Q12(floor(Sx),ceil(Sy))……(x1,y2)Q21(floor(Sx+1),floor(Sy))……(x2,y1)Q22(floor(Sx+1),ceil(Sy))……(x2,y2)

f ( x , y ) = ( x 2 − x ) f ( Q 11 ) + ( y − y 1 ) ( x 2 − x ) f ( Q 12 ) + ( x − x 1 ) f ( Q 22 ) f(x,y)=(x_2-x)f(Q_{11}) + (y-y_1)(x_2-x)f(Q_{12})+(x-x_1)f(Q_{22}) f(x,y)=(x2x)f(Q11)+(yy1)(x2x)f(Q12)+(xx1)f(Q22)

双线性插值手写代码

def bilinear_interpolation(source_image, shape):
    src_h, src_w, channel = source_image.shape  # 原图片的高、宽、通道数
    dst_h, dst_w = shape[1], shape[0]  # 输出图片的高、宽
    if src_h == dst_h and src_w == dst_w:
        return source_image
    dst_image = np.zeros((dst_h, dst_w, 3), dtype=np.uint8)
    scale_x, scale_y = float(src_w) / dst_w, float(src_h) / dst_h
    for i in range(channel):
        for dst_y in range(dst_h):
            for dst_x in range(dst_w):
                # 源图像和目标图像几何中心的对齐
                src_x = (dst_x + 0.5) * scale_x - 0.5
                src_y = (dst_y + 0.5) * scale_y - 0.5
                # 计算在源图上四个近邻点的位置
                src_x0 = int(np.floor(src_x))
                src_y0 = int(np.floor(src_y))
                src_x1 = min(src_x0 + 1, src_w - 1)
                src_y1 = min(src_y0 + 1, src_h - 1)

                # 双线性插值
                temp0 = (src_x1 - src_x) * source_image[src_y0, src_x0, i] + (src_x - src_x0) * source_image[
                    src_y0, src_x1, i]
                temp1 = (src_x1 - src_x) * source_image[src_y1, src_x0, i] + (src_x - src_x0) * source_image[
                    src_y1, src_x1, i]
                dst_image[dst_y, dst_x, i] = int((src_y1 - src_y) * temp0 + (src_y - src_y0) * temp1)

    return dst_image

双线性插值opencv代码

cv2.resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)
当参数interpolation=INTER_LINEAR(默认)时便是双线性插值。

双线性插值法计算量比最邻近插值法复杂很多,但避免了灰度不连续的缺点,图像更光滑。

你可能感兴趣的:(计算机视觉,人工智能)