opencv轮廓抖动_OPENCV视频去抖动 | 学步园

#include

#include

#include

#include

#include

using namespace std;

using namespace cv;

// This video stablisation smooths the global trajectory using a sliding average window

//const int SMOOTHING_RADIUS = 15; // In frames. The larger the more stable the video, but less reactive to sudden panning

const int HORIZONTAL_BORDER_CROP = 20; // In pixels. Crops the border to reduce the black borders from stabilisation being too noticeable.

// 1. Get previous to current frame transformation (dx, dy, da) for all frames

// 2. Accumulate the transformations to get the image trajectory

// 3. Smooth out the trajectory using an averaging window

// 4. Generate new set of previous to current transform, such that the trajectory ends up being the same as the smoothed trajectory

// 5. Apply the new transformation to the video

struct TransformParam

{

TransformParam() {}

TransformParam(double _dx, double _dy, double _da) {

dx = _dx;

dy = _dy;

da = _da;

}

double dx;

double dy;

double da; // angle

};

struct Trajectory

{

Trajectory() {}

Trajectory(double _x, double _y, double _a) {

x = _x;

y = _y;

a = _a;

}

// "+"

friend Trajectory operator+(const Trajectory &c1,const Trajectory &c2){

return Trajectory(c1.x+c2.x,c1.y+c2.y,c1.a+c2.a);

}

//"-"

friend Trajectory operator-(const Trajectory &c1,const Trajectory &c2){

return Trajectory(c1.x-c2.x,c1.y-c2.y,c1.a-c2.a);

}

//"*"

friend Trajectory operator*(const Trajectory &c1,const Trajectory &c2){

return Trajectory(c1.x*c2.x,c1.y*c2.y,c1.a*c2.a);

}

//"/"

friend Trajectory operator/(const Trajectory &c1,const Trajectory &c2){

return Trajectory(c1.x/c2.x,c1.y/c2.y,c1.a/c2.a);

}

//"="

Trajectory operator =(const Trajectory &rx){

x = rx.x;

y = rx.y;

a = rx.a;

return Trajectory(x,y,a);

}

double x;

double y;

double a; // angle

};

//

int main(int argc, char **argv)

{

// For further analysis

ofstream out_transform("prev_to_cur_transformation.txt");

ofstream out_trajectory("trajectory.txt");

ofstream out_smoothed_trajectory("smoothed_trajectory.txt");

ofstream out_new_transform("new_prev_to_cur_transformation.txt");

VideoCapture cap("F:\\OPENCV实验室\\test9.avi");

assert(cap.isOpened());

Mat cur, cur_grey;

Mat prev, prev_grey;

cap >> prev;//get the first frame.ch

cvtColor(prev, prev_grey, COLOR_BGR2GRAY);

// Step 1 - Get previous to current frame transformation (dx, dy, da) for all frames

vector prev_to_cur_transform; // previous to current

// Accumulated frame to frame transform

double a = 0;

double x = 0;

double y = 0;

// Step 2 - Accumulate the transformations to get the image trajectory

vector trajectory; // trajectory at all frames

//

// Step 3 - Smooth out the trajectory using an averaging window

vector smoothed_trajectory; // trajectory at all frames

Trajectory X;//posteriori state estimate

TrajectoryX_;//priori estimate

Trajectory P;// posteriori estimate error covariance

Trajectory P_;// priori estimate error covariance

Trajectory K;//gain

Trajectoryz;//actual measurement

double pstd = 4e-3;//can be changed

double cstd = 0.25;//can be changed

Trajectory Q(pstd,pstd,pstd);// process noise covariance

Trajectory R(cstd,cstd,cstd);// measurement noise covariance

// Step 4 - Generate new set of previous to current transform, such that the trajectory ends up being the same as the smoothed trajectory

vector new_prev_to_cur_transform;

//

// Step 5 - Apply the new transformation to the video

//cap.set(CV_CAP_PROP_POS_FRAMES, 0);

Mat T(2,3,CV_64F);

int vert_border = HORIZONTAL_BORDER_CROP * prev.rows / prev.cols; // get the aspect ratio correct

VideoWriter outputVideo;

outputVideo.open("compare.avi" , CV_FOURCC('X','V','I','D'), 24,cvSize(cur.rows, cur.cols*2+10), true);

//

int k=1;

int max_frames = cap.get(CV_CAP_PROP_FRAME_COUNT);

Mat last_T;

Mat prev_grey_,cur_grey_;

while(true) {

cap >> cur;

if(cur.data == NULL) {

break;

}

cvtColor(cur, cur_grey, COLOR_BGR2GRAY);

// vector from prev to cur

vector prev_corner, cur_corner;

vector prev_corner2, cur_corner2;

vector status;

vector 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); // false = rigid transform, no scaling/shearing

// 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(0,2);

double dy = T.at(1,2);

double da = atan2(T.at(1,0), T.at(0,0));

//

//prev_to_cur_transform.push_back(TransformParam(dx, dy, da));

out_transform << k << " " << dx << " " << dy << " " << da << endl;

//

// Accumulated frame to frame transform

x += dx;

y += dy;

a += da;

//trajectory.push_back(Trajectory(x,y,a));

//

out_trajectory << k << " " << x << " " << y << " " << a << endl;

//

z = Trajectory(x,y,a);

//

if(k==1){

// intial guesses

X = Trajectory(0,0,0); //Initial estimate, set 0

P =Trajectory(1,1,1); //set error variance,set 1

}

else

{

//time update(prediction)

X_ = X; //X_(k) = X(k-1);

P_ = P+Q; //P_(k) = P(k-1)+Q;

// measurement update(correction)

K = P_/( P_+R ); //gain;K(k) = P_(k)/( P_(k)+R );

X = X_+K*(z-X_); //z-X_ is residual,X(k) = X_(k)+K(k)*(z(k)-X_(k));

P = (Trajectory(1,1,1)-K)*P_; //P(k) = (1-K(k))*P_(k);

}

//smoothed_trajectory.push_back(X);

out_smoothed_trajectory << k << " " << X.x << " " << X.y << " " << X.a << endl;

//-

// target - current

double diff_x = X.x - x;//

double diff_y = X.y - y;

double diff_a = X.a - a;

dx = dx + diff_x;

dy = dy + diff_y;

da = da + diff_a;

//new_prev_to_cur_transform.push_back(TransformParam(dx, dy, da));

//

out_new_transform << k << " " << dx << " " << dy << " " << da << endl;

//

T.at(0,0) = cos(da);

T.at(0,1) = -sin(da);

T.at(1,0) = sin(da);

T.at(1,1) = cos(da);

T.at(0,2) = dx;

T.at(1,2) = dy;

Mat cur2;

warpAffine(prev, cur2, T, cur.size());

cur2 = cur2(Range(vert_border, cur2.rows-vert_border), Range(HORIZONTAL_BORDER_CROP, cur2.cols-HORIZONTAL_BORDER_CROP));

// Resize cur2 back to cur size, for better side by side comparison

resize(cur2, cur2, cur.size());

// Now draw the original and stablised side by side for coolness

Mat canvas = Mat::zeros(cur.rows, cur.cols*2+10, cur.type());

prev.copyTo(canvas(Range::all(), Range(0, cur2.cols)));

cur2.copyTo(canvas(Range::all(), Range(cur2.cols+10, cur2.cols*2+10)));

// If too big to fit on the screen, then scale it down by 2, hopefully it'll fit

if(canvas.cols > 1920) {

resize(canvas, canvas, Size(canvas.cols/2, canvas.rows/2));

}

//outputVideo<

imshow("before and after", canvas);

waitKey(10);

//

prev = cur.clone();//cur.copyTo(prev);

cur_grey.copyTo(prev_grey);

cout << "Frame: " << k << "/" << max_frames << " - good optical flow: " << prev_corner2.size() << endl;

k++;

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值