从Nearest插值到Bilinear插值的分析与python实现

从Nearest插值到Bilinear插值的分析与python实现

这篇主要是想分析一下Nearest差值和Bilinear差值的计算细节,然后附上对应的Python实现代码,希望对你有帮助:https://github.com/LonglongaaaGo/ComputerVision

效果

先给出实现效果。
首先我们有一张小狗狗:
请添加图片描述

然后用Nearest 上采样,能够得到:
请添加图片描述
可以看到,有很多的锯齿,看起来不是很完美。
然后试试这个实现的Bilinear 上采样:
请添加图片描述
能够看到整体上柔和很多~虽然有点模糊,但是比Nearest好了很多。

正文

图像在计算机当中进行表示的话,是离散的,形式如下:
在这里插入图片描述
就是 x , y x,y x,y能够表示对应在图像中的坐标,而 F F F看成对应的函数。 F [ x , y ] F[x,y] F[x,y]表示的就是对应的像素信息。为了方便 讨论,就从1通道进行解释。
但是如果我们想做变换的话,如果直接用离散的点进行变换,肯定会丢失很多信息,所以我们就要考虑在连续的空间里进行变换。对应的,表现形式可以如下:
在这里插入图片描述
如果我们将 F [ 0 , 0 ] F[0,0] F[0,0]的中心点作为坐标 ( 0 , 0 ) (0,0) (0,0)的话,那么对应的左对角的点就是 ( − 0.5 , − 0.5 ) (-0.5,-0.5) (0.5,0.5)。这种做法比较常见,也是比较推荐的一种形式。接下来就是要对图像进行缩放,缩放的公式就是:
(srcX+0.5) ⁡ = ( d s t X + 0.5 ) ∗ ( s r c W i d t h / d s t W i d t h ) \operatorname{(srcX+0.5)}=\mathrm{(dstX+0.5)} *(\mathrm{srcWidth} / \mathrm{dstWidth}) (srcX+0.5)=(dstX+0.5)(srcWidth/dstWidth)
(srcY+0.5) ⁡ = ( d s t Y + 0.5 ) ∗ ( s r c H e i g h t / d s t H e i g h t ) \operatorname{(srcY+0.5)}=\mathrm{(dstY+0.5)} *(\mathrm{srcHeight} / \mathrm{dstHeight}) (srcY+0.5)=(dstY+0.5)(srcHeight/dstHeight)
这里定义
(srcX,srcY) ⁡ \operatorname{(srcX,srcY)} (srcX,srcY)就是对应的原始图像的坐标
(dstX,dstY) ⁡ \operatorname{(dstX,dstY)} (dstX,dstY)就是对应的缩放后的图像的坐标
s r c W i d t h , s r c H e i g h t \mathrm{srcWidth,srcHeight} srcWidth,srcHeight就是原始图像的宽和高
d s t W i d t h , d s t H e i g h t \mathrm{dstWidth,dstHeight} dstWidth,dstHeight就是缩放后的图像的宽和高

通过上述公式和定义,我们可以很快地计算出缩放后的图片和原图之间的关系。根据上面公式得到各个点的位置之后,就需要将连续点转化成离散的点。而Nearest差值和Bilinear差值方法的区别,也主要在这一步:
Nearest 插值方法就比较简单,就是直接四舍五入将连续地点变成离散的整数。这样的做法存在的问题上面也看到了,就是会产生明显的锯齿。如果还不明白的话,看一眼代码会更加直观。形式如下图所示:
灰色代表要插入的点
就是说,假设灰色的点代表是插值的点,那么就是取其最近的颜色,作为插值后的颜色。所以在这里表示就是亮黄色。直接赋值。

双线性插值 Bilinear Interpolation,直观理解如下图所示:
在这里插入图片描述
我们还是建立在上述情况,这个时候,灰色的点 q q q位于 ( x , y ) (x,y) (x,y),不再是直接考虑最近的点,而是和其相近的四个点,然后通过面积的比重,来分配权重。所以公式可以表示成:
q = V 1 ∗ A 1 + V 2 ∗ A 2 + V 3 ∗ A 3 + V 4 ∗ A 4 q=V 1* A 1+V 2 * A 2+V 3*A 3+V 4* A 4 q=V1A1+V2A2+V3A3+V4A4
对应的计算就可以这么写(请参照图上的坐标进行一一对应):
f ( x , y ) ≈ f ( V 1 ) ( x 2 − x 1 ) ( y 2 − y 1 ) ( x 2 − x ) ( y 2 − y ) + f ( V 2 ) ( x 2 − x 1 ) ( y 2 − y 1 ) ( x − x 1 ) ( y 2 − y ) + f ( V 3 ) ( x 2 − x 1 ) ( y 2 − y 1 ) ( x 2 − x ) ( y − y 1 ) + f ( V 4 ) ( x 2 − x 1 ) ( y 2 − y 1 ) ( x − x 1 ) ( y − y 1 ) . \begin{aligned} &f(x, y) \approx \frac{f\left(V_{1}\right)}{\left(x_{2}-x_{1}\right)\left(y_{2}-y_{1}\right)}\left(x_{2}-x\right)\left(y_{2}-y\right)+\frac{f\left(V_{2}\right)}{\left(x_{2}-x_{1}\right)\left(y_{2}-y_{1}\right)}\left(x-x_{1}\right)\left(y_{2}-y\right) \\ &+\frac{f\left(V_{3}\right)}{\left(x_{2}-x_{1}\right)\left(y_{2}-y_{1}\right)}\left(x_{2}-x\right)\left(y-y_{1}\right)+\frac{f\left(V_{4}\right)}{\left(x_{2}-x_{1}\right)\left(y_{2}-y_{1}\right)}\left(x-x_{1}\right)\left(y-y_{1}\right) . \end{aligned} f(x,y)(x2x1)(y2y1)f(V1)(x2x)(y2y)+(x2x1)(y2y1)f(V2)(xx1)(y2y)+(x2x1)(y2y1)f(V3)(x2x)(yy1)+(x2x1)(y2y1)f(V4)(xx1)(yy1).

这样就能直接得到当前点 f ( x , y ) f(x,y) f(x,y)的值。
注意, f ( x , y ) f(x,y) f(x,y)表示的就是像素,以函数的形式来进行表示。 ( x 2 − x 1 ) ( y 2 − y 1 ) \left(x_{2}-x_{1}\right)\left(y_{2}-y_{1}\right) (x2x1)(y2y1)表示的就是总面积。
至此,Nearest差值和Bilinear差值讲解就结束了,可以看一下代码,更能够容易理解一点。在这里插入图片描述
如果觉得不错,记得关注哟!一起来学习深度学习,机器学习等前沿算法!!
欢迎转载!
参考:https://www.cnblogs.com/wojianxin/p/12516029.html

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在图像处理中,插值是一种重要的技术。在放大或缩小图像时,插值可以帮助我们得到更平滑、更清晰的图像。常用的插值算法有最近邻插值和双线性插值。下面我们将手动实现这两种插值算法,并用Python进行演示。 首先,我们需要导入一些常用的包,包括numpy、matplotlib和PIL。numpy用于处理矩阵,matplotlib用于显示图像,PIL用于读取和保存图像。 ```python import numpy as np import matplotlib.pyplot as plt from PIL import Image ``` 接下来,我们定义一个函数nearest_interpolation,用于实现最近邻插值。 ```python def nearest_interpolation(img, scale): """ 最近邻插值 :param img: 原图像 :param scale: 缩放比例 :return: 插值后的图像 """ height, width = img.shape # 计算插值后的图像大小 new_height = int(height * scale) new_width = int(width * scale) # 初始化插值后的图像 new_img = np.zeros((new_height, new_width), dtype=np.uint8) # 计算缩放比例 x_ratio = width / new_width y_ratio = height / new_height # 插值 for i in range(new_height): for j in range(new_width): x = int(j * x_ratio) y = int(i * y_ratio) new_img[i, j] = img[y, x] return new_img ``` 该函数接受两个参数,分别是原图像和缩放比例。在函数内部,我们首先计算插值后的图像大小。然后,我们使用双重循环,对插值后的每一个像素进行计算。对于每一个像素,我们首先计算它在原图像中的位置,然后使用最近邻像素的值来进行插值。最后,我们返回插值后的图像。 接下来,我们定义一个函数bilinear_interpolation,用于实现双线性插值。 ```python def bilinear_interpolation(img, scale): """ 双线性插值 :param img: 原图像 :param scale: 缩放比例 :return: 插值后的图像 """ height, width = img.shape # 计算插值后的图像大小 new_height = int(height * scale) new_width = int(width * scale) # 初始化插值后的图像 new_img = np.zeros((new_height, new_width), dtype=np.uint8) # 计算缩放比例 x_ratio = width / new_width y_ratio = height / new_height # 插值 for i in range(new_height): for j in range(new_width): x = j * x_ratio y = i * y_ratio # 计算四个最近的像素 x1 = int(x) y1 = int(y) x2 = x1 + 1 y2 = y1 + 1 # 确保不越界 if x2 >= width: x2 = width - 1 if y2 >= height: y2 = height - 1 # 计算权重 w1 = (x2 - x) * (y2 - y) w2 = (x - x1) * (y2 - y) w3 = (x2 - x) * (y - y1) w4 = (x - x1) * (y - y1) # 计算插值后的像素值 new_img[i, j] = w1 * img[y1, x1] + w2 * img[y1, x2] + w3 * img[y2, x1] + w4 * img[y2, x2] return new_img ``` 该函数的实现原理比最近邻插值稍微复杂一些。我们首先计算插值后的图像大小,然后使用双重循环,对插值后的每一个像素进行计算。对于每一个像素,我们首先计算它在原图像中的位置,然后找到它周围四个最近的像素。我们使用这四个像素的值和它们之间的距离来计算权重,然后使用这些权重对它们进行加权平均来进行插值。最后,我们返回插值后的图像。 下面是一个完整的演示程序,我们将使用这个程序来比较最近邻插值和双线性插值的效果。 ```python # 读取图像 img = Image.open("lena.png").convert("L") img = np.array(img) # 最近邻插值 nearest_img = nearest_interpolation(img, 2) plt.subplot(121) plt.imshow(nearest_img, cmap="gray") plt.title("nearest interpolation") # 双线性插值 bilinear_img = bilinear_interpolation(img, 2) plt.subplot(122) plt.imshow(bilinear_img, cmap="gray") plt.title("bilinear interpolation") plt.show() ``` 在这个程序中,我们首先读取一张灰度图像,然后使用最近邻插值和双线性插值对它进行放大。最后,我们使用matplotlib来显示结果。运行这个程序,我们可以看到最近邻插值和双线性插值的效果如下图所示: ![nearest_bilinear_comparison](https://img-blog.csdn.net/20180519174415263?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hpdGdwdC9sb2dvXzIwMTgwNzEyMTY5MDkyMzA0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/85) 从结果可以看出,双线性插值的效果要比最近邻插值好得多。最近邻插值的图像看起来比较粗糙,而双线性插值的图像则比较平滑。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值