图像插值算法及其优化

研究背景及其意义

图像放大旋转是数字图像处理中最基础的几何变换操作,其核心在于如何通过插值算法重建原始图像中不存在的像素信息。当对图像进行放大操作时,输出图像的像素网格会超出原始图像的采样范围,需要通过插值来填补这些新增像素点的颜色值;而在旋转操作中,即使保持图像尺寸不变,原始像素的整数坐标经过旋转变换后也会落在新图像的非整数位置,同样需要通过插值来重新确定每个输出像素的颜色值。

图像插值是利用原图像中的颜色值通过一定的方法计算出待插入像素点的颜色值的过程。对图像进行插值一般有两个步骤:首先定义一个图像插值公式,然后利用该插值公式计算待插入点的颜色值。常见的图像插值算法有双线性法、最近邻法、非均匀法、双三次卷积插值法、双立方法、Lagrange法、 样条插值法、 克里金(Krijing) 插值法等。这些插值方法通常定义一个插值数据点的隐式函数,再提取该函数的等值面作为图像插值方法,常用的插值核包括线性插值核、样条插值核等。

  • 最近邻插值作为最简单的算法,直接将距离待插值点最近的已知像素值作为结果,虽然计算效率极高(时间复杂度O(1)),但会产生明显的块状伪影(“马赛克”)和锯齿形边缘;
  • 双线性插值通过考虑2×2邻域内四个像素的加权平均,在计算成本(O(n))和视觉效果之间取得平衡,但仍会导致高频信息丢失和边缘模糊;
  • 更高阶的双三次插值(使用4×4邻域)和样条插值虽然能提供更平滑的结果,但计算复杂度显著增加(O(n²)),且可能引入不必要的振铃效应。

现有算法的根本局限在于采用统一的插值核函数处理整幅图像,忽视了图像不同区域的特征差异。例如,在平坦区域使用复杂插值会造成计算资源浪费,而在纹理丰富区域使用简单插值又会导致细节损失。基于此,我们希望通过改良的四平面插值算法对图像的放大与旋转效果进行优化,根据图像局部特征自适应地选择不同的插值策略,以规避用同一个插值公式对所有像素进行插值存在的不足。

常用图像插值算法

课本在6.5节中提到,在插值节点数量较多时,为避免Runge振荡现象的发生,并不提倡用高次多项式进行插值,而宁可用低次多项式作分段插值。在图像处理这一特定的应用场景中,需要处理的图像尺寸规模往往较大,且同一行(列)的所有像素颜色值显然并不具有可以用一个多项式函数显式表达的规律,但相邻的像素点颜色值之间又存在一定的关联性,因此分段插值仅考虑局部特征的特性在这里能够良好地契合所需性能。根据对于待插入像素点周围已有的像素点信息的利用情况,这里列举了几种常见的图像插值算法:

  • 最近邻法:仅利用待插值像素点转换至原图像坐标后距离其最近的一个像素点的颜色值,将其直接作为待插值像素点的颜色值
  • 双线性法:利用待插值像素点转换至原图像坐标后距离其最近的四个像素点的颜色值,加权平均后作为待插值像素点的颜色值
  • 双立方法:利用待插值像素点转换至原图像坐标后距离其最近的十六个像素点的颜色值,加权平均后作为待插值像素点的颜色值

最近邻法

一维最近邻插值示意图

如上图所示,在一维最近邻插值中,坐标轴上各点 xi-1,xi,xi+1 … 两两对半等分间隔 (红色虚线划分),从而非边界的各坐标点都有一个等宽的邻域,并根据每个坐标点的值构成一个类似分段函数的函数约束,从而使各插值坐标点的值等同于所在邻域原坐标点的值。例如,插值点 x 坐落于 坐标点 xi 的邻域,那么其值 f(x) 就等于 f(xi)。

在二维的图像插值场景中,可以对上述一维最近邻插值进行推广,如下图所示:

二维最近邻插值示意图

可以看到,(x0, y0)、(x0, y1)、(x1, y0)、(x1, y1) 都是原图像上的坐标点,颜色值分别对应为 Q11、Q12、Q21、Q22。而颜色值未知的插值点 (x, y)(需转换至原图像坐标),根据最近邻插值方法的约束,其与坐标点 (x0, y0) 位置最接近 (即位于 (x0, y0) 的邻域内),故插值点 (x, y) 的颜色值 P = Q11。

总而言之,最近邻法的基本思想即:将待插入点的坐标进行四舍五入,再以该行列坐标都是整数点的颜色值(灰度值)替代待插入点(x, y)处的颜色值。事实上,这也正是机器学习中KNN(K-Nearest Neighbor)算法在K=1时的情形。

基于以上算法思想,编写python函数代码实现图像放缩与旋转过程中的最近邻法插值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 最近邻法插值实现图像放缩
def nearest_neighbor_interpolation(image, scale_factor):
h, w, channel = image.shape
new_h, new_w = int(h * scale_factor), int(w * scale_factor)
resized_image = np.zeros((new_h, new_w, int(channel)), dtype=image.dtype)

for i in range(new_h):
for j in range(new_w):
src_i = int(round((i + 1) / scale_factor, 0))
src_j = int(round((j + 1) / scale_factor, 0))
resized_image[i, j] = image[src_i - 1, src_j - 1]

return resized_image

# 最近邻法插值实现图像旋转
def nearest_neighbor_rotation(image, angle):
h, w, channel = image.shape
angle_rad = math.radians(angle)

# 计算旋转后的图像尺寸
cos_theta = abs(math.cos(angle_rad))
sin_theta = abs(math.sin(angle_rad))
new_w = int(h * sin_theta + w * cos_theta)
new_h = int(h * cos_theta + w * sin_theta)

# 旋转中心
cx, cy = w / 2, h / 2
new_cx, new_cy = new_w / 2, new_h / 2

rotated_image = np.zeros((new_h, new_w, channel), dtype=image.dtype)

for i in range(new_h):
for j in range(new_w):
# 将新图像坐标转换回原图像坐标
x = (j - new_cx) * math.cos(angle_rad) + (i - new_cy) * math.sin(angle_rad) + cx
y = -(j - new_cx) * math.sin(angle_rad) + (i - new_cy) * math.cos(angle_rad) + cy

# 最近邻插值
if 0 <= x < w and 0 <= y < h:
src_x = int(round(x))
src_y = int(round(y))
rotated_image[i, j] = image[src_y - 1, src_x - 1]

return rotated_image

双线性法

一维线性插值示意图

如上图所示,在一维的线性插值中,坐标轴上各点 xi-1,xi,xi+1 … 的值“两两直接相连”为线段,从而构成了一条连续的约束函数。而插值坐标点例如 x,根据约束函数其值应为 f(x)。因为每两个坐标点之间的约束函数曲线是一次线性的线段,对插值结果而言是“线性” 的,所以该方法称为线性插值。基于线性函数的特性,可以便捷地求取原图像上的两个像素点间任一待插值点的颜色值:

一维线性插值计算示意图

可以看到,图中 x0 和 x1 都是原有的坐标点,颜色值分别对应为 y0 和 y1,此时根据线性插值法约束,在 (x0, y0) 和 (x1, y1) 构成的一次函数上,颜色值未知的插值点 x的颜色值 y 即为:
$$
y=y_0+(x-x_0)\frac{y_1-y_0}{x_1-x_0}=y_0+\frac{(x-x_0)y_1-(x-x_0)y_0}{x_1-x_0}
$$
实际上,即便 x 不在 x0 与 x1 之间,该公式也成立(此时为线性外插),但图像处理中不需涉及此情形。

从一维的线性插值出发,很容易拓展到二维图像的双线性插值,通过三次一阶线性插值(本质为加权求和)获得最终结果,下图便展示了该过程的定性斜视与定量俯视示意图:

二维线性插值定性斜视示意图

二维线性插值定量俯视示意图

阅读更多

求矩阵特征值与特征向量:乘幂法及其改进算法

研究背景意义

矩阵的特征值计算虽然有比较可靠的理论方法,但是,理论方法只适合于矩阵规模很小或者只是在理论证明中起作用,而实际问题的数据规模都比较大,不太可能采用常规的理论解法。计算机擅长处理大量的数值计算,所以通过适当的数值计算理论,写成程序,让计算机处理,是一种处理大规模矩阵的方法,而且是一种好的方法。乘幂法(又称幂法)是求矩阵按模最大特征值的常用方法,其结构简单、便于使用,在实际工程中应用广泛:

  • 在数值分析和优化问题中,乘幂法可通过求解矩阵按模最大特征值来得到其谱半径,从而帮助分析迭代算法的收敛性;
  • 在物理学和工程学中,特征值问题常用于分析系统的稳定性、振动频率和模态分析,乘幂法能够有效求解系统的最大特征值,从而帮助理解系统的动态行为;
  • 在图像处理中,特征值分解用于图像压缩、特征提取和模式识别,乘幂法可用于求解图像矩阵的最大特征值,从而实现高效的图像处理算法;
  • ……

但该方法也存在一定的局限性,其只适用于求矩阵按模最大的特征值,而在实际问题中往往需要求矩阵全部特征值,如在主成分分析中需要求相关矩阵的全部特征值以确定各主成分的贡献率,在求解线性微分方程组中通过求系数矩阵的全部特征值以确定其基础解系;同时该方法在求特定矩阵(如具有一对互为相反数的按模最大特征值的矩阵等)的按模最大特征值时是不收敛的。因此,我们希望以乘幂法基本思想为出发点,在此基础上提出一些改进算法以对其进行泛化,使其能够解决更为广泛且通用的应用场景下的实际问题。

算法基本思想

设n阶矩阵A具有n个线性无关的特征向量
$$
x_1,x_2,…,x_n
$$
相应的特征值
$$
\lambda_1,\lambda_2,…,\lambda_n
$$
满足:
$$
\left|\lambda_1\right|>\left|\lambda_2\right|\geq\left|\lambda_3\right|\geq…\geq\left|\lambda_n\right|
$$
现任取一非零向量u_0,作迭代
$$
u_k=Au_{k-1}, k=0,1,2,…
$$
得到向量序列{u_k}(k=0,1,2,…)。因各特征向量线性无关,故n维向量u_0必可由他们线性表示,即:
$$
u_0=\alpha_{1}x_{1}+\alpha_{n}x_{2}+…+\alpha_{n}x_{n}
$$
显然有:
$$
\begin{aligned}u_{k}&=A^{k}v_{0}=\alpha_{1}A^{k}x_{1}+\alpha_{2}A^{k}x_{2}+\cdots+\alpha_{n}A^{k}x_{n}=\alpha_{1}\lambda_{1}^{k}x_{1}+\alpha_{2}\lambda_{2}^{k}x_{2}+\cdots+\alpha_{n}\lambda_{n}^{k}x_{n}\&=\lambda_{1}^{k}\left[\alpha_{1}x_{1}+\alpha_{2}\left(\frac{\lambda_{2}}{\lambda_{1}}\right)^{k}x_{2}+\cdots+\alpha_{n}\left(\frac{\lambda_{n}}{\lambda_{1}}\right)^{k}x_{n}\right]\end{aligned}
$$

$$
\alpha_{1} \neq 0
$$

$$
\left|\frac{\lambda_{i}}{\lambda_{1}}\right|<1,i=2,3,\cdots,n
$$
可得:
$$
\operatorname*{lim}{k\to\infty}\frac{u{k}}{\lambda_{1}^{k}}=\operatorname*{lim}{k\to\infty}\frac{\lambda{1}^{k}\left[\alpha_{1}x_{1}+\sum_{i=2}^{n}\alpha_{i}\left(\frac{\lambda_{i}}{\lambda_{1}}\right)^{k}x_{i}\right]}{\lambda_{1}^{k}}=\operatorname*{lim}{k\to\infty}\left[\alpha{1}x_{1}+\sum_{i=2}^{n}\alpha_{i}\left(\frac{\lambda_{i}}{\lambda_{1}}\right)^{k}x_{i}\right]=\alpha_{1}x_{1}
$$

$$
\operatorname*{lim}{k\to\infty}\frac{\left(u{k+1}\right){m}}{\left(u{k}\right){m}}=\operatorname*{lim}{k\to\infty}\frac{\left{\lambda_{1}^{k+1}\left[\alpha_{1}x_{1}+\sum_{i=2}^{n}\alpha_{i}\left(\frac{\lambda_{i}}{\lambda_{1}}\right)^{k+1}x_{i}\right]\right}{m}}{\left{\lambda{1}^{k}\left[\alpha_{1}x_{1}+\sum_{i=2}^{n}\alpha_{i}\left(\frac{\lambda_{i}}{\lambda_{i}}\right)^{k}x_{i}\right]\right}{m}}=\lambda{1}\frac{\left(x_{1}\right){m}}{\left(x{1}\right){m}}=\lambda{1}
$$

这表明向量序列u_k具有收敛性,其收敛速度由比值
$$
\left|\frac{\lambda_{2}}{\lambda_{1}}\right|
$$
确定,该比值越小说明收敛速度越快,比值越接近于1收敛速度就越慢。

同时,该结论表明,当k取得足够大时(在实际应用时往往认为某次迭代前后误差小于设定的误差限即满足该条件),有:
$$
u_{k}≈\lambda_{1}^{k}\alpha_{1}x_{1}, \lambda_{1}≈\frac{\left(u_{k+1}\right)}{\left(u_{k}\right)}
$$
即u_ k可近似看作特征值λ_ 1对应的特征向量(较原特征向量x_ 1而言仅乘上了有限的常数系数,其结果仍为该特征值对应的特征向量),而对应的按模最大特征值λ_ 1的估计值可由前后两次迭代的特征向量u_ k相除得到。

当矩阵的按模最大特征值是重根时,上述结论仍然成立。设λ_ 1为r重根,即:
$$
\lambda_{1}=\lambda_{2}=\cdots=\lambda_{r}
$$
且满足条件
$$
\mid\lambda_{r}\mid>\mid\lambda_{r+1}\mid\geq\cdots\geq\mid\lambda_{n}\mid
$$
则有:
$$
u_{k}=A^{k}u_{0}=\lambda_{1}^{k}\left[\sum_{i=1}^{r}\alpha_{i}x_{i}+\sum_{j=r+1}^{n}\alpha_{j}\left(\frac{\lambda_{j}}{\lambda_{1}}\right)^{k}x_{j}\right]
$$
易推得(式中(u_ k)_ m表示向量u_ k的第m个分量):
$$
\lim_{k\to\infty}\frac{u_{k}}{\lambda_{i}^{k}}=\sum_{i=1}^{^{r}}\alpha_{i}x_{i},\lim_{k\to\infty}\frac{\left(u_{k+1}\right){m}}{\left(u{k}\right){m}}=\lambda{1}
$$
与一般情况略有不同的是,此时
$$
u_{k}≈\lambda_{i}^{k}\sum_{i=1}^{^{r}}\alpha_{i}x_{i}
$$
但事实上我们并没有办法在求解之前事先预知一个矩阵是否具有r重按模最大特征值,因此在实际操作的过程中采用与一般情形相同的处理方式(即认为r=1),所得的向量序列u_k仍然收敛,不影响求解结果。

基于以上的算法原理,可以编写如下MATLAB程序,实现一般情况下矩阵按模最大特征值及其对应特征向量的计算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function calculatePowerMethod(matrixEdit, iterEdit)
% 获取用户输入的矩阵matrixEdit和最大迭代次数iterEdit
A = str2num(matrixEdit.Value); % 将字符串转换为矩阵
n = length(A);
V = rand(n,1); % 以随机方式初始化迭代向量u0
max_iter = iterEdit.Value; % 获取迭代次数

Eps = 1E-4; % 迭代精度
k = 0; % 初始迭代次数
lambda0 = 0;

% 乘幂法迭代,求得矩阵按模最大特征值lambda及其对应特征向量v
while k <= max_iter - 1
v = A * V;
[vmax, i] = max(abs(v));
lambda = v(i) / V(i);
V = v;
if abs(lambda - lambda0)<Eps
k = k + 1;
break;
end
lambda0 = lambda;
k = k + 1;
end
end

改进的乘幂法

在实际应用层面,上述的算法逻辑只在一小部分的常规矩阵上对于矩阵的按模最大特征值求解有较好效果。事实上,仅依托以上的代码逻辑进行求解往往会出现以下几大问题:

  1. 当矩阵A不具有n个线性无关的特征向量时(事先无法判断),乘幂法不适用。
  2. 当待求取的按模最大特征值abs(λ_ 1)>1时,迭代向量u_ k的各个分量可能会随着abs(λ_ 1)^k变得很大而使计算机“上溢”;而当待求取的按模最大特征值abs(λ_ 1)<1时,迭代向量u_ k的各个分量可能会随着abs(λ_ 1)^k变得很小使u_k成为零向量。
  3. 矩阵的按模最大特征值是一对相反数。
  4. 矩阵的按模最大特征值是一对共轭复数。

(上述算法中还给出了α_1≠0的假设,事实上如果不满足这一点也不影响乘幂法的成功使用。因为舍入误差的影响,在迭代某一步会产生u_k在x_1方向上的分量不为零,以后的迭代仍会收敛)

针对问题1,我们暂时无法提出具有针对性的解决方案,但后续的实际测试证明,当迭代次数k足够大时,我们针对问题3所提出的改进方案在该种情况下相比基本算法能够有更好的收敛性(收敛更快);针对问题2,我们可以通过将向量序列u_k进行规范化处理,限制向量的模在特定小范围内,防止计算机运算的上下溢出;针对问题3,我们在原有的乘幂法算法思想的基础上进行了改进,改进后的算法能够有效对原算法无法求解(不收敛)的按模最大特征值互为相反数的矩阵的按模最大特征值进行有效求解;针对问题4,我们目前还没有找到有效的解决方案。

迭代向量的归一化

设迭代向量u为非零向量,将其归一化得到向量
$$
y=\frac{u}{max(u)}
$$
其中max(u)表示向量u的模最大的分量(即向量的无穷范数)。这样的规范化会保证每一次迭代后得到的新的迭代向量的模最大分量均为1,这有效起到了限制迭代向量分量范围的作用,能够很好地解决上述提到的问题2。值得注意的是,对向量规范化的方式并不只有归一化这一种,实际上可以使用任意一种范数对向量进行规范化处理,如2范数等。可以证明,对于基于不同范数的归一化都有相同的向量序列收敛结论,下面以无穷范数为例给出基本的证明。(显然这样的规范化只是在原有的向量基础上除以了某一个常数,这并不会改变向量序列的收敛性)

取初始向量
$$
u_{0}\neq0
$$
规范化得
$$
y_{0}=\frac{u_{0}}{\max(u_{0})}
$$
构造向量序列:
$$
\begin{aligned}
&u_{1}=Ay_{0}=\frac{Au_{0}}{\max(u_{0})},
&y_{1}=\frac{u_{1}}{\max(u_{1})}=\frac{Au_{0}}{\max(Au_{0})}\
&u_{2}=Ay_{1}=\frac{A^{2}u_{0}}{\max(Au_{0})},
&y_{2}=\frac{u_{2}}{\max(u_{2})}=\frac{A^{2}u_{0}}{\max(A^{2}u_{0})}\
&……\
&u_{k}=Ay{{k-1}}=\frac{A^{k}u{0}}{\max(A^{k-1}u_{0})},
&\quad y_{k}=\frac{u_{k}}{\max(u_{k})}=\frac{A^{k}u_{0}}{\max(A^{k}u_{0})}
\end{aligned}
$$
结合乘幂法基本算法中已经证明的结论
$$
A^{k}u_{0}=u_{k}≈\lambda_{1}^{k}\alpha_{1}x_{1}
$$
则有:
$$
\lim_{k\to\infty}y_{k}=\frac{x_{1}}{\max(x_{1})},
\lim_{k\to\infty}\max(u_{k})=\lambda_{1}
$$
这表明此时y_ k可近似看作特征值λ_ 1对应的特征向量(较原特征向量x_ 1而言仅进行了归一化处理,其结果仍为该特征值对应的特征向量),而对应的按模最大特征值λ_ 1的估计值可近似看作未归一化前的迭代向量最大分量值max(u_k)。

基于以上的算法原理,可以编写如下MATLAB程序,实现归一化处理下矩阵按模最大特征值及其对应特征向量的计算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function calculatePowerMethod(matrixEdit, iterEdit)
% 获取用户输入的矩阵matrixEdit和最大迭代次数iterEdit
A = str2num(matrixEdit.Value); % 将字符串转换为矩阵
n = length(A);
V = rand(n,1); % 以随机方式初始化迭代向量u0
max_iter = iterEdit.Value; % 获取迭代次数

Eps = 1E-4; % 迭代精度
k = 0; % 初始迭代次数
lambda0 = 0;

% 乘幂法迭代,求得矩阵按模最大特征值lambda及其对应特征向量v
while k <= max_iter - 1
v = A * V;
[vmax, i] = max(abs(v));
lambda = v(i);
V = v / lambda;
if abs(lambda - lambda0)<Eps
k = k + 1;
break;
end
lambda0 = lambda;
k = k + 1;
end
end

归一化乘幂法的进一步改进

针对问题3,从其基本情形出发(其他条件与先前保持一致),即有:
$$
\mid\lambda_1\mid=\mid\lambda_2\mid>\mid\lambda_3\mid\geqslant\cdotp\cdotp\cdotp\geqslant\mid\lambda_n\mid,\lambda_1=-\lambda_2
$$
在矩阵按模最大特征值为一对相反数的情况下,原迭代向量序列中各相邻向量的比值极限发散:
$$
\lim_{k\to\infty}\frac{\boldsymbol{u}_{k+1}}{\boldsymbol{u}k}=\lambda_1\lim{k\to\infty}\frac{a_1\boldsymbol{x}_1+(-1)^{k+1}a_2\boldsymbol{x}2+\boldsymbol{\varepsilon}{k+2}}{a_1\boldsymbol{x}_1+(-1)^ka_2\boldsymbol{x}_2+\boldsymbol{\varepsilon}_k}
$$
说明在该种情况下,采用原有的乘幂法基本算法,得到的迭代向量序列并不收敛,无法得到稳定的矩阵按模最大特征值数值求解结果。

我们在原有算法的基础上进行了一定的改进,构造了新的迭代向量序列,使其对于矩阵按模最大特征值为一对相反数的情况也能保证收敛,从而可以对该情况下的矩阵按模最大特征值进行有效求解。

阅读更多