Python实现最近邻nearest、双线性bilinear、双三次bicubic插值

介绍

关于最近邻nearest、双线性bilinear、双三次bicubic插值的原理,本文就不做具体的介绍了,已经有很多优秀的文章,比如:

强推:
https://blog.csdn.net/qq_39478403/article/details/105796249?spm=1001.2014.3001.5502

双线性bilinear插值:
https://www.cnblogs.com/wancy/p/15212604.html
https://blog.csdn.net/hxxjxw/article/details/118229375
https://zhuanlan.zhihu.com/p/463913651
https://blog.csdn.net/qq_28266311/article/details/86293713

双三次bicubic插值:
https://www.csdn.net/tags/NtzaIg3sMzY3NzYtYmxvZwO0O0OO0O0O.html
https://blog.csdn.net/wanghaoranand/article/details/107684548

非常感谢以上博客,本博客的代码也是参考了以上博客才得以完成
话不多说,直接码代码

最近邻nearest插值

def nearest(srcImg, dstH, dstW):
    srcH, srcW, _ = srcImg.shape
    # 将原图像的高度和宽度扩展一个像素
    # 目的是为了防止后面的计算出现数组越界的情况
    srcImg = np.pad(srcImg, ((0,1),(0,1),(0,0)), mode='reflect')
    # 创建目标图像
    dstImg = np.zeros((dstH, dstW, 3), dtype=np.uint8)
    # 遍历目标图像中的每个像素点
    for dstX in range(dstH):
        for dstY in range(dstW):
            # 寻找目标图像上的一个点对应在原图像上的位置 (x, y)
            # 注意这里的x和y不是一个整数
            x = dstX * (srcH / dstH)
            y = dstY * (srcW / dstW)
            # 将x和y进行向下取整,得到原图上对应的像素位置(scrX, srcY)
            scrX = int(x)
            srcY = int(y)
            # 计算目标像素与原图像上整数像素之间的距离
            u = x - scrX
            v = y - srcY
            # 根据距离来判断该选择周围四个像素中哪个像素
            if u > 0.5:
                scrX += 1
            if v > 0.5:
                srcY += 1
            # 选择原图像上距离最近的那个像素作为目标像素的值
            dstImg[dstX, dstY] = srcImg[scrX, srcY]
    return dstImg.astype(np.uint8)

双线性bilinear插值

def bilinear(srcImg, dstH, dstW):
    srcH, srcW, _ = srcImg.shape
    # 将原图像的高度和宽度扩展一个像素
    # 目的是为了防止后面的计算出现数组越界的情况
    srcImg = np.pad(srcImg, ((0,1),(0,1),(0,0)), mode='reflect')
    # 创建目标图像
    dstImg = np.zeros((dstH, dstW, 3), dtype=np.uint8)
    # 遍历目标图像中的每个像素点
    for dstX in range(dstH):
        for dstY in range(dstW):
            # 寻找目标图像上的一个点对应在原图像上的位置 (x, y)
            # 注意这里的x和y不是一个整数
            x = dstX * (srcH / dstH)
            y = dstY * (srcW / dstW)
            # 将x和y进行向下取整,得到原图上对应的像素位置(scrX, srcY)
            scrX = int(x)
            srcY = int(y)
            # 计算目标像素与原图像上整数像素之间的距离
            u = x - scrX
            v = y - srcY
            # 计算目标像素值,通过原图像四个整数像素的加权和
            dstImg[dstX, dstY] = (1-u) * (1-v) * srcImg[scrX,   srcY  ] + \
                                 u     * (1-v) * srcImg[scrX+1, srcY  ] + \
                                 (1-u) * v     * srcImg[scrX,   srcY+1] + \
                                 u     * v     * srcImg[scrX+1, srcY+1]
    return dstImg.astype(np.uint8)

双三次bicubic插值

参考的核函数:
在这里插入图片描述
图片来源于:https://www.csdn.net/tags/NtzaIg3sMzY3NzYtYmxvZwO0O0OO0O0O.html

def W(x):
    # a = -1
    x = abs(x)
    if x <= 1:
        return 1 - 2*(x**2) + (x**3)
    elif x < 2:
        return 4 - 8*x + 5*(x**2) - (x**3)
    else:
        return 0

def weighted_sum(srcImg, scrX, srcY, u, v):
    # 为了加速,使用矩阵乘法
    A = np.array([W(u+1), W(u), W(u-1), W(u-2)])
    # A: 1x4
    A = A[np.newaxis, :]
    C = np.array([W(v+1), W(v), W(v-1), W(v-2)])
    # C: 4x1
    C = C[:, np.newaxis]
    # 选取原图像中对应的16个像素
    # 本应该是srcImg[scrX-1:scrX+3, srcY-1:srcY+3]
    # 为了防止数组越界,前面已经原图像进行了pad操作,即前面pad一个像素,后面pad两个像素
    # 所以此时的scrX-1已经对应着原图像的scrX了
    B = srcImg[scrX:scrX+4, srcY:srcY+4]
    res = np.zeros(3, dtype=np.float32)
    for i in range(3):
        tmp = np.matmul(A, B[:,:,i])
        tmp = np.matmul(tmp, C)
        if tmp > 255: tmp = 255
        if tmp < 0: tmp = 0
        res[i] = tmp
    return res

def bicubic(srcImg, dstH, dstW):
    srcH, srcW, _ = srcImg.shape
    # 将原图像的高度和宽度扩展(1, 2)个像素
    # 目的是为了防止后面的计算出现数组越界的情况
    srcImg = np.pad(srcImg, ((1,2),(1,2),(0,0)), mode='reflect')
    # 创建目标图像
    dstImg = np.zeros((dstH, dstW, 3), dtype=np.uint8)
    # 遍历目标图像中的每个像素点
    for dstX in range(dstH):
        for dstY in range(dstW):
            # 寻找目标图像上的一个点对应在原图像上的位置 (x, y)
            # 注意这里的x和y不是一个整数
            x = dstX * (srcH / dstH)
            y = dstY * (srcW / dstW)
            # 将x和y进行向下取整,得到原图上对应的像素位置(scrX, srcY)
            scrX = int(x)
            srcY = int(y)
            # 计算目标像素与原图像上整数像素之间的距离
            u = x - scrX
            v = y - srcY
            # 计算目标像素值,通过原图像16个整数像素的加权和
            dstImg[dstX, dstY] = weighted_sum(srcImg, scrX, srcY, u, v)
    return dstImg.astype(np.uint8)

测试

img = np.asarray(Image.open('./images/lena.png'))
# 512 x 512

start = time.time()
# img = nearest(img, 1000, 1000)
# img = bilinear(img, 1000, 1000)
img = bicubic(img, 1000, 1000)
print('cost time:', time.time() - start)

Image.fromarray(img).save('./results/lena_bicubic.png')

测试时间结果:
最近邻nearest插值:0.9347765445709229 s
双线性bilinear插值:5.8758697509765625 s
双三次bicubic插值:24.310532808303833 s

原始图像:
在这里插入图片描述
最近邻nearest插值结果:
在这里插入图片描述
双线性bilinear插值结果:
在这里插入图片描述
双三次bicubic插值结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_33757398/article/details/124217610