最邻近插值算法、双线性插值算法的原理及实现

上采样与下采样

缩小图像(下采样或降采样)的主要目的有两个:1、使得图像符合显示区域的大小;2、生成对应图像的缩略图。

放大图像(上采样)的主要目的是放大原图像,从而可以显示在更高分辨率的显示设备上。

上下采样时,图像的放大与缩小,需要保持图像不失真,这时需要用到插值算法。

常用的插值算法

1、最邻近插值

在四个像素点上划分为四个区域A B C D如下图所示,然后插值到A区域的点,其像素值等于坐标(i,j)的像素值,插值到B区域的点,其像素值等于坐标(i+1,j)的像素值,插值到C区域的点,其像素值等于坐标(i,j+1)的像素值,插值到D区域的点,其像素值等于坐标(i+1,j+1)的像素值。

 代码:

import cv2
import numpy as np
def function(img):  #插值算法函数
    height,width,channels = img.shape
    emptyImage=np.zeros((500,500,channels),np.uint8)  #改变图像大小为500*500
    sh = 500/height  #放大比例
    sw = 500/width
    for i in range(500):
        for j in range(500):
            x = int(i/sh)
            y = int(j/sw)
            emptyImage[i,j]=img[x,y]
    return emptyImage
img = cv2.imread("lenna.jpg")
print(img.shape)
zoom = function(img)
print(zoom)
print(zoom.shape)
cv2.imshow("nearest interp",zoom)
cv2.imshow("image",img)
cv2.waitKey(0)

运行结果:

 2、双线性插值

双线性插值顾名思义就是两次线性,如下图所示,已知Q12 Q22 Q11 Q21四个点的像素值 ,现在要求点P的像素值;先根据点Q12 Q22求出R2的像素值以及根据点Q11 Q21求出R1的像素值,然后根据R2 R1的像素值求出P的像素值,其过程分为两次单线性插值求出P的像素值。

 具体求值过程如下:

 双线性插值算法的精度比最邻近插值算法的高,没有灰度不连续的缺点,图像看起来更光滑,但是复杂度高,计算量大。

代码:

import numpy as np
import cv2
def bilinear_interpolation(img,out_dim):
    src_h, src_w, channel = img.shape
    dst_h, dst_w = out_dim[1], out_dim[0]
    print("src_h, src_w = ",src_h, src_w)
    print("dst_h, dst_w = ",dst_h, dst_w)
    if src_h == dst_h and src_w == dst_w:
        return img.copy()
    dst_img = np.zeros((dst_h,dst_w,3),dtype=np.uint8)
    scale_x, scale_y = float(src_w) / dst_w, float(src_h) / dst_h
    for i in range(3):
        for dst_y in range(dst_h):
            for dst_x in range(dst_w):
                src_x = (dst_x + 0.5) * scale_x-0.5  #中心重合
                src_y = (dst_y + 0.5) * scale_y-0.5

                src_x0 = int(np.floor(src_x))
                src_x1 = min(src_x0 + 1,src_w - 1)
                src_y0 = int(np.floor(src_y))
                src_y1 = min(src_y0 + 1, src_h - 1)

                temp0 = (src_x1 - src_x ) * img[src_y0,src_x0,i] + (src_x - src_x0) * img[src_y0,src_x1,i]
                temp1 = (src_x1 - src_x) * img[src_y1, src_x0, i] + (src_x - src_x0) * img[src_y1, src_x1, i]
                dst_img[dst_y,dst_x,i] = int((src_y1 - src_y) * temp0 + (src_y - src_y0) * temp1)
    return dst_img

if __name__ == '__main__':
    img = cv2.imread('lenna.jpg')
    dst = bilinear_interpolation(img,(500,500))
    cv2.imshow('bilinner interp',dst)
    cv2.waitKey()

运行结果:

 可以看到运行结果明显比最邻近插值算法的运行结果清晰。

猜你喜欢

转载自blog.csdn.net/Exception_3212536934/article/details/125141459