双线性插值代码讲解(bilinear_interpolation)

    这几天再看STN网络,即空间变换网络,里面设计到双线性插值。算法虽老,但是并没有去看过,只是简单使用opencv调用过。闲来无事,就使用numpy库实现下整个流程。我认为只有代码才能让我清楚了解里面的每一步,现在对整个代码进行注释分析,方便大家理解双线性插值算法。大家可以查看这篇文章:https://blog.csdn.net/sinat_33718563/article/details/78825971。图像空间坐标变化公式如下:

    a表示图像坐标选择缩放等等仿射参数,t参数表示图像偏移信息量。有了这个(2,3)的仿射矩阵,就可以得到图像的空间变化坐标信息。

    双线性插值,就是已知Q12,22,21,11的坐标的像素值,去求p点的像素值。其中公式如下:

    因为我们是在挑选边长为1的正方形的四个角的像素值,所以(x2-x1)(y2-y1)的值为1,故公式可以简化。具体代码可以看下面的注释,如有不太明白,请留言反馈。

#coding:utf-8
import numpy as np
import cv2
#######该函数建立目标图像的像素网格,网格大小为图像高×宽,取值范围为-1,1.返回值为形状为(3,h*w)的numpy矩阵
#######[0,:]为x轴网格点   [1,:]为y轴网格点    [2,:]为1  为了进行矩阵相乘,相当与偏置
def regular_grids(img_h,img_w):
    x_linspace = np.linspace(-1,1,img_w)
    y_linspace = np.linspace(-1,1,img_h)
    x_coord,y_coord = np.meshgrid(x_linspace,y_linspace)
    x_coord = x_coord.flatten()
    y_coord = y_coord.flatten()
    ones = np.ones_like(x_coord)
    x_y_grid = np.concatenate([x_coord,y_coord,ones],axis=0)
    return np.reshape(x_y_grid,(3,img_h*img_w))
########输入参数:原图,变化后的坐标(x,y),输出图片的尺寸
def interpolation(img,sample_grid,output_size):

    height,width,num_channels = img.shape
    x = sample_grid[0,:].astype(np.float32) ####sample_grid分别保存了输出图片的网格dot仿射矩阵后的新坐标(x,y)
    y = sample_grid[1,:].astype(np.float32)
    x = 0.5 *(x+1.0)*float(width)  ####网格初始取值范围(-1,1)  +1乘以w除以0.5 变化到对应原始图片坐标
    y = 0.5 *(y+1.0)*float(height)
    x_0 = x.astype(np.int32)   ####向下取整   x_0,x_1,y_0,y_1分别代表左上和右下坐标点
    x_1 = x_0+1               #####加1
    y_0 = y.astype(np.int32)
    y_1 = y_0+1
    max_x = width-1
    max_y = height-1
    ##########进行剪裁,防止(x,y)索引超过原始图片的宽高
    x_0 = np.clip(x_0,0,max_x)
    x_1 = np.clip(x_1,0,max_x)
    y_0 = np.clip(y_0,0,max_y)
    y_1 = np.clip(y_1,0,max_y)
    #########建立索引矩阵,用于挑选原始图像中的像素值 大小为输出图像的宽×高
    base = np.zeros(shape=(output_size[0],output_size[1]),dtype='int32').flatten()

    base_y0 = base+(y_0*width) ######找到y_0,y_1在原始矩阵中的索引   因为y代表图像第y行 所以需要乘以原始图片的宽,
    base_y1 = base+(y_1*width)
    #######加上x轴坐标,找到原始图片的具体像素值索引位置
    indices_a = base_y0+x_0  ###左上像素索引位置
    indices_b = base_y1+x_0  ###左下像素索引位置
    indices_c = base_y0+x_1  ###右上
    indices_d = base_y1+x_1  ###右下
    ########挑选出对应索引位置的像素信息值
    img_flatten = np.reshape(img,newshape=(-1,num_channels))
    pixel_values_a = img_flatten[indices_a,:]
    pixel_values_b = img_flatten[indices_b,:]
    pixel_values_c = img_flatten[indices_c,:]
    pixel_values_d = img_flatten[indices_d,:]
    #####转换为float型进行计算
    x_0 = x_0.astype(np.float32)
    x_1 = x_1.astype(np.float32)
    y_0 = y_0.astype(np.float32)
    y_1 = y_1.astype(np.float32)
    #####计算各个区域的值,area_a+area_b+area_c+area_d 的值非0即1
    area_a = np.expand_dims(((x_1 - x) * (y_1 - y)), 1)  ###单位面积1的方格中,右下部分面积
    area_b = np.expand_dims(((x_1 - x) * (y - y_0)), 1)  ####右上面积
    area_c = np.expand_dims(((x - x_0) * (y_1 - y)), 1)  ####左下面积
    area_d = np.expand_dims(((x - x_0) * (y - y_0)), 1)  ####左上面积
    values_a = area_a * pixel_values_a  ### 右下面积乘以左上像素值
    values_b = area_b * pixel_values_b  ### 右上面积乘以左下像素值
    values_c = area_c * pixel_values_c  ### 左下面积乘以右上像素值
    values_d = area_d * pixel_values_d  ### 左上面积乘以右下像素值
    ###相加就是实际插入像素值
    return values_a + values_b + values_c + values_d
def transform(img,affine_matrix,output_size):
    num_channels = img.shape[2]
    ###affine_matrix.shape = (2,3)
    regular_grid = regular_grids(*output_size)
    sample_grid = np.dot(affine_matrix,regular_grid)
    final_img = interpolation(img,sample_grid,output_size)
    final_img = final_img.astype(np.uint8)
    final_img = np.reshape(final_img,(output_size[0],output_size[1],num_channels))
    return final_img
if __name__ == '__main__':
    affine_matrix = np.array([[1.5,0,0],[0,1.5,0]])
    img = cv2.imread('./test.jpg',1)
    final =transform(img,affine_matrix,output_size=(500,500))
    # cv2.imshow('img',final)
    # cv2.waitKey()

test图片,该图片是用于字符定位的素材,平常也做一些该方面的实验。

 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Bilinear interpolation双线性插值)是一种用于在离散数据点之间进行插值的方法。它通过在两个方向上进行线性插值来估计未知点的值。这种插值方法常用于图像处理和计算机图形学中。 双线性插值的原理是基于两个相邻的数据点之间的线性插值。首先,根据给定的坐标找到四个最近的数据点,然后在水平和垂直方向上进行线性插值,以获得未知点的值。 以下是一个使用双线性插值的示例代码[^1]: ```python import numpy as np def bilinear_interpolation(x, y, points): x1, y1 = points[0] x2, y2 = points[1] q11 = points[2] q12 = points[3] q21 = points[4] q22 = points[5] f = 1 / ((x2 - x1) * (y2 - y1)) value = f * ( q11 * (x2 - x) * (y2 - y) + q21 * (x - x1) * (y2 - y) + q12 * (x2 - x) * (y - y1) + q22 * (x - x1) * (y - y1) ) return value # 示例数据点 points = np.array([ [0, 0, 1, 3, 2, 4], [0, 1, 6, 8, 7, 9] ]) # 插值点坐标 x = 0.5 y = 0.5 # 进行双线性插值 result = bilinear_interpolation(x, y, points) print("Interpolated value:", result) ``` 这段代码中,我们定义了一个`bilinear_interpolation`函数,它接受插值点的坐标和四个最近的数据点的值作为输入。然后,根据双线性插值的公式计算出插值点的值,并返回结果。 在上面的示例中,我们使用了一个简单的二维数组作为示例数据点,然后对坐标为(0.5, 0.5)的点进行双线性插值。最后,输出插值点的值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值