双线性插值的理解与python实现

介绍

双线性插值是图像缩放的一种方式,其主要分为两步线性插值,一是在x方向插值,二是用x方向插值结果再在y方向插值,具体步骤如下:

1.定位像素点

先找到目标图像像素点(dst_x, dst_y)在源图像上的像素点位置(src_x, src_y)。
一般是使用直接缩放:
src_x=dst_x * scale_x (scale_x为源图像与目标图像宽比例)
而我们这里使用几何中心对称:
src_x = (dst_x + 0.5) * scale_x - 0.5
然后找到上下左右最近邻的四个像素点用于计算插值。

2.两步插值

(x,y) ( x , y ) 为插值点在源图像的坐标,待计算插值为 z z
首先x方向上插值:相邻两点为 (x0,y0) ( x 0 , y 0 ) (x1,y0) ( x 1 , y 0 ) ,像素值分别为 z0=f(x0,y0) z 0 = f ( x 0 , y 0 ) z1=f(x1,y0) z 1 = f ( x 1 , y 0 ) ,从而有公式: zz0xx0=z1z0x1x0 z − z 0 x − x 0 = z 1 − z 0 x 1 − x 0 ,从而插值 z=x1xx1x0z0+xx0x1x0z1 z = x 1 − x x 1 − x 0 z 0 + x − x 0 x 1 − x 0 z 1

然后y方向上插值:以上得到的上方插值 z z 记为 ztop z t o p ,同理可得下方插值为 zbot z b o t ,那么最后插值为: Z=y1yy1y0ztop+yy0y1y0zbot Z = y 1 − y y 1 − y 0 z t o p + y − y 0 y 1 − y 0 z b o t

python实现

# coding=utf-8
import cv2
import numpy as np
import time

def resize(src, new_size):
    dst_w, dst_h = new_size # 目标图像宽高
    src_h, src_w = src.shape[:2] # 源图像宽高
    if src_h == dst_h and src_w == dst_w:
        return src.copy()
    scale_x = float(src_w) / dst_w # x缩放比例
    scale_y = float(src_h) / dst_h # y缩放比例

    # 遍历目标图像,插值
    dst = np.zeros((dst_h, dst_w, 3), dtype=np.uint8)
    for n in range(3): # 对channel循环
        for dst_y in range(dst_h): # 对height循环
            for dst_x in range(dst_w): # 对width循环
                # 目标在源上的坐标
                src_x = (dst_x + 0.5) * scale_x - 0.5
                src_y = (dst_y + 0.5) * scale_y - 0.5
                # 计算在源图上四个近邻点的位置
                src_x_0 = int(np.floor(src_x))
                src_y_0 = int(np.floor(src_y))
                src_x_1 = min(src_x_0 + 1, src_w - 1)
                src_y_1 = min(src_y_0 + 1, src_h - 1)

                # 双线性插值
                value0 = (src_x_1 - src_x) * src[src_y_0, src_x_0, n] + (src_x - src_x_0) * src[src_y_0, src_x_1, n]
                value1 = (src_x_1 - src_x) * src[src_y_1, src_x_0, n] + (src_x - src_x_0) * src[src_y_1, src_x_1, n]
                dst[dst_y, dst_x, n] = int((src_y_1 - src_y) * value0 + (src_y - src_y_0) * value1)
    return dst

if __name__ == '__main__':
    img_in = cv2.imread('./JPEGImages/000001.jpg')
    start = time.time()
    img_out = cv2.resize(img_in, (600,600))
    print 'cost %f seconds' % (time.time() - start)

    cv2.imshow('src_image', img_in)
    cv2.imshow('dst_image', img_out)
    cv2.waitKey()

总结

由于实现插值是通过遍历像素点,是串行方式且在cpu上运行,因此比较耗时,复杂度和输出图片尺寸有关,实测512*512图像耗时为3s左右,而opencv中的cv2.resize()函数速度很快,具体实现需进一步了解。

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