主要内容

利用点特征匹配实现视频稳定

这个例子展示了如何稳定从一个抖动的平台上捕获的视频。稳定视频的一种方法是跟踪图像中的一个显著特征,并将其作为一个定位点来消除与它相关的所有扰动。然而,这一过程必须通过了解第一个视频帧中该显著特征的位置来引导。在这个例子中,我们探索了一种视频稳定的方法,没有任何这样的工作先天的知识。相反,它会自动搜索视频序列中的“背景平面”,并使用其观测到的失真来纠正摄像机的运动。

该稳定算法包括两个步骤。首先,我们确定仿射图像变换之间的所有相邻帧的视频序列使用estimateGeometricTransform2D用于两个图像之间点对应的函数。第二,我们扭曲视频帧以实现稳定的视频。我们将使用计算机视觉工具箱™,用于算法和显示。

步骤1。从电影文件中读取帧

这里我们读取一个视频序列的前两帧。我们将它们作为强度图像读取,因为颜色对于稳定算法是不必要的,而且使用灰度图像可以提高速度。下面我们将这两个帧并排显示,并生成一个红青色合成来说明它们之间的像素级差异。两帧之间明显有很大的垂直和水平偏移。

文件名=“shaky_car.avi”;hVideoSrc = VideoReader(文件名);imgA = rgb2gray (im2single (readFrame (hVideoSrc)));%读取第一帧到imgAimgB = rgb2gray (im2single (readFrame (hVideoSrc)));%读取第二帧到imgB图;imshowpair (imgA imgB,“蒙太奇”);标题([“帧”repmat (' '[70]),B帧的]);

图;imshowpair (imgA imgB,“ColorChannels”“red-cyan”);标题(颜色合成(框架A =红色,框架B =青色));

步骤2。收集每一帧的突出点

我们的目标是确定一个转换,将纠正两帧之间的失真。我们可以使用estimateGeometricTransform2D函数,它将返回一个仿射变换。作为输入,我们必须为这个函数提供两帧之间的点对应集合。为了生成这些对应关系,我们首先从两个帧中收集感兴趣的点,然后在它们之间选择可能的对应关系。

在这一步中,我们为每一帧生成这些候选点。为了有最好的机会让这些点在另一帧中有相应的点,我们希望在图像显著特征(如角)周围有点。为此,我们使用detectFASTFeatures函数,实现了最快的角点检测算法之一。

两帧检测到的点如下图所示。观察它们中有多少覆盖相同的图像特征,比如沿着林木线的点,大型路标的角落,以及汽车的角落。

ptThresh = 0.1;pointsA = detectFASTFeatures (imgA,“MinContrast”, ptThresh);pointsB = detectFASTFeatures (imgB,“MinContrast”, ptThresh);%显示图像A和图像B中的角图;imshow (imgA);持有;情节(pointsA);标题(在一个角落的);

图;imshow (imgB);持有;情节(pointsB);标题(“B角落”);

步骤3。选择点之间的对应关系

接下来,我们选择上面推导的点之间的对应关系。对于每个点,我们提取一个快速视网膜关键点(FREAK)描述符围绕它。由于FREAK描述符是二进制的,所以我们在点之间使用的匹配代价是汉明距离。帧A和帧B中的点被假定匹配。请注意,没有唯一性约束,所以帧B中的点可以对应帧A中的多个点。

提取怪物描述符的角落[featuresA, pointsA] = extractFeatures(imgA, pointsA);[featuresB, pointsB] = extractFeatures(imgB, pointsB);

匹配在当前帧和前一帧中发现的特征。由于怪物描述符是二进制的,所以matchFeatures函数使用汉明距离来寻找相应的点。

indexPairs = matchFeatures(featuresA, featuresB);pointsA = pointsA(indexPairs(:, 1),:);indexPairs(:, 2),:);

下图显示的是与上面相同的颜色合成,但添加了来自框架A的红色点和来自框架B的绿色点。点与点之间用黄线表示由上述程序选择的对应关系。这些通信中有许多是正确的,但也有大量的异常值。

图;showMatchedFeatures(imgA, imgB, pointsA, pointtsb);传奇(“一个”“B”);

步骤4。从噪声通信中估计变换

在前一步中获得的许多点对应是不正确的。但是我们仍然可以使用M-estimator SAmple Consensus (MSAC)算法得到两个图像之间的几何变换的稳健估计,这是RANSAC算法的变体。MSAC算法的实现estimateGeometricTransform2D函数。这个函数,当给定一组点对应时,将搜索有效的内对应。然后从这些推导出仿射变换,使第一组点的内嵌线与第二组点的内嵌线匹配得最接近。这个仿射变换将是如下形式的3 × 3矩阵:

(a_1 a_3 0;a₂a_4 0;t_x t_y 1]

的参数 一个 定义变换的缩放、旋转和剪切效果,而参数 t 是翻译参数。这个变换可以用来扭曲图像,这样它们对应的特征将被移动到相同的图像位置。

仿射变换的一个限制是它只能改变成像平面。因此,它不适用于寻找3d场景的两帧之间的一般失真,比如从移动的汽车上拍摄的视频。但它确实在某些条件下起作用,我们将很快描述这些条件。

[tform, inlierIdx] = estimategeometritransform2d (...pointsB pointsA,仿射的);pointsBm = pointsB(inlierIdx,赋值);pointtsam = pointsA(inlierIdx,赋值);imgBp = imwarp(imgB, tform,“OutputView”imref2d(大小(imgB)));pointsBmp = transformPointsForward(tform, pointsBm.Location);

下面是一个彩色合成显示帧a与重新投影的帧B重叠,以及重新投影的点对应。结果非常好,内部对应几乎完全一致。两张照片的核心对齐得很好,以至于红青色的合成图在那个区域几乎变成纯黑白。

注意,内部的对应关系都是在图像的背景中,而不是在前景中,前景本身没有对齐。这是因为背景特征足够遥远,它们的行为就好像它们在一个无限遥远的平面上。因此,即使仿射变换仅限于改变成像平面,在这里这足以对齐两幅图像的背景平面。此外,如果我们假设背景平面在帧间没有明显移动或改变,那么这个变换实际上是捕捉相机运动。因此,纠正这将稳定视频。只要摄像机在帧间的运动足够小,或者相反,如果视频帧率足够高,这个条件就会保持。

图;showMatchedFeatures(imgA, imgBp, pointsAm, pointsBmp);传奇(“一个”“B”);

第5步。变换逼近与平滑

给定一组视频帧 T 0 1 2 ... ,我们现在可以使用上述程序来估计所有帧之间的失真 T T + 1 仿射变换, H .即帧的累积畸变 相对于第一帧的将是所有前面的帧间变换的乘积,或

H c u u l 一个 t v e H j 0 - 1

我们可以使用上述仿射变换的所有六个参数,但是,为了数值的简单和稳定性,我们选择将矩阵重新拟合为一个更简单的比例-旋转-平移变换。与完全仿射变换的6个自由参数相比,它只有4个自由参数:一个比例因子、一个角度和两个平移。这个新的变换矩阵的形式是:

[s * cos (ang) s * sin (ang) 0;* sin (ang) s * cos (ang) 0;t_x t_y 1]

下面我们通过拟合上面得到的变换来展示这个转换过程 H 使用缩放-旋转-平移等效函数, H 年代 R t .为了表明变换的误差是最小的,我们用这两种变换重新投影帧B,并显示下面的两幅图像为红青色合成图。由于图像呈现黑白,很明显,不同重投影之间的像素级差异可以忽略不计。

%提取缩放和旋转部件子矩阵。H = tform.T;R = H (1:2, 1:2);%从两个可能的arctan的均值计算θ=意味着([量化(R(2),(1)量化(R - R (3), (4))));%从两个稳定平均值计算的平均值计算规模scale = mean(R([1 4])/cos(theta));%翻译保持不变:翻译= H(3,1:2);%重建新的s-R-t变换:HsRt =[[缩放*[cos() -sin();罪(θ)因为(θ)];...翻译],[0 0 1]'];tformsRT = affine2d (HsRt);imgBold = imgB, tform,“OutputView”imref2d(大小(imgB)));imgBsRt = imgB, tformsRT,“OutputView”imref2d(大小(imgB)));图(2)中,clf;imshowpair (imgBold imgBsRt,“ColorChannels”“red-cyan”),轴图像;标题(仿射和s-R-t变换输出的颜色合成);

步骤6。运行完整视频

现在我们应用上述步骤来平滑一个视频序列。为便于阅读,上述估计两幅图像之间变换的程序已放置在MATLAB®函数中cvexEstStabilizationTform.这个函数cvexTformToSRT还将一般仿射变换转换为比例-旋转-平移变换。

每一步我们都计算变换 H 在现在的帧之间。我们把它作为s-R-t变换, H 年代 R t .然后我们把累积变换结合起来, H c u u l 一个 t v e ,它描述了自第一帧以来的所有摄像机运动。平滑视频的最后两帧以红青色组合显示在视频播放器中。

有了这段代码,你也可以去掉早期退出条件,让循环处理整个视频。

%将视频源重置为文件的开头。读(hVideoSrc, 1);hVPlayer = vision.VideoPlayer;%创建视频查看器%处理视频中的所有帧movMean = rgb2gray (im2single (readFrame (hVideoSrc)));imgB = movMean;imgBp = imgB;correctedMean = imgBp;2 = 2;Hcumulative =眼(3);hasFrame(hVideoSrc) && ii < 10%在新帧中读取imgA = imgB;% z ^ 1imgAp = imgBp;% z ^ 1imgB = rgb2gray (im2single (readFrame (hVideoSrc)));movMean = movMean + imgB;%估计从帧A到帧B的变换,并适合作为s-R-tH = cvexEstStabilizationTform (imgA imgB);HsRt = cvexTformToSRT (H);Hcumulative = HsRt * Hcumulative;imgBp = imwarp (imgB affine2d (Hcumulative),“OutputView”imref2d(大小(imgB)));%显示颜色合成与最后修正的帧步骤(hVPlayer imfuse (imgAp imgBp,“ColorChannels”“red-cyan”));correctedMean = correctedMean + imgBp;2 = 2 + 1;结束correctedMean = correctedMean / (ii-2);movMean = movMean / (ii-2);这里你调用对象的release方法来关闭任何打开的文件%和释放内存。释放(hVPlayer);

在计算过程中,我们计算了原始视频帧和修正后的帧的平均值。这些平均值在下面并排显示。左图显示的是原始输入帧的均值,证明了原始视频中存在很大的失真。然而,右边校正后的帧的平均值显示的图像核心几乎没有失真。当前景细节被模糊时(这是汽车向前运动的必然结果),这显示了稳定算法的有效性。

图;imshowpair (movMean correctedMean,“蒙太奇”);标题([“原始输入的意思”repmat (' '50 [1]),“修正序列的意思”]);

参考文献

[1] Tordoff, B;穆雷,DW。“运动估计的引导采样和共识。”计算机视觉,2002年欧洲会议。

[2]李,肯塔基州;壮族,YY;陈,;Ouhyoung, M。“使用鲁棒特征轨迹的视频稳定。”国立台湾大学,2009。

[3] Litvin,;康拉德,J;卡尔,WC。使用卡尔曼滤波和拼接的概率视频稳定电子成像、图像和视频通信学术研讨会,2003。

[4]松下,Y;Ofek E;唐,X;Shum HY。“帧视频稳定。”微软®亚洲研究院。CVPR 2005。