双线性图像插值/缩放 - 计算示例
Bilinear image interpolation / scaling - A calculation example
我想问你一些双线性插值/缩放的细节。假设我们有这个矩阵:
|100 | 50 |
|70 | 20 |
这是一张 2 x 2 灰度图像。现在,我想将它缩放为两倍,我的矩阵如下所示:
| 100 | f1 | 50 | f2 |
| f3 | f4 | f5 | f6 |
| 70 | f7 | 20 | f8 |
所以如果我们想计算f4
,计算定义为
f1 = 100 + 0.5(50 - 100) = 75
f7 = 70 + 0.5(20 - 70) = 45
现在终于:
f4 = 75 + 0.5(45 - 75) = 60
但是,我真的无法理解 f3 或 f1
的正确计算方法
我们是否分别在每个方向上进行双线性缩放?因此,这意味着:
f3 = 100 + 0.5(70 - 100) = 85
f1 = 100 + 0.5(50 - 100) = 75
还有,我应该怎么对待f2,f6,f8。这些点是否像最近邻算法中那样简单地被复制?
我想向您指出来自维基百科的这张非常有见地的图表,它说明了如何对一个点进行双线性插值:
来源:Wikipedia
如您所见,四个红点是已知的。这些点您事先知道,P
是我们希望插入的点。因此,我们必须执行两个步骤(正如您在 post 中指出的那样)。要处理 x
坐标(水平),我们必须计算顶行红点和底行红点的插值是多少行。这导致两个蓝点 R1
和 R2
。为了处理 y
坐标(垂直),我们使用两个蓝色点并垂直插值以获得最终的 P
点。
当你调整图像大小时,即使我们看不到我要说的内容,但可以想象这个图像是一个 3D 信号 f
.矩阵中的每个点实际上是一个 3D 坐标,其中列位置是 x
值,行位置是 y
值,z
值是数量/灰度值矩阵本身。因此,做z = f(x,y)
就是矩阵中(x,y)
位置的矩阵的值。在我们的例子中,因为您处理的是图像,所以 (x,y)
的每个值都是从 1 到 rows/columns 的整数,具体取决于您正在查看的维度。
因此,给定要在 (x,y)
处插值的坐标,并给定上图中的红色坐标,我们根据图表将其称为 x1,y1,x2,y2
- 具体遵循约定图表和引用图像的访问方式:x1 = 1, x2 = 2, y1 = 2, y2 = 1
,蓝色坐标 R1
和 R2
是通过一维插值列计算的,使用同一行,两个点重合:
R1 = f(x1,y1) + (x - x1)/(x2 - x1)*(f(x2,y1) - f(x1,y1))
R2 = f(x1,y2) + (x - x1)/(x2 - x1)*(f(x2,y2) - f(x1,y2))
重要的是要注意 (x - x1) / (x2 - x1)
是 权重/比例 表示输出包含在 [=37= 处看到的两个值之间的多少混合] 和 f(x2,y1)
用于 R1
或 f(x1,y2)
和 f(x2,y2)
用于 R2
。具体来说,x1
是起点,(x2 - x1)
是 x
值的差异。您可以验证将 x1
替换为 x
得到 0,而将 x2
替换为 x
得到 1。此权重在计算所需的 [0,1]
之间波动上班。
需要注意的是,图片原点在左上角,所以(1,1)
在左上角。一旦找到 R1
和 R2
,我们可以通过按行插值找到 P
:
P = R2 + (y - y2)/(y2 - y1)*(R1 - R2)
同样,(y - y2) / (y2 - y1)
表示 R1
和 R2
对最终输出 P
的贡献比例/混合。因此,您正确计算了 f5
,因为您使用了四个已知点:左上角为 100,右上角为 50,左下角为 70,右下角为 20。具体来说,如果您想计算 f5
,这意味着 (x,y) = (1.5,1.5)
因为我们在 100 和 50 之间,因为您将图像缩放了两倍。如果将这些值代入上述计算,您将得到预期的值 60。两次计算的权重也将导致 0.5
,这是您在计算中得到的结果,也是我们所期望的。
如果你计算f1
,这对应于(x,y) = (1.5,1)
,如果你将其代入上面的等式,你会看到(y - y2)/(y2 - y1)
给你0或者权重为0,所以计算的只是 R2
,仅对应于沿顶行的线性插值。同样,如果我们计算 f7
,这意味着我们想要在 (x,y) = (1.5,2)
处进行插值。在这种情况下,您会看到 (y - y2) / (y2 - y1)
为 1 或权重为 1,因此 P = R2 + (R1 - R2)
,这简化为 R1
并且仅是沿底行的线性插值。
现在有 f3
和 f5
的情况。它们分别对应于 (x,y) = (1,1.5)
和 (x,y) = (2,1.5)
。将这些值替换为 R1
和 R2
以及 P
两种情况给出:
f3
R1 = f(1,2) + (1 - 1)/(2 - 1)*(f(2,2) - f(1,2)) = f(1,2)
R2 = f(1,1) + (1 - 1)/(2 - 1)*(f(1,2) - f(1,1)) = f(1,1)
P = R1 + (1.5 - 1)*(R1 - R2) = f(1,2) + 0.5*(f(1,2) - f(1,1))
P = 70 + 0.5*(100 - 70) = 85
f5
R1 = f(1,2) + (2 - 1)/(2 - 1)*(f(2,2) - f(1,2)) = f(2,2)
R2 = f(1,1) + (2 - 1)/(2 - 1)*(f(1,2) - f(1,1)) = f(1,2)
P = R1 + (1.5 - 1)*(R1 - R2) = f(2,2) + 0.5*(f(2,2) - f(1,2))
P = 20 + 0.5*(50 - 20) = 35
那么这告诉我们什么?这意味着您仅在 沿 y 方向 进行插值。当我们查看 P
时,这一点很明显。更彻底地检查 P
对 f3
和 f5
的计算,您会发现我们只考虑垂直方向的值。
因此,如果您想要一个明确的答案,f1
和 f7
是通过仅沿同一行沿 x
/ 列方向插值找到的. f3
和 f5
是通过沿同一列插值 y
/ 行方向找到的。如您所见,f4
使用 f1
和 f7
的混合来计算最终值。
为了回答你最后一个问题,f2
、f6
和f8
根据个人喜好填写。这些值被认为是越界的,x
和 y
值都是 2.5
,并且在 (x,y)
的 [1,2]
网格之外。在 MATLAB 中,默认实现是将定义边界之外的任何值填充为非数字 (NaN
),但有时,人们会使用线性插值进行外推、复制边界值或执行一些操作精致的填充,如对称或圆形填充。这取决于你所处的情况,但是关于如何填写 f2
、f6
和 f8
没有正确和明确的答案——这完全取决于你的应用程序和什么使对你来说最有意义。
作为奖励,我们可以在 MATLAB 中验证我的计算是否正确。我们首先在 [1,2]
范围内定义一个 (x,y)
点的网格,然后调整图像大小,使其在我们指定每点 0.5 分辨率而不是 1 分辨率的情况下放大两倍。我要调用您定义的矩阵 A
:
A = [100 50; 70 20]; %// Define original matrix
[X,Y] = meshgrid(1:2,1:2); %// Define original grid of points
[X2,Y2] = meshgrid(1:0.5:2.5,1:0.5:2.5) %// Define expanded grid of points
B = interp2(X,Y,A,X2,Y2,'linear'); %// Perform bilinear interpolation
原始 (x,y)
点网格如下所示:
>> X
X =
1 2
1 2
>> Y
Y =
1 1
2 2
将矩阵的大小扩大两倍的扩展网格如下所示:
>> X2
X2 =
1.0000 1.5000 2.0000 2.5000
1.0000 1.5000 2.0000 2.5000
1.0000 1.5000 2.0000 2.5000
1.0000 1.5000 2.0000 2.5000
>> Y2
Y2 =
1.0000 1.0000 1.0000 1.0000
1.5000 1.5000 1.5000 1.5000
2.0000 2.0000 2.0000 2.0000
2.5000 2.5000 2.5000 2.5000
B
是使用 X
和 Y
作为点的原始网格的输出, X2
和 Y2
是我们要插值的点在.
我们得到:
>> B
B =
100 75 50 NaN
85 60 35 NaN
70 45 20 NaN
NaN NaN NaN NaN
我想问你一些双线性插值/缩放的细节。假设我们有这个矩阵:
|100 | 50 |
|70 | 20 |
这是一张 2 x 2 灰度图像。现在,我想将它缩放为两倍,我的矩阵如下所示:
| 100 | f1 | 50 | f2 |
| f3 | f4 | f5 | f6 |
| 70 | f7 | 20 | f8 |
所以如果我们想计算f4
,计算定义为
f1 = 100 + 0.5(50 - 100) = 75
f7 = 70 + 0.5(20 - 70) = 45
现在终于:
f4 = 75 + 0.5(45 - 75) = 60
但是,我真的无法理解 f3 或 f1
的正确计算方法我们是否分别在每个方向上进行双线性缩放?因此,这意味着:
f3 = 100 + 0.5(70 - 100) = 85
f1 = 100 + 0.5(50 - 100) = 75
还有,我应该怎么对待f2,f6,f8。这些点是否像最近邻算法中那样简单地被复制?
我想向您指出来自维基百科的这张非常有见地的图表,它说明了如何对一个点进行双线性插值:
来源:Wikipedia
如您所见,四个红点是已知的。这些点您事先知道,P
是我们希望插入的点。因此,我们必须执行两个步骤(正如您在 post 中指出的那样)。要处理 x
坐标(水平),我们必须计算顶行红点和底行红点的插值是多少行。这导致两个蓝点 R1
和 R2
。为了处理 y
坐标(垂直),我们使用两个蓝色点并垂直插值以获得最终的 P
点。
当你调整图像大小时,即使我们看不到我要说的内容,但可以想象这个图像是一个 3D 信号 f
.矩阵中的每个点实际上是一个 3D 坐标,其中列位置是 x
值,行位置是 y
值,z
值是数量/灰度值矩阵本身。因此,做z = f(x,y)
就是矩阵中(x,y)
位置的矩阵的值。在我们的例子中,因为您处理的是图像,所以 (x,y)
的每个值都是从 1 到 rows/columns 的整数,具体取决于您正在查看的维度。
因此,给定要在 (x,y)
处插值的坐标,并给定上图中的红色坐标,我们根据图表将其称为 x1,y1,x2,y2
- 具体遵循约定图表和引用图像的访问方式:x1 = 1, x2 = 2, y1 = 2, y2 = 1
,蓝色坐标 R1
和 R2
是通过一维插值列计算的,使用同一行,两个点重合:
R1 = f(x1,y1) + (x - x1)/(x2 - x1)*(f(x2,y1) - f(x1,y1))
R2 = f(x1,y2) + (x - x1)/(x2 - x1)*(f(x2,y2) - f(x1,y2))
重要的是要注意 (x - x1) / (x2 - x1)
是 权重/比例 表示输出包含在 [=37= 处看到的两个值之间的多少混合] 和 f(x2,y1)
用于 R1
或 f(x1,y2)
和 f(x2,y2)
用于 R2
。具体来说,x1
是起点,(x2 - x1)
是 x
值的差异。您可以验证将 x1
替换为 x
得到 0,而将 x2
替换为 x
得到 1。此权重在计算所需的 [0,1]
之间波动上班。
需要注意的是,图片原点在左上角,所以(1,1)
在左上角。一旦找到 R1
和 R2
,我们可以通过按行插值找到 P
:
P = R2 + (y - y2)/(y2 - y1)*(R1 - R2)
同样,(y - y2) / (y2 - y1)
表示 R1
和 R2
对最终输出 P
的贡献比例/混合。因此,您正确计算了 f5
,因为您使用了四个已知点:左上角为 100,右上角为 50,左下角为 70,右下角为 20。具体来说,如果您想计算 f5
,这意味着 (x,y) = (1.5,1.5)
因为我们在 100 和 50 之间,因为您将图像缩放了两倍。如果将这些值代入上述计算,您将得到预期的值 60。两次计算的权重也将导致 0.5
,这是您在计算中得到的结果,也是我们所期望的。
如果你计算f1
,这对应于(x,y) = (1.5,1)
,如果你将其代入上面的等式,你会看到(y - y2)/(y2 - y1)
给你0或者权重为0,所以计算的只是 R2
,仅对应于沿顶行的线性插值。同样,如果我们计算 f7
,这意味着我们想要在 (x,y) = (1.5,2)
处进行插值。在这种情况下,您会看到 (y - y2) / (y2 - y1)
为 1 或权重为 1,因此 P = R2 + (R1 - R2)
,这简化为 R1
并且仅是沿底行的线性插值。
现在有 f3
和 f5
的情况。它们分别对应于 (x,y) = (1,1.5)
和 (x,y) = (2,1.5)
。将这些值替换为 R1
和 R2
以及 P
两种情况给出:
f3
R1 = f(1,2) + (1 - 1)/(2 - 1)*(f(2,2) - f(1,2)) = f(1,2)
R2 = f(1,1) + (1 - 1)/(2 - 1)*(f(1,2) - f(1,1)) = f(1,1)
P = R1 + (1.5 - 1)*(R1 - R2) = f(1,2) + 0.5*(f(1,2) - f(1,1))
P = 70 + 0.5*(100 - 70) = 85
f5
R1 = f(1,2) + (2 - 1)/(2 - 1)*(f(2,2) - f(1,2)) = f(2,2)
R2 = f(1,1) + (2 - 1)/(2 - 1)*(f(1,2) - f(1,1)) = f(1,2)
P = R1 + (1.5 - 1)*(R1 - R2) = f(2,2) + 0.5*(f(2,2) - f(1,2))
P = 20 + 0.5*(50 - 20) = 35
那么这告诉我们什么?这意味着您仅在 沿 y 方向 进行插值。当我们查看 P
时,这一点很明显。更彻底地检查 P
对 f3
和 f5
的计算,您会发现我们只考虑垂直方向的值。
因此,如果您想要一个明确的答案,f1
和 f7
是通过仅沿同一行沿 x
/ 列方向插值找到的. f3
和 f5
是通过沿同一列插值 y
/ 行方向找到的。如您所见,f4
使用 f1
和 f7
的混合来计算最终值。
为了回答你最后一个问题,f2
、f6
和f8
根据个人喜好填写。这些值被认为是越界的,x
和 y
值都是 2.5
,并且在 (x,y)
的 [1,2]
网格之外。在 MATLAB 中,默认实现是将定义边界之外的任何值填充为非数字 (NaN
),但有时,人们会使用线性插值进行外推、复制边界值或执行一些操作精致的填充,如对称或圆形填充。这取决于你所处的情况,但是关于如何填写 f2
、f6
和 f8
没有正确和明确的答案——这完全取决于你的应用程序和什么使对你来说最有意义。
作为奖励,我们可以在 MATLAB 中验证我的计算是否正确。我们首先在 [1,2]
范围内定义一个 (x,y)
点的网格,然后调整图像大小,使其在我们指定每点 0.5 分辨率而不是 1 分辨率的情况下放大两倍。我要调用您定义的矩阵 A
:
A = [100 50; 70 20]; %// Define original matrix
[X,Y] = meshgrid(1:2,1:2); %// Define original grid of points
[X2,Y2] = meshgrid(1:0.5:2.5,1:0.5:2.5) %// Define expanded grid of points
B = interp2(X,Y,A,X2,Y2,'linear'); %// Perform bilinear interpolation
原始 (x,y)
点网格如下所示:
>> X
X =
1 2
1 2
>> Y
Y =
1 1
2 2
将矩阵的大小扩大两倍的扩展网格如下所示:
>> X2
X2 =
1.0000 1.5000 2.0000 2.5000
1.0000 1.5000 2.0000 2.5000
1.0000 1.5000 2.0000 2.5000
1.0000 1.5000 2.0000 2.5000
>> Y2
Y2 =
1.0000 1.0000 1.0000 1.0000
1.5000 1.5000 1.5000 1.5000
2.0000 2.0000 2.0000 2.0000
2.5000 2.5000 2.5000 2.5000
B
是使用 X
和 Y
作为点的原始网格的输出, X2
和 Y2
是我们要插值的点在.
我们得到:
>> B
B =
100 75 50 NaN
85 60 35 NaN
70 45 20 NaN
NaN NaN NaN NaN