采用Python、numpy库实现图像的插值算法,主要用于分析三种常见的插值算法的具体流程。
插值,分为图像内插值和图像间插值,其主要应用是对图像进行放大以及旋转等操作,是根据一幅较低分辨率图像再生出另一幅均具有较高分辨率的图像,是图像内插值。图像间的插值,也叫图像的超分辨率重建,是指在一图像序列之间再生出若干幅新的图像,可应用于医学图像序列切片和视频序列之间的插值图像内插值实际上是对单帧图像的图像重建过程,这就意味着生成原始图像中没有的数据。
本文研究图像内插值,图象插值方法有:最近邻插值,双线性插值,双平方插值,双立方插值以及其他高阶方法。最近邻插值和双线性插值算法很容易出现锯齿,生成的图片质量不好。因此一般只在对图像质量要求不高的场合下采用。双平方插值和双立方插值,实质上是”低通滤波器”,在增强图像平滑效果的同时丢失了许多高频信息。而在很多应用场合,细节信息恰恰非常重要,要考虑如何在保证平滑效果的同时尽可能地保留细节信息。
最近邻插值:
这是最简单的一种插值方法,不需要计算,在待求象素的四邻像素中,将距离待求象素最近的邻像素灰度赋给待求像素。设i+u, j+v(i, j为正整数, u, v为大于零小于1的小数,下同)为待求像素坐标,则待求像素灰度的值 f(i+u, j+v)。如下图所示:
如果(i+u, j+v)落在A区,即u<0.5, v<0.5,则将左上角像素的灰度值赋给待求像素,同理,落在B区则赋予右上角的像素灰度值,落在C区则赋予左下角像素的灰度值,落在D区则赋予右下角像素的灰度值。
最邻近元法计算量较小,但可能会造成插值生成的图像灰度上的不连续,在灰度变化的地方可能出现明显的锯齿状。
双线性插值:
双线性内插法是利用待求象素四个邻像素的灰度在两个方向上作线性内插,如下图所示:
f(i+u, j+v) = (1-u) * (1-v) * f(i, j) + (1-u) * v * f(i, j+1) + u * (1-v) * f(i+1, j) + u * v * f(i+1, j+1)
双线性内插法的计算比最邻近点法复杂,计算量较大,但没有灰度不连续的缺点,结果基本令人满意。它具有低通滤波性质,使高频分量受损,图像轮廓可能会有一点模糊。
双三次插值:
该方法利用三次多项式S(x)求逼近理论上最佳插值函数sin(x)/x, 根据其不同的数学表达式可分为三角插值法、Bell分布插值、B样条曲线插值。待求像素(x, y)的灰度值由其周围16个灰度值加权内插得到,如下图:
三次曲线插值方法计算量较大,但插值后的图像效果最好。
具体的效果如下图所示:左上为原始图像,右上为最近邻插值,左下为双线性插值,右下为双立方插值(Bell分布)。
Python代码:
#coding:utf-8
#*********************************************************************************************************
'''
说明:利用python/numpy/opencv实现图像插值法(最邻近,双线性,双三次(Bell分布))
算法思路:
1)以彩色图的方式加载图片;
2)根据想要生成的图像大小,映射获取某个像素点在原始图像中的浮点数坐标;
3)根据浮点数坐标确定插值算法中的系数、参数;
4)采用不同的算法实现图像插值。
'''
import cv2
import numpy as np
import matplotlib.pyplot as plt
def Nearest( img, bigger_height, bigger_width, channels ):
near_img = np.zeros( shape = ( bigger_height, bigger_width, channels ), dtype = np.uint8 )
for i in range( 0, bigger_height ):
for j in range( 0, bigger_width ):
row = ( i / bigger_height ) * img.shape[0]
col = ( j / bigger_width ) * img.shape[1]
near_row = round ( row )
near_col = round( col )
if near_row == img.shape[0] or near_col == img.shape[1]:
near_row -= 1
near_col -= 1
near_img[i][j] = img[near_row][near_col]
return near_img
def Bilinear( img, bigger_height, bigger_width, channels ):
bilinear_img = np.zeros( shape = ( bigger_height, bigger_width, channels ), dtype = np.uint8 )
for i in range( 0, bigger_height ):
for j in range( 0, bigger_width ):
row = ( i / bigger_height ) * img.shape[0]
col = ( j / bigger_width ) * img.shape[1]
row_int = int( row )
col_int = int( col )
u = row - row_int
v = col - col_int
if row_int == img.shape[0]-1 or col_int == img.shape[1]-1:
row_int -= 1
col_int -= 1
bilinear_img[i][j] = (1-u)*(1-v) *img[row_int][col_int] + (1-u)*v*img[row_int][col_int+1] + u*(1-v)*img[row_int+1][col_int] + u*v*img[row_int+1][col_int+1]
return bilinear_img
def Bicubic_Bell( num ):
# print( num)
if -1.5 <= num <= -0.5:
# print( -0.5 * ( num + 1.5) ** 2 )
return -0.5 * ( num + 1.5) ** 2
if -0.5 < num <= 0.5:
# print( 3/4 - num ** 2 )
return 3/4 - num ** 2
if 0.5 < num <= 1.5:
# print( 0.5 * ( num - 1.5 ) ** 2 )
return 0.5 * ( num - 1.5 ) ** 2
else:
# print( 0 )
return 0
def Bicubic ( img, bigger_height, bigger_width, channels ):
Bicubic_img = np.zeros( shape = ( bigger_height, bigger_width, channels ), dtype = np.uint8 )
for i in range( 0, bigger_height ):
for j in range( 0, bigger_width ):
row = ( i / bigger_height ) * img.shape[0]
col = ( j / bigger_width ) * img.shape[1]
row_int = int( row )
col_int = int( col )
u = row - row_int
v = col - col_int
tmp = 0
for m in range( -1, 3):
for n in range( -1, 3 ):
if ( row_int + m ) < 0 or (col_int+n) < 0 or ( row_int + m ) >= img.shape[0] or (col_int+n) >= img.shape[1]:
row_int = img.shape[0] - 1 - m
col_int = img.shape[1] - 1 - n
numm = img[row_int + m][col_int+n] * Bicubic_Bell( m-u ) * Bicubic_Bell( n-v )
tmp += np.abs( np.trunc( numm ) )
Bicubic_img[i][j] = tmp
return Bicubic_img
if __name__ == '__main__':
img = cv2.imread( 'data/lena.jpg', cv2.IMREAD_COLOR)
img = cv2.cvtColor( img, cv2.COLOR_BGR2RGB )
print( img[3][3] )
height, width, channels = img.shape
print( height, width )
bigger_height = height + 200
bigger_width = width + 200
print( bigger_height, bigger_width)
near_img = Nearest( img, bigger_height, bigger_width, channels )
bilinear_img = Bilinear( img, bigger_height, bigger_width, channels )
Bicubic_img = Bicubic( img, bigger_height, bigger_width, channels )
plt.figure()
plt.subplot( 2, 2, 1 )
plt.title( 'Source_Image' )
plt.imshow( img )
plt.subplot( 2, 2, 2 )
plt.title( 'Nearest_Image' )
plt.imshow( near_img )
plt.subplot( 2, 2, 3 )
plt.title( 'Bilinear_Image' )
plt.imshow( bilinear_img )
plt.subplot( 2, 2, 4 )
plt.title( 'Bicubic_Image' )
plt.imshow( Bicubic_img )
plt.show()