将坚持不懈的降落镜头重新注册到卫星图像上

2021-03-14 11:51:38

火星2020的着陆仍然是世界上的持久性漫游者。下降的令人惊叹的镜头展示了序列的每个阶段。如果你还没有看到它,你已经可以在这里观看。

我发现卓越的一件事是Martianterrain的自我相似性。由于着陆器朝着地面下降,因此很难获得规模的锐阵,因为没有熟悉的参考框架,告诉我们地面有多遥远。这让我踏上了一个项目,其中将镜头从火星表达轨道器中获得的卫星图像上,以及一个规模,告诉我们实际上的地面有多大的功能是:

在这篇文章中,我将解释我如何使用Python,OpenCV,PyTorch,AndBlender进行上述镜头。

生成我的视频涉及将每个帧与卫星图像相结合的原始素材Sothat的框架扭曲。常用方式的方式:

找到一个数学函数,将第一个图像中的点映射到第二个图像中的那些。

在此OpenCV教程中描述了实现上述的详细信息,但我将总结此过程。

左侧打破这一点,是我们希望对齐的视频的帧,在右边的参考卫星图像:

首先,我们使用OpenCV的规模不变功能转换(SIFT)键点Detector从图像中拔出突出关键点:

这里的每个红十字会都标记了由截图算法确定的可能“有趣”点。与每个点相关联(但未示出)是128Values的矢量,它描述了围绕关键点的图像的一部分。 TheIDEA是该描述符是不变的,比例(作为名称阶段),旋转和点亮差异。然后,我们可以匹配具有类似描述符的图像中的点数:

现在我们已经找到了关键点对,下一步是找到从视频帧将关键点映射到卫星图像的相应关键点。为此,我们利用了一类众多转型的历史投射转换。可以使用投影变换,以便在从这些距离的不同位置和角度对我们有用的位置和角度进行观察时,将平面上的固定点改变明显位置。这假设相机符合直线透视投影(即没有透镜失真),这似乎是这种情况。

投影转换由3x3矩阵\(m \)表示。要将此类Atransformation应用于2D点\(v \),我们首先将A 1附加到给出3向量,然后由矩阵管道:

\ [v' = m \ begin {bmatrix} v_x \\ v_y \\ 1 \ neg {bmatrix} \]返回2d点,结果由ITSThird元素划分,并截断回2向量:

\ [v_ \ text {projected} = \ begin {bmatrix} v' _x / v' _z \\ v' _y / v' _z \ end {bmatrix} \]这可以是可视化的byplotting z = 1平面上的点,将变换应用,然后对每个点朝向原点,回到z = 1平面:

当我们谈论撰写投影转换时,我们实际做的是Multiply依赖底层矩阵:投影变换具有两个转换的组成等于由各自矩阵的矩阵产物的突出变换。写象征性的书面可以写成

\ [\ forall x \ in \ mathbb {r} ^ 2 \ \ colon \ p_ {m_1}(p_ {m_2}(x))= p_ {m_1 m_2}(x)\]找到转换使用RANSAC完成方法。有关Ransac的更多详情,请参阅我的Pluto Flyby Post。

一旦我们对每个帧进行了转换,我们就可以恢复卫星图像的参考帧的每个视频框架,从而获得稳定的视图。

不幸的是,不仅仅是重复对每个帧的上述过程的情况,以便产生完整的视频,因为该算法不能为每个帧拓展足够的对应关系。

为了解决这个问题,我们还寻找视频弗拉梅姆之间的变换。如果一个帧没有直接转换链接到卫星图像,但我们确实将其与另一个自身连接到卫星图像的帧的转换,然后我们可以简单地将两个转换映射到映射到原始帧卫星景观。

因此,我将每三十帧(即,每秒一帧)标记为“关键帧”,然后彻底搜索每对keyframe之间的变换。对于我搜索的剩余帧,用于转换为最新帧。

这导致具有每帧一个节点的相当密集的图表,并且找到了一个边缘变形。这是一个简化的例子,每个5帧的关键帧而不是每30个:

卫星节点到特定帧节点的任何路径都表示转换的链条,当组合时将帧映射到SatelliteView上。

我们将首先选择每个节点的一条路径。卫星节点的宽度优先考虑卫星节点将为每个帧提供一条路径,而alsoguarteeing是最短的:

虽然上述方法产生了一个不错的重点,但它并不完美。当最短路径更改时,临时清除模式会切换。

如果我们纳入所有通信,而不仅仅是那些在最短路径上的通信,这提供了更多信息并导致更平滑和更高的ComitateTrans。

为此,我写了一个丢失函数,返回总重注错误,给定每个图像的卫星相对转换:

def项目(v):#投影到平面上z = 1返回v / v [..., - 1] [...,无] def丢失(frame_transforms,src_pts,dst_pts,src_idx,dst_idx):m_src_inv =火炬。逆(frame_transform)[src_idx] m_dst = frame_transforms [dst_idx] ref_pts =火炬。 einsum(' nij,nj-> ni',m_src_inv,src_pts)reprojected_dst_pts =项目(火炬。einsum(' nij,nj-> ni' m_dst,ref_pts)返回火炬 。 dist(reprojected_dst_pts,dst_pts)

src_pts和dst_pts都是n x 3阵列,代表数据集中的每对点。 Frame_Transforms是表示候选变换的M x 3 x 3阵列,m是视频中的帧数。 Frame_Transforms是相对于卫星图像的,这就是用Frame_Transforms变换时卫星图像的卫星图像[i]框架I中的对应点。

由于每帧多点对,因此SRC_IDX和DST_IDX将每个点对的每一半映射到相应的视频帧。

丢失函数通过从每对的第一点拍摄第一点,将映射回到卫星图像的参考框架,然后将它们映射到第二图像的参考框架。通过精确的帧变换和富合作用的对应关系,这些变换的点应该非常接近对应的第二组第二点。损失功能的最后一行释放了恢复的首发和(未改性)第二点之间的欧几里德距离(平方和)。这个想法是,如果我们发现一组具有较低损失的框架,那么我们将有一个更准确的OFFRANSEMATIONS。

使用火炬写入损失。火炬是一种自动化的框架,具有用于应用渐变(在其他内容中)的功能。这样,我们可以使用它来迭代地改善我们的Frame_Transforms:

src_pts,dst_pts,src_idx,dst_idx = dataset frame_transforms = initial_frame_transforms Optim =火炬。 Optim。 adam([frame_transforms],lr = 1e-5),而true:Optim。 zero_grad()l =损失(frame_transforms,src_pts,dst_pts,src_idx,dst_idx)l。倒退()Optim。步 ()

数据集是由该组对应关系构建的,并且initial_frame_transforms是衍生自组合转换的最短路径的字母。

运行此循环后,我们获取每个帧的最终变换集。这会产生更稳定的转换:

要生产最终视频,我使用3D建模和呈现应用程序搅拌机。我使用blender'srich python脚本界面来为quad设置一个Quad,其角落遵循其中的视频的角落。为了获得闪贷的Shader System的Quad的正确纹理:

通常,着色器系统决定了表面上的特定点应该是阴影的,这通常是光线,视图方向,表面的函数的函数。在这里,我以一种非常简单的方式使用它,它会在3D空间中赋予Quad的点应该是什么颜色的颜色。

拍摄点的位置彩色,并更换Z分量A 1.这是通过附加一个将2-向量迁移到3向量中的投影变换的第一阶段。

通过由此处显示的常量定义的矩阵乘以该3矢量。事实上,这是一个动画,以便在任何给定的帧上这些显示Frame_Transforms [Frame_Num]。

此时,坐标在视频帧中的像素方面。然而,随着下一阶段需要它们在0到1的范围内,因此在此处划分视频宽度和高度。

我使用了许多卫星图像而不是一个。但是,我指定了“参考帧”(即,具有身份转换的帧)和其余的帧,就好像它们是视频键帧一样。

在视频的早期部分期间,流动站的热屏幕是可见的。没有Intervelion,一些帧对应关系跟踪热屏幕(这是本身的移动)而不是地形,导致跟踪不良。因此,我将一些关键点从特定帧上的热屏幕中手术解压缩,同时与至少一个HeatsheID'SkyyPoints类似的关键点。

很少,找到退化的帧对应关系。当所有匹配标准点都处于一行中,您可以获得与旋转的多个解决方案。即使匹配的关键点不完全在一行中但areClose中,也可以不准确地进行变换。有一种这样的imagepair在我的视频中导致了这个问题,我手动排除在外。

我已经表明,缺口Rover的镜头可以达到并与参考卫星图像进行束缚和对齐。虽然我对结果很满意,但它肯定有助于将上下文放在原始镜头上,而且可以改善它可以改进的方式,例如,在视频的早期部分,没有许多筛选的关键点。这表明了在跟踪中的贱原。也许用不同的关键点进行实验将产生更多可用的关键点。

还可以解决我在这里尚未开发的问题的方法。 例如,问题与通用稳定化的问题非常相似。 也许我可以使用现成的求助主者来实现一致的效果。