图像插值算法有很多一般采用的是最邻近插值和双线性插值。
最邻近插值
最邻近插值顾名思义就是取图像最近点的值作为新的插入值,话不多说直接上代码
def nearest_interpolation(src_img, tar_size):
H = src_img.shape[0] #原始图像的高
W = src_img.shape[1] #原始图像的宽
channel= src_img.shape[2]
tar_H = H * tar_size[0] #插值后的高
tar_W = W * tar_size[1] #插值后的宽
tar_img = np.zeros([tar_H, tar_W, channel], dtype=np.uint8) #先生成插值后图像的大小,以0填充,注意一定是np.uint8
for h in range(tar_H - 1):
for w in range(tar_W - 1):
src_h = round(h / tar_size[0]) #得到对应原始图像的高和宽并取整
src_w = round(w/ tar_size[1])
tar_img[h, w] = src_img[src_h, src_w] #赋值
return tar_img
双线性插值
网上有很多介绍双线性插值原理,在这就不阐述了,简单一个原理就是根据周围四个点利用公式f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)计算新的插入值。
def bilinear_interpolation(org_img, tar_size):
org_h, org_w, channel= org_img.shape #得到原图图像的长和宽
dst_img = np.zeros((org_h * tar_size[0], org_w * tar_size[1], channel),dtype = np.uint8) #生成插值后图像的大小
dst_h, dst_w , channel= dst_img.shape #得到插值后图像的长和宽
scale_h = org_h / dst_h #计算插值后的倍数
scale_w = org_w / dst_w
for i in range(dst_h):
for j in range(dst_w):
src_x = i * scale_h #计算目标像素在原图像中的位置
src_y = j * scale_w
src_x_int = int(math.floor(src_x)) #取整
src_y_int = int(math.floor(src_y))
u = src_x - src_x_int
v = src_y - src_y_int
#判断是否超出边界
if src_x_int + 1 == org_h or src_y_int + 1 == org_w:
dst_img[i, j, :] = org_img[src_x_int, src_y_int, :]
continue
#根据公式求插值后的图像
dst_img[i, j, :] =(1-u)*(1-v)*org_img[src_x_int,src_y_int, :] + \
(1-u)*v*org_img[src_x_int,src_y_int+1, :] + \
u*(1-v)*org_img[src_x_int+1,src_y_int, :] +\
u*v*org_img[src_x_int+1,src_y_int+1, :]
return dst_img
全部代码如下:
from PIL import Image
import matplotlib.pyplot as plt
import cv2 as cv
import numpy as np
import math
#最近邻插值就是简单的选择x和y的整数部分的坐标像素点赋值给新图像
def nearest_interpolation(src_img, tar_size):
H = src_img.shape[0] #原始图像的高
W = src_img.shape[1] #原始图像的宽
channel= src_img.shape[2]
tar_H = H * tar_size[0] #插值后的高
tar_W = W * tar_size[1] #插值后的宽
tar_img = np.zeros([tar_H, tar_W, channel], dtype=np.uint8) #先生成插值后图像的大小,以0填充,注意一定是np.uint8
for h in range(tar_H - 1):
for w in range(tar_W - 1):
src_h = round(h / tar_size[0]) #得到对应原始图像的高和宽并取整
src_w = round(w/ tar_size[1])
tar_img[h, w] = src_img[src_h, src_w] #赋值
return tar_img
##双线性插值,根据公式f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)计算即可
def bilinear_interpolation(org_img, dst_shape):
org_h, org_w, channel= org_img.shape #得到原图图像的长和宽
dst_img = np.zeros((org_h * dst_shape[0], org_w *dst_shape[1], channel),dtype = np.uint8) #生成插值后图像的大小
dst_h, dst_w , channel= dst_img.shape #得到插值后图像的长和宽
scale_h = org_h / dst_h #计算插值后的倍数
scale_w = org_w / dst_w
for i in range(dst_h):
for j in range(dst_w):
src_x = i * scale_h #计算目标像素在原图像中的位置
src_y = j * scale_w
src_x_int = int(math.floor(src_x)) #取整
src_y_int = int(math.floor(src_y))
u = src_x - src_x_int
v = src_y - src_y_int
#判断是否查出边界
if src_x_int + 1 == org_h or src_y_int + 1 == org_w:
dst_img[i, j, :] = org_img[src_x_int, src_y_int, :]
continue
#根据公式求插值后的图像
dst_img[i, j, :] =(1-u)*(1-v)*org_img[src_x_int,src_y_int, :] + \
(1-u)*v*org_img[src_x_int,src_y_int+1, :] + \
u*(1-v)*org_img[src_x_int+1,src_y_int, :] +\
u*v*org_img[src_x_int+1,src_y_int+1, :]
return dst_img
image = Image.open('img.jpg') #读取图像
imgData = np.array(image) #将图像转化为数组
tar_size = (2, 3) #插值后图像的大小
# tar_img = nearest_interpolation(imgData, tar_size) ##邻近插值插值
tar_img = bilinear_interpolation(imgData, tar_size) ##双线性插值
plt.figure("Image")
plt.imshow(image)
plt.axis('on')
plt.title('image')
plt.show()
plt.figure('tar_img')
plt.imshow(tar_img)
plt.axis('on')
plt.title('tar_img')
plt.show()
后续将会跟新3d图像的插值算法