Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/videostab/src/stabilizer.cpp
16354 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
15
// Third party copyrights are property of their respective owners.
16
//
17
// Redistribution and use in source and binary forms, with or without modification,
18
// are permitted provided that the following conditions are met:
19
//
20
// * Redistribution's of source code must retain the above copyright notice,
21
// this list of conditions and the following disclaimer.
22
//
23
// * Redistribution's in binary form must reproduce the above copyright notice,
24
// this list of conditions and the following disclaimer in the documentation
25
// and/or other materials provided with the distribution.
26
//
27
// * The name of the copyright holders may not be used to endorse or promote products
28
// derived from this software without specific prior written permission.
29
//
30
// This software is provided by the copyright holders and contributors "as is" and
31
// any express or implied warranties, including, but not limited to, the implied
32
// warranties of merchantability and fitness for a particular purpose are disclaimed.
33
// In no event shall the Intel Corporation or contributors be liable for any direct,
34
// indirect, incidental, special, exemplary, or consequential damages
35
// (including, but not limited to, procurement of substitute goods or services;
36
// loss of use, data, or profits; or business interruption) however caused
37
// and on any theory of liability, whether in contract, strict liability,
38
// or tort (including negligence or otherwise) arising in any way out of
39
// the use of this software, even if advised of the possibility of such damage.
40
//
41
//M*/
42
43
#include "precomp.hpp"
44
#include "opencv2/videostab/stabilizer.hpp"
45
#include "opencv2/videostab/ring_buffer.hpp"
46
47
// for debug purposes
48
#define SAVE_MOTIONS 0
49
50
namespace cv
51
{
52
namespace videostab
53
{
54
55
StabilizerBase::StabilizerBase()
56
{
57
setLog(makePtr<LogToStdout>());
58
setFrameSource(makePtr<NullFrameSource>());
59
setMotionEstimator(makePtr<KeypointBasedMotionEstimator>(makePtr<MotionEstimatorRansacL2>()));
60
setDeblurer(makePtr<NullDeblurer>());
61
setInpainter(makePtr<NullInpainter>());
62
setRadius(15);
63
setTrimRatio(0);
64
setCorrectionForInclusion(false);
65
setBorderMode(BORDER_REPLICATE);
66
curPos_ = 0;
67
doDeblurring_ = false;
68
doInpainting_ = false;
69
processingStartTime_ = 0;
70
curStabilizedPos_ = 0;
71
}
72
73
74
void StabilizerBase::reset()
75
{
76
frameSize_ = Size(0, 0);
77
frameMask_ = Mat();
78
curPos_ = -1;
79
curStabilizedPos_ = -1;
80
doDeblurring_ = false;
81
preProcessedFrame_ = Mat();
82
doInpainting_ = false;
83
inpaintingMask_ = Mat();
84
frames_.clear();
85
motions_.clear();
86
blurrinessRates_.clear();
87
stabilizedFrames_.clear();
88
stabilizedMasks_.clear();
89
stabilizationMotions_.clear();
90
processingStartTime_ = 0;
91
}
92
93
94
Mat StabilizerBase::nextStabilizedFrame()
95
{
96
// check if we've processed all frames already
97
if (curStabilizedPos_ == curPos_ && curStabilizedPos_ != -1)
98
{
99
logProcessingTime();
100
return Mat();
101
}
102
103
bool processed;
104
do processed = doOneIteration();
105
while (processed && curStabilizedPos_ == -1);
106
107
// check if the frame source is empty
108
if (curStabilizedPos_ == -1)
109
{
110
logProcessingTime();
111
return Mat();
112
}
113
114
return postProcessFrame(at(curStabilizedPos_, stabilizedFrames_));
115
}
116
117
118
bool StabilizerBase::doOneIteration()
119
{
120
Mat frame = frameSource_->nextFrame();
121
if (!frame.empty())
122
{
123
curPos_++;
124
125
if (curPos_ > 0)
126
{
127
at(curPos_, frames_) = frame;
128
129
if (doDeblurring_)
130
at(curPos_, blurrinessRates_) = calcBlurriness(frame);
131
132
at(curPos_ - 1, motions_) = estimateMotion();
133
134
if (curPos_ >= radius_)
135
{
136
curStabilizedPos_ = curPos_ - radius_;
137
stabilizeFrame();
138
}
139
}
140
else
141
setUp(frame);
142
143
log_->print(".");
144
return true;
145
}
146
147
if (curStabilizedPos_ < curPos_)
148
{
149
curStabilizedPos_++;
150
at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_);
151
at(curStabilizedPos_ + radius_ - 1, motions_) = Mat::eye(3, 3, CV_32F);
152
stabilizeFrame();
153
154
log_->print(".");
155
return true;
156
}
157
158
return false;
159
}
160
161
162
void StabilizerBase::setUp(const Mat &firstFrame)
163
{
164
InpainterBase *inpaint = inpainter_.get();
165
doInpainting_ = dynamic_cast<NullInpainter*>(inpaint) == 0;
166
if (doInpainting_)
167
{
168
inpainter_->setMotionModel(motionEstimator_->motionModel());
169
inpainter_->setFrames(frames_);
170
inpainter_->setMotions(motions_);
171
inpainter_->setStabilizedFrames(stabilizedFrames_);
172
inpainter_->setStabilizationMotions(stabilizationMotions_);
173
}
174
175
DeblurerBase *deblurer = deblurer_.get();
176
doDeblurring_ = dynamic_cast<NullDeblurer*>(deblurer) == 0;
177
if (doDeblurring_)
178
{
179
blurrinessRates_.resize(2*radius_ + 1);
180
float blurriness = calcBlurriness(firstFrame);
181
for (int i = -radius_; i <= 0; ++i)
182
at(i, blurrinessRates_) = blurriness;
183
deblurer_->setFrames(frames_);
184
deblurer_->setMotions(motions_);
185
deblurer_->setBlurrinessRates(blurrinessRates_);
186
}
187
188
log_->print("processing frames");
189
processingStartTime_ = clock();
190
}
191
192
193
void StabilizerBase::stabilizeFrame()
194
{
195
Mat stabilizationMotion = estimateStabilizationMotion();
196
if (doCorrectionForInclusion_)
197
stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_);
198
199
at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion;
200
201
if (doDeblurring_)
202
{
203
at(curStabilizedPos_, frames_).copyTo(preProcessedFrame_);
204
deblurer_->deblur(curStabilizedPos_, preProcessedFrame_);
205
}
206
else
207
preProcessedFrame_ = at(curStabilizedPos_, frames_);
208
209
// apply stabilization transformation
210
211
if (motionEstimator_->motionModel() != MM_HOMOGRAPHY)
212
warpAffine(
213
preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
214
stabilizationMotion(Rect(0,0,3,2)), frameSize_, INTER_LINEAR, borderMode_);
215
else
216
warpPerspective(
217
preProcessedFrame_, at(curStabilizedPos_, stabilizedFrames_),
218
stabilizationMotion, frameSize_, INTER_LINEAR, borderMode_);
219
220
if (doInpainting_)
221
{
222
if (motionEstimator_->motionModel() != MM_HOMOGRAPHY)
223
warpAffine(
224
frameMask_, at(curStabilizedPos_, stabilizedMasks_),
225
stabilizationMotion(Rect(0,0,3,2)), frameSize_, INTER_NEAREST);
226
else
227
warpPerspective(
228
frameMask_, at(curStabilizedPos_, stabilizedMasks_),
229
stabilizationMotion, frameSize_, INTER_NEAREST);
230
231
erode(at(curStabilizedPos_, stabilizedMasks_), at(curStabilizedPos_, stabilizedMasks_),
232
Mat());
233
234
at(curStabilizedPos_, stabilizedMasks_).copyTo(inpaintingMask_);
235
236
inpainter_->inpaint(
237
curStabilizedPos_, at(curStabilizedPos_, stabilizedFrames_), inpaintingMask_);
238
}
239
}
240
241
242
Mat StabilizerBase::postProcessFrame(const Mat &frame)
243
{
244
// trim frame
245
int dx = static_cast<int>(floor(trimRatio_ * frame.cols));
246
int dy = static_cast<int>(floor(trimRatio_ * frame.rows));
247
return frame(Rect(dx, dy, frame.cols - 2*dx, frame.rows - 2*dy));
248
}
249
250
251
void StabilizerBase::logProcessingTime()
252
{
253
clock_t elapsedTime = clock() - processingStartTime_;
254
log_->print("\nprocessing time: %.3f sec\n", static_cast<double>(elapsedTime) / CLOCKS_PER_SEC);
255
}
256
257
258
OnePassStabilizer::OnePassStabilizer()
259
{
260
setMotionFilter(makePtr<GaussianMotionFilter>());
261
reset();
262
}
263
264
265
void OnePassStabilizer::reset()
266
{
267
StabilizerBase::reset();
268
}
269
270
271
void OnePassStabilizer::setUp(const Mat &firstFrame)
272
{
273
frameSize_ = firstFrame.size();
274
frameMask_.create(frameSize_, CV_8U);
275
frameMask_.setTo(255);
276
277
int cacheSize = 2*radius_ + 1;
278
frames_.resize(cacheSize);
279
stabilizedFrames_.resize(cacheSize);
280
stabilizedMasks_.resize(cacheSize);
281
motions_.resize(cacheSize);
282
stabilizationMotions_.resize(cacheSize);
283
284
for (int i = -radius_; i < 0; ++i)
285
{
286
at(i, motions_) = Mat::eye(3, 3, CV_32F);
287
at(i, frames_) = firstFrame;
288
}
289
290
at(0, frames_) = firstFrame;
291
292
StabilizerBase::setUp(firstFrame);
293
}
294
295
296
Mat OnePassStabilizer::estimateMotion()
297
{
298
return motionEstimator_->estimate(at(curPos_ - 1, frames_), at(curPos_, frames_));
299
}
300
301
302
Mat OnePassStabilizer::estimateStabilizationMotion()
303
{
304
return motionFilter_->stabilize(curStabilizedPos_, motions_, std::make_pair(0, curPos_));
305
}
306
307
308
Mat OnePassStabilizer::postProcessFrame(const Mat &frame)
309
{
310
return StabilizerBase::postProcessFrame(frame);
311
}
312
313
314
TwoPassStabilizer::TwoPassStabilizer()
315
{
316
setMotionStabilizer(makePtr<GaussianMotionFilter>());
317
setWobbleSuppressor(makePtr<NullWobbleSuppressor>());
318
setEstimateTrimRatio(false);
319
reset();
320
}
321
322
323
void TwoPassStabilizer::reset()
324
{
325
StabilizerBase::reset();
326
frameCount_ = 0;
327
isPrePassDone_ = false;
328
doWobbleSuppression_ = false;
329
motions2_.clear();
330
suppressedFrame_ = Mat();
331
}
332
333
334
Mat TwoPassStabilizer::nextFrame()
335
{
336
runPrePassIfNecessary();
337
return StabilizerBase::nextStabilizedFrame();
338
}
339
340
341
#if SAVE_MOTIONS
342
static void saveMotions(
343
int frameCount, const std::vector<Mat> &motions, const std::vector<Mat> &stabilizationMotions)
344
{
345
std::ofstream fm("log_motions.csv");
346
for (int i = 0; i < frameCount - 1; ++i)
347
{
348
Mat_<float> M = at(i, motions);
349
fm << M(0,0) << " " << M(0,1) << " " << M(0,2) << " "
350
<< M(1,0) << " " << M(1,1) << " " << M(1,2) << " "
351
<< M(2,0) << " " << M(2,1) << " " << M(2,2) << std::endl;
352
}
353
std::ofstream fo("log_orig.csv");
354
for (int i = 0; i < frameCount; ++i)
355
{
356
Mat_<float> M = getMotion(0, i, motions);
357
fo << M(0,0) << " " << M(0,1) << " " << M(0,2) << " "
358
<< M(1,0) << " " << M(1,1) << " " << M(1,2) << " "
359
<< M(2,0) << " " << M(2,1) << " " << M(2,2) << std::endl;
360
}
361
std::ofstream fs("log_stab.csv");
362
for (int i = 0; i < frameCount; ++i)
363
{
364
Mat_<float> M = stabilizationMotions[i] * getMotion(0, i, motions);
365
fs << M(0,0) << " " << M(0,1) << " " << M(0,2) << " "
366
<< M(1,0) << " " << M(1,1) << " " << M(1,2) << " "
367
<< M(2,0) << " " << M(2,1) << " " << M(2,2) << std::endl;
368
}
369
}
370
#endif
371
372
373
void TwoPassStabilizer::runPrePassIfNecessary()
374
{
375
if (!isPrePassDone_)
376
{
377
// check if we must do wobble suppression
378
379
WobbleSuppressorBase *wobble = wobbleSuppressor_.get();
380
doWobbleSuppression_ = dynamic_cast<NullWobbleSuppressor*>(wobble) == 0;
381
382
// estimate motions
383
384
clock_t startTime = clock();
385
log_->print("first pass: estimating motions");
386
387
Mat prevFrame, frame;
388
bool ok = true, ok2 = true;
389
390
while (!(frame = frameSource_->nextFrame()).empty())
391
{
392
if (frameCount_ > 0)
393
{
394
motions_.push_back(motionEstimator_->estimate(prevFrame, frame, &ok));
395
396
if (doWobbleSuppression_)
397
{
398
Mat M = wobbleSuppressor_->motionEstimator()->estimate(prevFrame, frame, &ok2);
399
if (ok2)
400
motions2_.push_back(M);
401
else
402
motions2_.push_back(motions_.back());
403
}
404
405
if (ok)
406
{
407
if (ok2) log_->print(".");
408
else log_->print("?");
409
}
410
else log_->print("x");
411
}
412
else
413
{
414
frameSize_ = frame.size();
415
frameMask_.create(frameSize_, CV_8U);
416
frameMask_.setTo(255);
417
}
418
419
prevFrame = frame;
420
frameCount_++;
421
}
422
423
clock_t elapsedTime = clock() - startTime;
424
log_->print("\nmotion estimation time: %.3f sec\n",
425
static_cast<double>(elapsedTime) / CLOCKS_PER_SEC);
426
427
// add aux. motions
428
429
for (int i = 0; i < radius_; ++i)
430
motions_.push_back(Mat::eye(3, 3, CV_32F));
431
432
// stabilize
433
434
startTime = clock();
435
436
stabilizationMotions_.resize(frameCount_);
437
motionStabilizer_->stabilize(
438
frameCount_, motions_, std::make_pair(0, frameCount_ - 1), &stabilizationMotions_[0]);
439
440
elapsedTime = clock() - startTime;
441
log_->print("motion stabilization time: %.3f sec\n",
442
static_cast<double>(elapsedTime) / CLOCKS_PER_SEC);
443
444
// estimate optimal trim ratio if necessary
445
446
if (mustEstTrimRatio_)
447
{
448
trimRatio_ = 0;
449
for (int i = 0; i < frameCount_; ++i)
450
{
451
Mat S = stabilizationMotions_[i];
452
trimRatio_ = std::max(trimRatio_, estimateOptimalTrimRatio(S, frameSize_));
453
}
454
log_->print("estimated trim ratio: %f\n", static_cast<double>(trimRatio_));
455
}
456
457
#if SAVE_MOTIONS
458
saveMotions(frameCount_, motions_, stabilizationMotions_);
459
#endif
460
461
isPrePassDone_ = true;
462
frameSource_->reset();
463
}
464
}
465
466
467
void TwoPassStabilizer::setUp(const Mat &firstFrame)
468
{
469
int cacheSize = 2*radius_ + 1;
470
frames_.resize(cacheSize);
471
stabilizedFrames_.resize(cacheSize);
472
stabilizedMasks_.resize(cacheSize);
473
474
for (int i = -radius_; i <= 0; ++i)
475
at(i, frames_) = firstFrame;
476
477
WobbleSuppressorBase *wobble = wobbleSuppressor_.get();
478
doWobbleSuppression_ = dynamic_cast<NullWobbleSuppressor*>(wobble) == 0;
479
if (doWobbleSuppression_)
480
{
481
wobbleSuppressor_->setFrameCount(frameCount_);
482
wobbleSuppressor_->setMotions(motions_);
483
wobbleSuppressor_->setMotions2(motions2_);
484
wobbleSuppressor_->setStabilizationMotions(stabilizationMotions_);
485
}
486
487
StabilizerBase::setUp(firstFrame);
488
}
489
490
491
Mat TwoPassStabilizer::estimateMotion()
492
{
493
return motions_[curPos_ - 1].clone();
494
}
495
496
497
Mat TwoPassStabilizer::estimateStabilizationMotion()
498
{
499
return stabilizationMotions_[curStabilizedPos_].clone();
500
}
501
502
503
Mat TwoPassStabilizer::postProcessFrame(const Mat &frame)
504
{
505
wobbleSuppressor_->suppress(curStabilizedPos_, frame, suppressedFrame_);
506
return StabilizerBase::postProcessFrame(suppressedFrame_);
507
}
508
509
} // namespace videostab
510
} // namespace cv
511
512