【问题标题】:Resize using bilinear interpolation in Python在 Python 中使用双线性插值调整大小
【发布时间】:2024-05-16 05:30:02
【问题描述】:

我正在尝试使用双线性插值手动实现调整图像大小。 到目前为止,我得到的是插值本身的功能,它似乎工作正常,但调整大小功能似乎只在角落正常工作:

def bilinear_interpolation(image, y, x):
height = len(image)
width = len(image[0])

x1 = min(math.floor(x), width - 1)
y1 = min(math.floor(y), height - 1)
x2 = min(math.ceil(x), width - 1)
y2 = min(math.ceil(y), height - 1)

a = image[y1][x1]
b = image[y2][x1]
c = image[y1][x2]
d = image[y2][x2]

new_pixel = a * (1 - x) * (1 - y)
new_pixel += b * y * (1 - x)
new_pixel += c * x * (1 - y)
new_pixel += d * x * y
return round(new_pixel)
def resize(image, new_height, new_width):

new_image = [[0 for _ in range(new_width)] for _ in range(new_height)]

for y in range(new_height):
    for x in range(new_width):
        x_ = (x / (new_width - 1)) * len(image[0])
        y_ = (y / (new_height - 1)) * len(image)

        new_image[y][x] = bilinear_interpolation(image, y_, x_)

return new_image

所以对于矩阵:

[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]

我明白了

[[1, 4], [9, 12], [13, 16]]

而不是

[[1, 4], [7, 10], [13, 16]]

提前致谢。

【问题讨论】:

    标签: python image-processing


    【解决方案1】:

    计算x_y_可以看我下面的answer

    公式为:

    x_ = (x - x_scaled_center) * scale_x + x_orig_center
    y_ = (y - y_scaled_center) * scale_y + y_orig_center
    

    在双线性插值中,你错过了dxdy的计算:

    dx = x - x1
    dy = y - y1
    
    new_pixel = a * (1 - dx) * (1 - dy)
    new_pixel += b * dy * (1 - dx)
    new_pixel += c * dx * (1 - dy)
    new_pixel += d * dx * dy
    

    这是一个完整的代码示例(将结果与cv2.resize 进行比较):

    import cv2
    import math
    import numpy as np
    
    def bilinear_interpolation(image, y, x):
        height = image.shape[0]
        width = image.shape[1]
    
        x1 = max(min(math.floor(x), width - 1), 0)
        y1 = max(min(math.floor(y), height - 1), 0)
        x2 = max(min(math.ceil(x), width - 1), 0)
        y2 = max(min(math.ceil(y), height - 1), 0)
    
        a = float(image[y1, x1])
        b = float(image[y2, x1])
        c = float(image[y1, x2])
        d = float(image[y2, x2])
    
        dx = x - x1
        dy = y - y1
    
        new_pixel = a * (1 - dx) * (1 - dy)
        new_pixel += b * dy * (1 - dx)
        new_pixel += c * dx * (1 - dy)
        new_pixel += d * dx * dy
        return round(new_pixel)
    
    
    def resize(image, new_height, new_width):
        new_image = np.zeros((new_height, new_width), image.dtype)  # new_image = [[0 for _ in range(new_width)] for _ in range(new_height)]
    
        orig_height = image.shape[0]
        orig_width = image.shape[1]
    
        # Compute center column and center row
        x_orig_center = (orig_width-1) / 2
        y_orig_center = (orig_height-1) / 2
    
        # Compute center of resized image
        x_scaled_center = (new_width-1) / 2
        y_scaled_center = (new_height-1) / 2
    
        # Compute the scale in both axes
        scale_x = orig_width / new_width;
        scale_y = orig_height / new_height;
    
        for y in range(new_height):
            for x in range(new_width):
                x_ = (x - x_scaled_center) * scale_x + x_orig_center
                y_ = (y - y_scaled_center) * scale_y + y_orig_center
    
                new_image[y, x] = bilinear_interpolation(image, y_, x_)
    
        return new_image
    
    img = cv2.imread('graf.png', cv2.IMREAD_GRAYSCALE)  # http://man.hubwiz.com/docset/OpenCV.docset/Contents/Resources/Documents/db/d70/tutorial_akaze_matching.html
    
    new_width = 500
    new_height = 400
    
    resized_img = resize(img, new_height, new_width)
    
    # Reference for testing
    reference_resized_img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_LINEAR)
    
    abs_diff = cv2.absdiff(reference_resized_img, resized_img)
    print('max abs_diff = ' + str(abs_diff.max()))  # 1 gray level difference
    
    cv2.imshow('img', img)
    cv2.imshow('resized_img', resized_img)
    cv2.imshow('reference_resized_img', reference_resized_img)
    cv2.imshow('abs_diff*10', abs_diff*10)
    cv2.waitKey()
    cv2.destroyAllWindows()
    

    img:

    resized_img:


    注意(对于其他用户):

    • 实施更多的是学术性而非实际性。
      如果您正在寻找一种有效的实施方式,请寻找其他地方。

    【讨论】: