双线性插值
网上其他文章介绍的双线性插值公式比较复杂,反正我是一直没记住。今天我们从另一个角度来看待双线性插值,相信看完这篇文章之后,你自己脱离文章不对照着双线性插值公式自己就可以实现相应代码了。
双线性插值可以应用在很多地方,比如图像拼接,点云拼接,图像仿射变换等等,这里我们以图像为例介绍双线性插值。
一维线性插值
如上图所示,假设已知
P
1
P_1
P1,
P
2
P_2
P2点灰度值,求
P
′
P'
P′点灰度值。很显然,根据距离分配权重,很容易得到
P
′
P'
P′的灰度值为
P
′
=
P
1
w
1
+
P
2
w
2
=
P
1
∗
d
2
d
+
P
2
∗
d
1
d
(1)
P'=P_1w_1+P_2w_2 = P_1 * \frac{d2}{d} + P_2 * \frac{d1}{d} \tag {1}
P′=P1w1+P2w2=P1∗dd2+P2∗dd1(1)
其中,
d
d
d为
P
1
P_1
P1,
P
2
P_2
P2之间的距离。
公式(1)应该很好理解吧。双线性插值问题一般都是正向变换,即已知原始图像数据,计算经旋转平移之后的图像。即我们把问题反过来,假设已知原始图像
P
P
P点的灰度值,经仿射变换后得到的
P
′
P'
P′坐标点往往不是整数,如何计算与之最近邻的整数坐标
P
1
P_1
P1,
P
2
P_2
P2的值呢,实际上就是计算
P
′
P'
P′点对
P
1
P_1
P1,
P
2
P_2
P2分别有多少贡献。这个也很好计算吧,我们有:
{
P
1
=
P
′
∗
w
1
P
2
=
P
′
∗
w
2
(2)
\begin{cases} P_1 = P' * w_1 \\ P_2 = P' * w_2 \tag{2} \end{cases}
{P1=P′∗w1P2=P′∗w2(2)
二维双线性插值
从一维线性插值类推到二维双线性插值是很自然的事,很显然,我们计算
P
′
P'
P′点对周围4个点
P
1
P_1
P1,
P
2
P_2
P2,
P
3
P_3
P3,
P
4
P_4
P4的贡献为:
P
i
=
P
′
∗
w
i
(3)
P_i = P' * w_i \tag {3}
Pi=P′∗wi(3)
其中,
w
i
w_i
wi是
P
′
P'
P′对
P
i
P_i
Pi贡献的权重,比如对
P
1
P_1
P1的贡献权重就是
w
1
=
s
3
/
s
w_1=s_3/s
w1=s3/s,其中,s是4个顶点围城的矩形面积,
s
3
s_3
s3是
P
′
P'
P′点与
P
3
P_3
P3点围城的矩形面积。
好了,到这里双线性插值介绍完了,公式很简单吧,不会记不住吧🤭,就算记不住,仔细想想类比下一维线性插值应该也可以自己推导出来这个公式(3)吧。
点云、图像拼接
这里我把点云和图像拼接放到一起讨论,其实原理都一样,都是利用双线性插值把原图映射到待拼接的大图上而已。
假设我们已经获取了 n n n张图像相对于某个坐标系的旋转和平移矩阵,现在的需求就是把这 n n n张图映射到这个坐标系下拼接在一起。
假设原始图像坐标
P
(
i
,
j
)
P(i, j)
P(i,j)经旋转平移后的坐标为
P
′
(
i
′
+
α
,
j
′
+
β
)
P'(i'+\alpha, j' + \beta)
P′(i′+α,j′+β),其中,
i
′
,
j
′
i', j'
i′,j′均是整数,
α
,
β
\alpha, \beta
α,β为小数。则围绕
P
′
P'
P′点的最近邻的4个点分别为
{
P
1
′
(
i
′
,
j
′
)
,
P
2
′
(
i
′
+
1
,
j
′
)
,
P
3
′
(
i
′
+
1
,
j
′
+
1
)
,
P
4
′
(
i
′
,
j
′
+
1
)
\begin{cases} P_1'(i', j'),\\ P_2'(i'+1, j'),\\ P_3'(i'+1, j' + 1), \\ P_4'(i', j'+1) \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧P1′(i′,j′),P2′(i′+1,j′),P3′(i′+1,j′+1),P4′(i′,j′+1)
利用公式(3)即可得到4个点的灰度值。
到这里还有一个问题就是公式(3)描述的只是单张图片旋转平移,如果是多张图片拼接,由上图可知,不仅仅 P ′ P' P′对 P 1 P_1 P1有贡献, P ′ ′ P'' P′′对 P 1 P_1 P1也有贡献。所以,最终, P 1 P_1 P1的灰度值变为:
P
1
′
=
∑
i
=
0
k
P
i
′
∗
w
i
(4)
P_1' = \sum_{i = 0}^{k} {P_i'*w_i} \tag{4}
P1′=i=0∑kPi′∗wi(4)
即
P
1
P_1
P1点的灰度值有k张图像加权求和,最后,我们对
P
1
P_1
P1点灰度值求加权平均即可。
P 1 = P 1 ′ ∑ w i (5) P_1 = \frac{P_1'}{\sum w_i} \tag{5} P1=∑wiP1′(5)
图像拼接过程总结一下就是:
- 提前获取待拼接图像的旋转平移矩阵;
- 提前分配好拼接大图内存,大图权重内存;
- 计算待拼接图像旋转平移后在大图中的坐标,按公式(4)计算4个最近邻点的灰度值累加和;
- 最终按公式(5)计算大图加权平均。
拼接缝
按上面的方式拼接多张图像,理想情况下是没问题的,但是绝大部分情况下,由于不同角度拍摄的图案亮度不均匀,或者不同相机曝光参数不一致,在图像与图像重合区域总能看到明显的过度拼接缝,并且在重合过度区域有明显的亮暗变化,如下图所示:
解决这个问题的办法一般网上给的方法就是如果能精确计算出拼接图像重合区域,在重合区域在重新计算加权平均,远离重合区域的给一个较小的权重,靠近重合区域中心的给一个较大的权重。
这个方法有两个很大的问题:
- 图像重合区域很难计算出来;
- 如果重合区只有2张图片那还好,如果有n张图片都对某个重合区域有贡献,那上面的这个方法就有问题了。
不过受此启发,我们提出的一个解决办法就是不考虑重合区域,给每张待拼接的小图分配一个权重,距离图像中心的给最大权重,远离图像中心的给小权重,最终小的权重图像金字塔模型,如下图所示:
这样,公式(4)可改写为:
P 1 ′ = ∑ i = 0 k P i ′ ∗ w i ∗ w s i (6) P_1'= \sum_{i = 0}^{k} {P_i'*w_i * w_{si}} \tag{6} P1′=i=0∑kPi′∗wi∗wsi(6)
其中, w s i w_{si} wsi是每张待拼接小图权重,可提前预分配好,每张图小图权重都是一样的。
下面是我拼接的一些3D点云数据:
从以上可看出,拼接缝已经消除了,并且不同图像之间的灰度过度特别自然,没有明显的灰度突变。
这个是2D图片拼接,由于项目现场没有标定板,我用一把直尺作为参照物,把4张图片拼接起来,效果也是很好的,拼接大图看不到明显的灰度过度。这个拼接有一点点重影,这个主要是因为我没有标定板,不同相机之间的平移距离是直接用尺子测量的,直尺的测量精度只有毫米级别,所以相机之间的平移距离肯定有误差。