最佳视频稳定算法

5
我正在创建一个稳定视频流的程序。目前,我的程序基于相位相关算法运作。我在计算两个图像——基础图像和当前图像之间的偏移量。接下来,我根据新坐标对当前图像进行校正。虽然这个程序能够工作,但是结果并不令人满意。你可能会发现,经过处理的视频看起来不太好,整个视频似乎更加抖动。
原始视频
去抖视频
这是我目前的实现方式:
计算图像之间的偏移量:
Point2d calculate_offset_phase_optimized(Mat one, Mat& two) {

  if(two.type() != CV_64F) {
    cvtColor(two, two, CV_BGR2GRAY);
    two.convertTo(two, CV_64F);
  }

  cvtColor(one, one, CV_BGR2GRAY);
  one.convertTo(one, CV_64F);

  return phaseCorrelate(one, two);

}

根据此坐标移动图像:

void move_image_roi_alt(Mat& img, Mat& trans, const Point2d& offset) {

  trans = Mat::zeros(img.size(), img.type());
  img(
    Rect(
        _0(static_cast<int>(offset.x)),
        _0(static_cast<int>(offset.y)),
        img.cols-abs(static_cast<int>(offset.x)),
        img.rows-abs(static_cast<int>(offset.y))
    )
  ).copyTo(trans(
    Rect(
        _0ia(static_cast<int>(offset.x)),
        _0ia(static_cast<int>(offset.y)),
        img.cols-abs(static_cast<int>(offset.x)), 
        img.rows-abs(static_cast<int>(offset.y))
    )   
  )); 
}

int _0(const int x) {
  return x < 0 ? 0 : x;
}

int _0ia(const int x) {
  return x < 0 ? abs(x) : 0;
}

我在查看文档时发现了作者稳定器YouTube和基于角点检测的算法,它看起来很有吸引力,但是我不太清楚它是如何工作的。

所以我的问题是如何有效地解决这个问题。

其中一个条件是,该程序将在较慢的计算机上运行,因此重型算法可能不太合适。
谢谢!
附言: 对于文本中的任何错误,我深感抱歉-这是自动翻译。


你的目标视频是什么类型的?只有人工图像(场景实际上是平面)还是真实视频,其中像素可能处于不同的深度?你想要纠正哪些运动?通常希望平稳运动,但高加速度的运动通常会产生噪音。 - Nico Schertler
这是目标视频的示例: http://www.youtube.com/watch?v=Ta8w_nzuMkU 这是我当前稳定器的结果: http://www.youtube.com/watch?v=-0p-uJEacVI 最高优先级是消除平面相机运动中的抖动。旋转和缩放是可选的。 - iRomul
1
我可以想象场景的深度可能是一个真正的问题(远处像素不会像近处像素那样移动)。我不知道通常是如何处理的,但是这是我会做的:使用两个或更多图像估计每个点的3D位置。也要估计3D相机运动。平滑相机路径(例如使用盒状滤波器)并重新渲染场景,填补可能出现的任何空洞。我不确定纯粹的翻译是否足够。 - Nico Schertler
2个回答

3
你可以在每一帧中使用图像描述符,例如SIFT,并计算帧之间的鲁棒性 匹配。然后可以计算帧之间的单应性矩阵并使用它来对齐它们。使用稀疏特征比使用密集相关性可以更快地实现。
Alternately, if you know the 相机参数, you can 计算点和相机的三维位置,并将图像重新投影到稳定的投影平面上。结果,您还会得到场景的稀疏三维重建(通常需要进行优化才能使用,精度有些不准确)。这就是例如Autostitch所做的事情,但实现起来非常困难。
请注意,相机参数也可以计算,但那更加困难。

感谢您的回答!我是这个领域的新手,所以遇到了一些不理解的事情。这是我的代码:detector.detect(base_frame, keypoints_base); detector.detect(current_frame, keypoints_cur); extractor.compute(..., keypoints_base, descriptors_base); extractor.compute(..., keypoints_cur, descriptors_cur); matcher.knnMatch(description_base, description_cur, matches, 2);然后我会过滤最佳匹配项并执行以下操作:homography = findHomography(k_base, k_cur, CV_RANSAC);但接下来我应该做什么?warpAffine不接受这个3x3的单应性矩阵,只接受2x3的。 - iRomul
请使用warpPerspective代替(参见http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html#warpperspective)。 - the swine
我试图实现这个算法,但结果并不令人满意:视频。请注意,帧是与固定帧进行比较的。在这种情况下,它是第一个视频帧。 完整代码 - iRomul
如果你的视频从第一帧开始就开始移动,那么你就不能把它作为参考,因为在帧之间没有共同的特征时,就不可能计算出变换。你需要使用一个浮动参考。 - the swine
1
浮动参考将通过计算连续帧之间的变换并堆叠变换来实现。同时,在每一步中,变换堆栈与单位矩阵插值,以便视图不会随时间而消失。这应该创建平滑的移动。 - the swine
显示剩余3条评论

2

在3行代码中,OpenCV可以为您完成此操作(这绝对是最短的方式,甚至可能是最好的):

t = estimateRigidTransform(newFrame, referenceFrame, 0); // 0 means not all transformations (5 of 6)
if(!t.empty()){    
    warpAffine(newFrame, stableFrame, t, Size(newFrame.cols, newFrame.rows)); // stableFrame should be stable now
}

您可以通过修改矩阵t来关闭某些转换,这可以带来更稳定的结果。这只是核心思想,然后您可以按照自己的方式进行修改:从矩阵t中更改参考框架、平滑的变换参数集等。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接