双线性插值算法原理及其python实现

双线性插值算法的原理比较简单,就是这样一个需求,假如想知道一个坐标的数值,直接找到其4个周围的数值,利用这4个数值进行线性插值出目标位置的数值,比较简单的思路就是先对x方向进行插值,然后对y方向进行插值,就诞生了所谓的双线性插值,示例图如下:

 也就是使用P1/P2/P3/P4四个点插值出来P的数值

不管是先进行x坐标还是先进行y坐标都是OK的

具体来说,就是使用先计算出Px1和Px2的数值,然后再计算出来Py1和Py2,最终计算出来P的数值。具体公式化为如下:

Px1=(P4-P1)\ast ((x-x1)/(x2-x1))))+P2 \\ Px2=(P3-P2)\ast ((x-x1)/(x2-x1))))+P1 \\ P=(Px1-Px2)\ast ((y-y1)/(y2-y1))))+Px2

简单的使用python实现一下:

class Point:
    def __init__(self, x=None, y=None):
        self.x = x
        self.y = y


def bilinear_interpolation(x, y, points, values):
    px1 = (values[3]-values[0])*((x-points[1].x)/(points[2].x-points[1].x))+values[1]
    px2 = (values[2] - values[1]) * ((x - points[0].x) / (points[3].x - points[0].x)) + values[0]
    p = (px1-px2)*((y-points[0].y)/(points[1].y-points[0].y))+px2
    return p


if __name__ == '__main__':
    points = [Point(1, 2), Point(1, 4), Point(3, 4), Point(3, 2)]
    vs = [1, 2, 3, 4]
    print(bilinear_interpolation(x=2, y=3, points=points, values=vs))#2.5

经常我们都能看到使用OpenCV等工具进行resize尺寸,默认一般都是双线性插值,双线性插值是效率和精度的平衡,也就是耗时比较少效果也不错。下面我使用python简单的实现一下resize,这里所说的resize都是放大的resize,因为缩小尺寸根本用不到插值,只需要在原图进行采样即可,所以我这里说的resize是针对放大尺寸来说的。

import cv2
import numpy as np


class Point:
    def __init__(self, x=None, y=None):
        self.x = x
        self.y = y


def bilinear_interpolation(x, y, points, values):
    px1 = (values[3]-values[0])*((x-points[1].x)/(points[2].x-points[1].x))+values[1]
    px2 = (values[2] - values[1]) * ((x - points[0].x) / (points[3].x - points[0].x)) + values[0]
    p = (px1-px2)*((y-points[0].y)/(points[1].y-points[0].y))+px2
    return np.clip(p, 0, 255)


def resize(img, w_new, h_new):
    out_img = np.zeros((h_new, w_new, 3))
    h, w = img.shape[:2]
    source_w = [(i+0.5)*w/w_new-0.5 for i in range(w_new)]
    source_w_1 = [int(np.clip(np.floor(i), 0, w-2)) for i in source_w]
    source_h = [(i + 0.5) * h / h_new - 0.5 for i in range(h_new)]
    source_h_1 = [int(np.clip(np.floor(i), 0, h - 2)) for i in source_h]

    for i in range(0, h_new):
        for j in range(0, w_new):
            #寻找4个近邻点
            p1 = (source_h_1[i], source_w_1[j])
            p2 = (source_h_1[i]+1, source_w_1[j])
            p3 = (source_h_1[i]+1, source_w_1[j]+1)
            p4 = (source_h_1[i], source_w_1[j]+1)
            points = [Point(p1[1], p1[0]), Point(p2[1], p2[0]), Point(p3[1], p3[0]), Point(p4[1], p4[0])]
            vs_b = [img[p1[0], p1[1], 0], img[p2[0], p2[1], 0], img[p3[0], p3[1], 0], img[p4[0], p4[1], 0]]
            vs_g = [img[p1[0], p1[1], 1], img[p2[0], p2[1], 1], img[p3[0], p3[1], 1], img[p4[0], p4[1], 1]]
            vs_r = [img[p1[0], p1[1], 2], img[p2[0], p2[1], 2], img[p3[0], p3[1], 2], img[p4[0], p4[1], 2]]
            # print(source_w[j], source_h[i], i, j)
            out_img[i, j, 0] = bilinear_interpolation(x=source_w[j], y=source_h[i], points=points, values=vs_b)
            out_img[i, j, 1] = bilinear_interpolation(x=source_w[j], y=source_h[i], points=points, values=vs_g)
            out_img[i, j, 2] = bilinear_interpolation(x=source_w[j], y=source_h[i], points=points, values=vs_r)
    return out_img


if __name__ == '__main__':
    # points = [Point(1, 2), Point(1, 4), Point(3, 4), Point(3, 2)]
    # vs = [1, 2, 3, 4]
    # print(bilinear_interpolation(x=2, y=3, points=points, values=vs))#2.5
    img = cv2.imread('demo.jpg')
    h, w = img.shape[:2]
    img = cv2.resize(img, (w//4, h//4))
    res = resize(img.astype(np.float32), w//2, h//2).astype(np.uint8)
    cv2.imwrite('demo_resize.jpg', res)
    res_cv = cv2.resize(img, (w//2, h//2))
    cv2.imwrite('demo_resize_opencv.jpg', res_cv)

运行结果如下:

 

不过需要注意的是,python这样运行分辨率较大时会很慢,可以考虑使用numpy的矩阵运算的方式进行运行或者修改成一些加速库,这里只是展示一些原理学习,并不能直接使用在工程项目里面。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
双线性插值算法是一种常用的图像缩放算法,它可以将一幅图像按照比例放大或缩小。在Python中,可以使用NumPy和PIL库实现双线性插值算法。具体步骤如下: 1.读取原始图像,并计算出目标图像的大小。 2.根据原始图像和目标图像的大小,计算出在目标图像中每个像素点对应的坐标在原始图像中的位置。 3.对于每个目标图像中的像素点,找到其周围4个像素点(左上、右上、左下、右下),并计算出其在原始图像中的值。 4.根据周围4个像素点的值和目标像素点在原始图像中的位置,使用双线性插值公式计算出目标像素点的值。 5.将计算出来的目标像素点值赋给目标图像相应位置的像素点。 下面是一个Python代码示例,实现双线性插值算法: ```python import numpy as np from PIL import Image def bilinear_interpolation(img, new_size): """ 双线性插值算法实现 :param img: 原始图像 :param new_size: 目标图像大小,格式为(w, h) :return: 目标图像 """ w, h = new_size src_h, src_w, channel = img.shape # 计算目标图像中每个像素点在原始图像中的位置 fx = float(src_w) / float(w) fy = float(src_h) / float(h) x, y = np.meshgrid(np.arange(w), np.arange(h)) x = x * fx y = y * fy # 找到周围4个像素点,并计算出其在原始图像中的值 x1 = np.floor(x).astype(int) x2 = x1 + 1 y1 = np.floor(y).astype(int) y2 = y1 + 1 x1 = np.clip(x1, 0, src_w - 1) x2 = np.clip(x2, 0, src_w - 1) y1 = np.clip(y1, 0, src_h - 1) y2 = np.clip(y2, 0, src_h - 1) Ia = img[y1, x1] Ib = img[y2, x1] Ic = img[y1, x2] Id = img[y2, x2] # 计算双线性插值公式 wa = (x2 - x) * (y2 - y) wb = (x2 - x) * (y - y1) wc = (x - x1) * (y2 - y) wd = (x - x1) * (y - y1) dst_img = wa[:, :, np.newaxis] * Ia + wb[:, :, np.newaxis] * Ib + wc[:, :, np.newaxis] * Ic + wd[:, :, np.newaxis] * Id return dst_img.astype(np.uint8) # 读取原始图像 img = np.array(Image.open('test.jpg')) # 调用双线性插值算法进行图像缩放 new_size = (img.shape // 2, img.shape // 2) dst_img = bilinear_interpolation(img, new_size) # 将目标图像保存为文件 Image.fromarray(dst_img).save('result.jpg') ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值