在图像处理中,如果需要对图像进行缩放,一般可以采取插值法,最常用的就是双线性插值法。本文首先从数学角度推导了一维线性插值和二维线性插值的计算过程,并总结了规律。随后将其应用到图像的双线性插值上,利用Matlab编程进行图像的缩放验证,实验证明,二维线性插值能够对图像做出较好的缩放效果。
数学角度的线性插值
一维线性插值
假设有一个一元函数 (y = f(x)) , 已知曲线上的两点,(A) 和 (B) 的坐标分别为 ((x_0 , y_0)) 、((x_1, y_1)) 。现在要在(A) 和 (B) 之间通过插值计算出一个点 (P) ,若已知 (P)点的横坐标 (x),如何求出 (P)点的纵坐标 (y) ?
这里我们的插值之所以叫做线性插值,就是因为我们假定了 (P) 点落在 (A) 点和 (B) 点的连线上,使得他们的坐标之间满足线性关系。所以,根据初中的知识,可以得到下面的等式:
[{{y – {y_0}} over {{y_1} – {y_0}}} = {{x – {x_0}} over {{x_1} – {x_0}}}
]
这里我们令:
[alpha = {{x – {x_0}} over {{x_1} – {x_0}}}
]
于是,我们可以得到(P)点的纵坐标 (y) 的表达式:
[y = left( {1 – alpha } ight){f(x_0)} + alpha {f(x_1)}
]
二维线性插值
一维线性插值可以扩展到二维的情况。
假设有一个二元函数 (z = f(x,y)) , 已知曲面上的四点,(A) 、(B) 、(C)、(D)的坐标分别为 ((x_0 , y_0)) 、((x_1, y_0)) 、((x_1, y_1))、((x_0, y_1)) 。现在要在(A) 、(B) 、(C)、(D)之间通过插值计算出一个点 (P) ,若已知 (P)点的坐标 ((x,y)),如何求出 (P)点的函数值坐标 (z) ?
这里我们依旧可以仿照一维线性插值,进行计算。
假设先计算 (y) 轴方向的插值点 (P_0) 和 (P_1) ,则根据上面的推导过程,且令
[alpha = {{y – {y_0}} over {{y_1} – {y_0}}}
]
则, (P_0) 的取值 (z_0)为:
[z_0 = left( {1 – alpha } ight){f(x_0,y_0)} + alpha {f(x_0,y_1)}
]
(P_1) 的取值 (z_1)为:
[z_1 = left( {1 – alpha } ight){f(x_1,y_0)} + alpha {f(x_1,y_1)}
]
再计算 (x) 轴方向的插值点 (P),令
[eta = {{x – {x_0}} over {{x_1} – {x_0}}}
]
则 (P) 的取值 (z)为:
[z = left( {1 – eta } ight){z_0} + eta {z_1}
]
整理得到下面的式子:
[eqalign{
& z = left( {1 – eta } ight)left[ {left( {1 – alpha } ight)fleft( {{x_0},{y_0}} ight) + alpha fleft( {{x_0},{y_1}} ight)} ight] + eta left[ {left( {1 – alpha } ight)fleft( {{x_1},{y_0}} ight) + alpha fleft( {{x_1},{y_1}} ight)} ight] cr
& ;;{kern 1pt} = left( {1 – eta } ight)left( {1 – alpha } ight)fleft( {{x_0},{y_0}} ight) + left( {1 – eta } ight)alpha fleft( {{x_0},{y_1}} ight) + eta left( {1 – alpha } ight)fleft( {{x_1},{y_0}} ight) + eta alpha fleft( {{x_1},{y_1}} ight) cr}
]
小结
由一维线性插值过渡到二维线性插值,我们发现,二者在表达式上有相似的规律:
一维线性插值:
[left{ {matrix{
{y = fleft( x ight)} hfill cr
{alpha = {{x_p – {x_0}} over {{x_1} – {x_0}}}} hfill cr
{{y_p} = left( {1 – alpha } ight)fleft( {{x_0}} ight) + alpha fleft( {{x_1}} ight)} hfill cr
} } ight.
]
二维线性插值:
[left{ {matrix{
{z = fleft( {x,y} ight)} hfill cr
{alpha = {{{x_p} – {x_0}} over {{x_1} – {x_0}}},eta = {{{y_p} – {y_0}} over {{y_1} – {y_0}}}} hfill cr
{{z_p} = left( {1 – eta } ight)left( {1 – alpha } ight)fleft( {{x_0},{y_0}} ight) + left( {1 – eta } ight)alpha fleft( {{x_0},{y_1}} ight) + eta left( {1 – alpha } ight)fleft( {{x_1},{y_0}} ight) + eta alpha fleft( {{x_1},{y_1}} ight)} hfill cr
} } ight.
]
图像中的双线性插值
我们可以用函数来表示一幅图像(假设为单通道)。如下图所示,假设有一幅图,其尺寸为3×3大小,每个像素点对应一个灰度值(0~255),以图像的左上角为坐标原点,横向为 (x) 轴,纵向为 (y) 轴,则图像的表达式可以表达为:
[f(x,y)
]
每个像素点的灰度值 (z) 由横纵坐标唯一确定,即 (z=f(x,y)) 。
假设需要将图片进行尺寸缩放,则可以利用前面所提到的双线性插值法进行变换。
这里我们定义原始的图片为 src
,其宽度为 src_width
, 高度为 src_height
,通道数为 channel
。
缩放的目标图片为 dst
,其宽度为 dst_width
, 高度为 dst_height
, 通道数与原始图片一样,为channel
。
利用双线性插值来进行图像的缩放步骤如下:
计算目标图片与原始图片之间的缩放因子(宽度、高度方向)
利用缩放因子,由目标图片像素位置反推回原始图片中的虚拟像素位置
由虚拟像素位置找到宽度和高度方向相邻的四个像素点
由四个像素点进行双线性插值计算,得出目标图像中的像素值
由于图片像素的位置一格表示一个像素,因此,在前面的公式中,相邻的点之间坐标在相同方向的差值为1。
基于Matlab的图片双线性插值
close all
clc
clear
% 读取原始图像,并转换为 double 类型
src = imread('lena.jpg');
src = im2double(src);
% 读取图像尺寸信息
[src_width, src_height,channel] = size(src);
% 目标图像尺寸
dst_width = 50;
dst_height = 50;
% 计算缩放因子
horFactor = src_width / dst_width;
verFactor = src_height / dst_height;
% 初始化矩阵
dst = zeros(dst_width,dst_height,channel);
for i = 1:channel
for j = 1:dst_width
x0 = j*horFactor; % 计算虚拟像素值位置
x1 = ceil(x0); % 取其左侧临近的位置
x2 = min([x1+1,src_width]); % 取其右侧侧临近的位置,用 min 防止超出原始图片边界
beta = x0 - x1; % 公式中的 beta
for k = 1:dst_height
y0 = k*verFactor; % 计算虚拟像素值位置
y1 = ceil(y0); % 取其左侧临近的位置
y2 = min([y1+1,src_height]);% 取其右侧侧临近的位置,用 min 防止超出原始图片边界
alpha = y0 - y1; % 公式中的 alpha
% 双线性插值求出该位置的像素值
dst(j,k,i) = (1-beta)*(1-alpha)*src(x1,y1,i) + ...
(1-beta)*alpha*src(x1,y2,i) + ...
beta*(1-alpha)*src(x2,y1,i) + ...
beta*alpha*src(x2,y2,i);
end
end
end
% 处理前后图片对比
subplot(1,2,1)
imshow(src)
subplot(1,2,2)
imshow(dst)
缩小图片
利用代码 可以对图像进行缩放 200×200 → 50×50
放大图片
利用代码 可以对图像进行缩放 200×200 → 600×600