手动实现最近邻的图像插值、双线性插值,用Python
时间: 2024-05-24 18:04:55 浏览: 109
在图像处理中,插值是一种重要的技术。在放大或缩小图像时,插值可以帮助我们得到更平滑、更清晰的图像。常用的插值算法有最近邻插值和双线性插值。下面我们将手动实现这两种插值算法,并用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)
从结果可以看出,双线性插值的效果要比最近邻插值好得多。最近邻插值的图像看起来比较粗糙,而双线性插值的图像则比较平滑。
阅读全文