一.图像插值算法
在图像处理中,平移变换、旋转变换以及放缩变换是一些基础且常用的操作。这些几何变换并不改变图象的象素值,只是在图象平面上进行象素的重新排列。在一幅输入图象 [ u , v ] [u,v] [u,v]中,灰度值仅在整数位置上有定义。然而,输出图象[x,y]的灰度值一般由处在非整数坐标上的 ( u , v ) (u,v) (u,v)值来决定。这就需要插值算法来进行处理,常见的插值算法有最近邻插值、双线性插值和三次样条插值。
1.1 最近邻插值算法
最近邻插值,是指将目标图像中的点,对应到源图像中后,找到最相邻的整数点,作为插值后的输出。
假设图像(灰度图)为例:
234 38 22
67 44 12
89 65 63
若我门想扩张为
? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ?
则 有
将一幅3X3的图像放大到4X4,用
f
(
x
,
y
)
f(x, y)
f(x,y)表示目标图像,
h
(
x
,
y
)
h(x, y)
h(x,y)表示原图像,我们有如下公式:
f
(
d
s
t
X
,
d
s
t
Y
)
=
h
(
d
s
t
X
s
r
c
W
i
d
t
h
d
s
t
W
i
d
t
h
,
d
s
t
Y
s
r
c
H
e
i
g
h
t
d
s
t
H
e
i
g
h
t
)
\begin{array}{c} f(dst_{X}, dst_{Y}) = h(\frac{dst_{X}src_{Width}} {dst_{Width}}, \frac{dst_{Y}src_{Height}} {dst_{Height}}) \end{array}
f(dstX,dstY)=h(dstWidthdstXsrcWidth,dstHeightdstYsrcHeight)
f
(
0
,
0
)
=
h
(
0
,
0
)
,
f
(
0
,
1
)
=
h
(
0
,
0.75
)
=
h
(
0
,
1
)
,
f
(
0
,
2
)
=
h
(
0
,
1.50
)
=
h
(
0
,
2
)
,
f
(
0
,
3
)
=
h
(
0
,
2.25
)
=
h
(
0
,
2
)
,
.
.
.
\begin{array}{c} f(0,0)=h(0,0), \ f(0,1)=h(0,0.75)=h(0,1),\ f(0,2)=h(0,1.50)=h(0,2), \ f(0,3)=h(0,2.25)=h(0,2), \ ...\ \end{array}
f(0,0)=h(0,0), f(0,1)=h(0,0.75)=h(0,1), f(0,2)=h(0,1.50)=h(0,2), f(0,3)=h(0,2.25)=h(0,2), ...
于是得图像为:
234 38 22 22
67 44 12 12
89 65 63 63
89 65 63 63
缺点: 用该方法作放大处理时,在图象中可能出现明显的块状效应
1.2 双线性插值(Bilinear interpolation)
双线型内插值算法就是一种比较好的图像缩放算法,它充分的利用了源图中虚拟点四周的四个真实存在的像素值来共同决定目标图中的一个像素值,因此缩放效果比简单的最邻近插值要好很多。
srcX=dstX* (srcWidth/dstWidth) ,
srcY = dstY * (srcHeight/dstHeight)
令
f
(
x
,
y
)
f(x,y)
f(x,y)为两个变量的函数,其在单位正方形顶点的值已知。假设我们希望通过插值得到正方形内任意点的函数值。则可由双线性方程:
f
(
x
,
y
)
=
a
x
+
b
y
+
c
x
y
+
d
f(x, y)=a x+b y+c x y+d
f(x,y)=ax+by+cxy+d
来定义的一个双曲抛物面与四个已知点拟合。
首先对上端的两个顶点进行线性插值得:
f ( x , 0 ) = f ( 0 , 0 ) + x [ f ( 1 , 0 ) − f ( 0 , 0 ) ] f(x, 0)=f(0,0)+x[f(1,0)-f(0,0)] f(x,0)=f(0,0)+x[f(1,0)−f(0,0)]
类似地,再对底端的两个顶点进行线性插值有: f ( x , 1 ) = f ( 0 , 1 ) + x [ f ( 1 , 1 ) − f ( 0 , 1 ) ] f(x, 1)=f(0,1)+x[f(1,1)-f(0,1)] f(x,1)=f(0,1)+x[f(1,1)−f(0,1)]
最后,做垂直方向的线性插值,以确定:
f ( x , y ) = f ( x , 0 ) + y [ f ( x , 1 ) − f ( x , 0 ) ] f(x, y)=f(x, 0)+y[f(x, 1)-f(x, 0)] f(x,y)=f(x,0)+y[f(x,1)−f(x,0)]
整理得:
f
(
x
,
y
)
=
[
f
(
1
,
0
)
−
f
(
0
,
0
)
]
x
+
[
f
(
0
,
1
)
−
f
(
0
,
0
)
]
y
+
[
f
(
1
,
1
)
+
f
(
0
,
0
)
−
f
(
0
,
1
)
−
f
(
1
,
0
)
]
x
y
+
f
(
0
,
0
)
\begin{array}{l} f(x, y)=[f(1,0)-f(0,0)] x+[f(0,1)-f(0,0)] y \ +[f(1,1)+f(0,0)-f(0,1)-f(1,0)] x y+f(0,0) \end{array}
f(x,y)=[f(1,0)−f(0,0)]x+[f(0,1)−f(0,0)]y +[f(1,1)+f(0,0)−f(0,1)−f(1,0)]xy+f(0,0)
一般在opencv中
方法:在计算源图像的虚拟浮点坐标的时候,一般情况:
srcX=dstX* (srcWidth/dstWidth) ,
srcY = dstY * (srcHeight/dstHeight)
中心对齐(OpenCV也是如此):
SrcX=(dstX+0.5)* (srcWidth/dstWidth) -0.5
SrcY=(dstY+0.5) * (srcHeight/dstHeight)-0.5
img = cv2.imread("timg.jpg")
if img is None:
print("timg.jpeg is not find")
print(img.shape)
cv2.imshow("timg.jpg",img)
print('Original Dimensions : ',img.shape)
scale_percent = 30 # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
resized = cv2.resize(img, dim, interpolation = cv2.INTER_LINEAR)
fx = 1.5
fy = 1.5
resized1 = cv2.resize(resized, dsize=None, fx=fx, fy=fy, interpolation = cv2.INTER_NEAREST)
resized2 = cv2.resize(resized, dsize=None, fx=fx, fy=fy, interpolation = cv2.INTER_LINEAR)
print('Resized Dimensions : ',resized.shape)
cv2.imshow("Resized image", resized)
cv2.imshow("INTER_NEAREST image", resized1)
cv2.imshow("INTER_LINEAR image", resized2)
cv2.waitKey(0)
cv2.destroyAllWindows()