主要内容

使用点特征匹配的视频稳定

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

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

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

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

文件名=“shaky_car.avi”;hVideoSrc = videereader(文件名);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);标题(“A字角”);

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

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

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

为角落提取FREAK描述符[featresa, pointsA] = extractFeatures(imgA, pointsA);[featuresB, pointsB] = extractFeatures(imgB, pointsB);

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

indexPairs = matchFeatures(featresa, featresb);pointsA = pointsA(indexPairs(:, 1),:);pointsB = pointsB(indexPairs(:, 2),:);

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

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

步骤4。从噪声对应估计变换

在上一步中获得的许多点对应关系是不正确的。但是我们仍然可以使用M-estimator SAmple Consensus (MSAC)算法推导出两个图像之间几何变换的鲁棒估计,该算法是RANSAC算法的变体。MSAC算法在estimateGeometricTransform2D函数。当给出一组点对应时,这个函数将搜索有效的inlier对应。然后,它将从这些点导出仿射变换,使来自第一个点集的内线与来自第二个点集的内线最匹配。这个仿射变换将是一个3 × 3矩阵的形式:

[a_1 a_3 0;A_2 a_4 0;T_x t_y 1]

的参数 一个 定义变换的缩放、旋转和剪切效果,而参数 t 是转换参数。此转换可用于扭曲图像,以便将其相应的特征移动到相同的图像位置。

仿射变换的一个局限性是它只能改变成像平面。因此,它不适合找出一个3-D场景的两帧之间的一般失真,比如这段从一辆移动的汽车上拍摄的视频。但它在某些条件下是有效的,我们稍后会讲到。

[tform, inlierIdx] = estimateGeometricTransform2D(...pointsB pointsA,仿射的);pointsBm = pointsB(inlierIdx,:);pointsAm = pointsA(inlierIdx,:);imgBp = imgB, tform,“OutputView”imref2d(大小(imgB)));pointsBmp = transformPointsForward(tform, pointsBmp . 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

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

[s*cos(ang) s*-sin(ang) 0;S *sin(ang) S *cos(ang) 0;T_x t_y 1]

下面我们通过拟合上述得到的变换来说明这个转换过程 H 用等价物旋转平移, H 年代 R t .为了表明转换转换的错误是最小的,我们用这两个转换重新投影帧B,并将下面的两张图像显示为红-青色复合。由于图像呈现黑白,显然不同重投影之间的像素差异可以忽略不计。

提取比例和旋转部分子矩阵。H = t形式;R = h (1:2,1:2);从两个可能的反切线的平均值计算θ=意味着([量化(R(2),(1)量化(R - R (3), (4))));从两个稳定平均值计算的平均值计算刻度scale = mean(R([1 4])/cos(theta));%翻译不变:翻译= H(3,1:2);重构新的s-R-t变换:HsRt = [[scale*[cos(theta) -sin(theta);罪(θ)因为(θ)];...翻译],[0 0 1]'];tformsRT = affine2d(HsRt);imgBold = imwarp(imgB, tform,“OutputView”imref2d(大小(imgB)));imgBsRt = imwarp(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;Ii = 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;Ii = Ii +1;结束correctedMean = correctedMean/(ii-2);movMean = movMean/(ii-2);这里调用对象上的release方法来关闭任何打开的文件%,释放内存。释放(hVPlayer);

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

图;imshowpair (movMean correctedMean,“蒙太奇”);标题([“原始输入平均值”repmat (' '50 [1]),“校正序列均值”]);

参考文献

[1]托多夫,B;穆雷,DW。运动估计的引导抽样和共识欧洲计算机视觉会议,2002。

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

[3]利特文,A;康拉德,J;卡尔,WC。“使用卡尔曼滤波和马赛克的概率视频稳定。”IS&T/SPIE电子成像、图像和视频通信与进程研讨会,2003。

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