0

我正在研究视频稳定领域。我使用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

首先,你可以模糊你的图像。它会有所帮助。其次,你可以通过简单的指数平滑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)); 
} 
+0

如何控制在[0,1] – user2745692

+0

1. tAvrg被平均(平滑)吨光滑水平,其中t是变换矩阵。 2.旋转没有关闭,此行被注释以允许您取消注释,并在符合您的情况时关闭旋转。 3.使用不同的值和检查结果。 –

+0

我改变了我的代码作为你的建议。但结果并不稳定。你能帮我解答一下问题吗? – user2745692