视频稳定

时间:2014-02-12 14:20:46

标签: c++ opencv image-processing video-processing image-stabilization

我正在研究视频稳定领域。我使用OpenCV实现了一个应用程序。

我的进步如:

冲浪点提取

匹配

estimateRigidTransform

warpAffine

但结果视频不稳定。任何人都可以帮我解决这个问题或者提供一些改进的源代码链接吗?

示例视频:Hippo video

这是我的代码[编辑]

#include "stdafx.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/opencv.hpp>

const double smooth_level = 0.7;
using namespace cv;
using namespace std;
struct TransformParam
{
    TransformParam() {}
    TransformParam(double _dx, double _dy, double _da) {
    dx = _dx;
    dy = _dy;
    da = _da;
}
   double dx; // translation x
   double dy; // translation y
   double da; // angle
};
int main( int argc, char** argv )
{
     VideoCapture cap ("test12.avi");  
     Mat cur, cur_grey;
     Mat prev, prev_grey;


     cap >> prev;
     cvtColor(prev, prev_grey, COLOR_BGR2GRAY);

     // Step 1 - Get previous to current frame transformation (dx, dy, da) for all frames
     vector <TransformParam> prev_to_cur_transform; // previous to current

     int k=1;
     int max_frames =  cap.get(CV_CAP_PROP_FRAME_COUNT);
     VideoWriter writeVideo ("stable.avi",0,30,cvSize(prev.cols,prev.rows),true);
     Mat last_T;
     double avg_dx = 0, avg_dy = 0, avg_da = 0;
     Mat smooth_T(2,3,CV_64F);
     while(true) {
        cap >> cur;

        if(cur.data == NULL) {
           break;
        }

        cvtColor(cur, cur_grey, COLOR_BGR2GRAY);

        // vector from prev to cur
        vector <Point2f> prev_corner, cur_corner;
        vector <Point2f> prev_corner2, cur_corner2;
        vector <uchar> status;
        vector <float> err;

        goodFeaturesToTrack(prev_grey, prev_corner, 200, 0.01, 30);
        calcOpticalFlowPyrLK(prev_grey, cur_grey, prev_corner, cur_corner, status, err);

       // weed out bad matches
       for(size_t i=0; i < status.size(); i++) {
           if(status[i]) {
               prev_corner2.push_back(prev_corner[i]);
              cur_corner2.push_back(cur_corner[i]);
           }
       }

       // translation + rotation only
       Mat T = estimateRigidTransform(prev_corner2, cur_corner2, false); 

       // in rare cases no transform is found. We'll just use the last known good transform.
       if(T.data == NULL) {
          last_T.copyTo(T);
       }

       T.copyTo(last_T);

      // decompose T
      double dx = T.at<double>(0,2);
      double dy = T.at<double>(1,2);
      double da = atan2(T.at<double>(1,0), T.at<double>(0,0));
      prev_to_cur_transform.push_back(TransformParam(dx, dy, da));

      avg_dx = (avg_dx * smooth_level) + (dx * (1- smooth_level));
      avg_dy = (avg_dy * smooth_level) + (dy * (1- smooth_level));
      avg_da = (avg_da * smooth_level) + (da * (1- smooth_level));

      smooth_T.at<double>(0,0) = cos(avg_da);
      smooth_T.at<double>(0,1) = -sin(avg_da);
      smooth_T.at<double>(1,0) = sin(avg_da);
      smooth_T.at<double>(1,1) = cos(avg_da);

      smooth_T.at<double>(0,2) = avg_dx;
      smooth_T.at<double>(1,2) = avg_dy;

      Mat stable;
      warpAffine(prev,stable,smooth_T,prev.size());

      Mat canvas = Mat::zeros(cur.rows, cur.cols*2+10, cur.type());
      prev.copyTo(canvas(Range::all(), Range(0, prev.cols)));
      stable.copyTo(canvas(Range::all(), Range(prev.cols+10, prev.cols*2+10)));

      imshow("before and after", canvas);
      waitKey(20);
      writeVideo.write(stable);
      cur.copyTo(prev);
      cur_grey.copyTo(prev_grey);
      k++;
   }
 }

1 个答案:

答案 0 :(得分:1)

首先,你可以模糊你的形象。它会有所帮助。其次,您可以通过指数平滑A(t + 1)= a * A(t)+(1-a)* A(t + 1)的最简单实现轻松平滑矩阵,并在[0; 1]范围。第三,你可以关闭某些类型的转换,如旋转,移位等。 这是代码示例:

t = estimateRigidTransform(new, old, 0); // 0 means not all transformations (5 of 6)
if(!t.empty()){
//  t(Range(0,2), Range(0,2)) = Mat::eye(2, 2, CV_64FC1); // turning off rotation
//  t.at<double>(0,2) = 0; t.at<double>(1,2) = 0; // turning off shift dx and dy
    tAvrg = tAvrg*a + t*(1-a); // a - smooth level in [0;1] range, play with it
    warpAffine(new, stable, tAvrg, Size(new.cols, new.rows));
}