Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/videostab/src/motion_stabilizing.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/motion_stabilizing.hpp"
45
#include "opencv2/videostab/global_motion.hpp"
46
#include "opencv2/videostab/ring_buffer.hpp"
47
#include "clp.hpp"
48
49
namespace cv
50
{
51
namespace videostab
52
{
53
54
void MotionStabilizationPipeline::stabilize(
55
int size, const std::vector<Mat> &motions, std::pair<int,int> range, Mat *stabilizationMotions)
56
{
57
std::vector<Mat> updatedMotions(motions.size());
58
for (size_t i = 0; i < motions.size(); ++i)
59
updatedMotions[i] = motions[i].clone();
60
61
std::vector<Mat> stabilizationMotions_(size);
62
63
for (int i = 0; i < size; ++i)
64
stabilizationMotions[i] = Mat::eye(3, 3, CV_32F);
65
66
for (size_t i = 0; i < stabilizers_.size(); ++i)
67
{
68
stabilizers_[i]->stabilize(size, updatedMotions, range, &stabilizationMotions_[0]);
69
70
for (int k = 0; k < size; ++k)
71
stabilizationMotions[k] = stabilizationMotions_[k] * stabilizationMotions[k];
72
73
for (int j = 0; j + 1 < size; ++j)
74
{
75
Mat S0 = stabilizationMotions[j];
76
Mat S1 = stabilizationMotions[j+1];
77
at(j, updatedMotions) = S1 * at(j, updatedMotions) * S0.inv();
78
}
79
}
80
}
81
82
83
void MotionFilterBase::stabilize(
84
int size, const std::vector<Mat> &motions, std::pair<int,int> range, Mat *stabilizationMotions)
85
{
86
for (int i = 0; i < size; ++i)
87
stabilizationMotions[i] = stabilize(i, motions, range);
88
}
89
90
91
void GaussianMotionFilter::setParams(int _radius, float _stdev)
92
{
93
radius_ = _radius;
94
stdev_ = _stdev > 0.f ? _stdev : std::sqrt(static_cast<float>(_radius));
95
96
float sum = 0;
97
weight_.resize(2*radius_ + 1);
98
for (int i = -radius_; i <= radius_; ++i)
99
sum += weight_[radius_ + i] = std::exp(-i*i/(stdev_*stdev_));
100
for (int i = -radius_; i <= radius_; ++i)
101
weight_[radius_ + i] /= sum;
102
}
103
104
105
Mat GaussianMotionFilter::stabilize(int idx, const std::vector<Mat> &motions, std::pair<int,int> range)
106
{
107
const Mat &cur = at(idx, motions);
108
Mat res = Mat::zeros(cur.size(), cur.type());
109
float sum = 0.f;
110
int iMin = std::max(idx - radius_, range.first);
111
int iMax = std::min(idx + radius_, range.second);
112
for (int i = iMin; i <= iMax; ++i)
113
{
114
res += weight_[radius_ + i - idx] * getMotion(idx, i, motions);
115
sum += weight_[radius_ + i - idx];
116
}
117
return sum > 0.f ? res / sum : Mat::eye(cur.size(), cur.type());
118
}
119
120
121
LpMotionStabilizer::LpMotionStabilizer(MotionModel model)
122
{
123
setMotionModel(model);
124
setFrameSize(Size(0,0));
125
setTrimRatio(0.1f);
126
setWeight1(1);
127
setWeight2(10);
128
setWeight3(100);
129
setWeight4(100);
130
}
131
132
133
#ifndef HAVE_CLP
134
135
void LpMotionStabilizer::stabilize(int, const std::vector<Mat>&, std::pair<int,int>, Mat*)
136
{
137
CV_Error(Error::StsError, "The library is built without Clp support");
138
}
139
140
#else
141
142
void LpMotionStabilizer::stabilize(
143
int size, const std::vector<Mat> &motions, std::pair<int,int> /*range*/, Mat *stabilizationMotions)
144
{
145
CV_Assert(model_ <= MM_AFFINE);
146
147
int N = size;
148
const std::vector<Mat> &M = motions;
149
Mat *S = stabilizationMotions;
150
151
double w = frameSize_.width, h = frameSize_.height;
152
double tw = w * trimRatio_, th = h * trimRatio_;
153
154
int ncols = 4*N + 6*(N-1) + 6*(N-2) + 6*(N-3);
155
int nrows = 8*N + 2*6*(N-1) + 2*6*(N-2) + 2*6*(N-3);
156
157
rows_.clear();
158
cols_.clear();
159
elems_.clear();
160
161
obj_.assign(ncols, 0);
162
collb_.assign(ncols, -INF);
163
colub_.assign(ncols, INF);
164
int c = 4*N;
165
166
// for each slack variable e[t] (error bound)
167
for (int t = 0; t < N-1; ++t, c += 6)
168
{
169
// e[t](0,0)
170
obj_[c] = w4_*w1_;
171
collb_[c] = 0;
172
173
// e[t](0,1)
174
obj_[c+1] = w4_*w1_;
175
collb_[c+1] = 0;
176
177
// e[t](0,2)
178
obj_[c+2] = w1_;
179
collb_[c+2] = 0;
180
181
// e[t](1,0)
182
obj_[c+3] = w4_*w1_;
183
collb_[c+3] = 0;
184
185
// e[t](1,1)
186
obj_[c+4] = w4_*w1_;
187
collb_[c+4] = 0;
188
189
// e[t](1,2)
190
obj_[c+5] = w1_;
191
collb_[c+5] = 0;
192
}
193
for (int t = 0; t < N-2; ++t, c += 6)
194
{
195
// e[t](0,0)
196
obj_[c] = w4_*w2_;
197
collb_[c] = 0;
198
199
// e[t](0,1)
200
obj_[c+1] = w4_*w2_;
201
collb_[c+1] = 0;
202
203
// e[t](0,2)
204
obj_[c+2] = w2_;
205
collb_[c+2] = 0;
206
207
// e[t](1,0)
208
obj_[c+3] = w4_*w2_;
209
collb_[c+3] = 0;
210
211
// e[t](1,1)
212
obj_[c+4] = w4_*w2_;
213
collb_[c+4] = 0;
214
215
// e[t](1,2)
216
obj_[c+5] = w2_;
217
collb_[c+5] = 0;
218
}
219
for (int t = 0; t < N-3; ++t, c += 6)
220
{
221
// e[t](0,0)
222
obj_[c] = w4_*w3_;
223
collb_[c] = 0;
224
225
// e[t](0,1)
226
obj_[c+1] = w4_*w3_;
227
collb_[c+1] = 0;
228
229
// e[t](0,2)
230
obj_[c+2] = w3_;
231
collb_[c+2] = 0;
232
233
// e[t](1,0)
234
obj_[c+3] = w4_*w3_;
235
collb_[c+3] = 0;
236
237
// e[t](1,1)
238
obj_[c+4] = w4_*w3_;
239
collb_[c+4] = 0;
240
241
// e[t](1,2)
242
obj_[c+5] = w3_;
243
collb_[c+5] = 0;
244
}
245
246
elems_.clear();
247
rowlb_.assign(nrows, -INF);
248
rowub_.assign(nrows, INF);
249
250
int r = 0;
251
252
// frame corners
253
const Point2d pt[] = {Point2d(0,0), Point2d(w,0), Point2d(w,h), Point2d(0,h)};
254
255
// for each frame
256
for (int t = 0; t < N; ++t)
257
{
258
c = 4*t;
259
260
// for each frame corner
261
for (int i = 0; i < 4; ++i, r += 2)
262
{
263
set(r, c, pt[i].x); set(r, c+1, pt[i].y); set(r, c+2, 1);
264
set(r+1, c, pt[i].y); set(r+1, c+1, -pt[i].x); set(r+1, c+3, 1);
265
rowlb_[r] = pt[i].x-tw;
266
rowub_[r] = pt[i].x+tw;
267
rowlb_[r+1] = pt[i].y-th;
268
rowub_[r+1] = pt[i].y+th;
269
}
270
}
271
272
// for each S[t+1]M[t] - S[t] - e[t] <= 0 condition
273
for (int t = 0; t < N-1; ++t, r += 6)
274
{
275
Mat_<float> M0 = at(t,M);
276
277
c = 4*t;
278
set(r, c, -1);
279
set(r+1, c+1, -1);
280
set(r+2, c+2, -1);
281
set(r+3, c+1, 1);
282
set(r+4, c, -1);
283
set(r+5, c+3, -1);
284
285
c = 4*(t+1);
286
set(r, c, M0(0,0)); set(r, c+1, M0(1,0));
287
set(r+1, c, M0(0,1)); set(r+1, c+1, M0(1,1));
288
set(r+2, c, M0(0,2)); set(r+2, c+1, M0(1,2)); set(r+2, c+2, 1);
289
set(r+3, c, M0(1,0)); set(r+3, c+1, -M0(0,0));
290
set(r+4, c, M0(1,1)); set(r+4, c+1, -M0(0,1));
291
set(r+5, c, M0(1,2)); set(r+5, c+1, -M0(0,2)); set(r+5, c+3, 1);
292
293
c = 4*N + 6*t;
294
for (int i = 0; i < 6; ++i)
295
set(r+i, c+i, -1);
296
297
rowub_[r] = 0;
298
rowub_[r+1] = 0;
299
rowub_[r+2] = 0;
300
rowub_[r+3] = 0;
301
rowub_[r+4] = 0;
302
rowub_[r+5] = 0;
303
}
304
305
// for each 0 <= S[t+1]M[t] - S[t] + e[t] condition
306
for (int t = 0; t < N-1; ++t, r += 6)
307
{
308
Mat_<float> M0 = at(t,M);
309
310
c = 4*t;
311
set(r, c, -1);
312
set(r+1, c+1, -1);
313
set(r+2, c+2, -1);
314
set(r+3, c+1, 1);
315
set(r+4, c, -1);
316
set(r+5, c+3, -1);
317
318
c = 4*(t+1);
319
set(r, c, M0(0,0)); set(r, c+1, M0(1,0));
320
set(r+1, c, M0(0,1)); set(r+1, c+1, M0(1,1));
321
set(r+2, c, M0(0,2)); set(r+2, c+1, M0(1,2)); set(r+2, c+2, 1);
322
set(r+3, c, M0(1,0)); set(r+3, c+1, -M0(0,0));
323
set(r+4, c, M0(1,1)); set(r+4, c+1, -M0(0,1));
324
set(r+5, c, M0(1,2)); set(r+5, c+1, -M0(0,2)); set(r+5, c+3, 1);
325
326
c = 4*N + 6*t;
327
for (int i = 0; i < 6; ++i)
328
set(r+i, c+i, 1);
329
330
rowlb_[r] = 0;
331
rowlb_[r+1] = 0;
332
rowlb_[r+2] = 0;
333
rowlb_[r+3] = 0;
334
rowlb_[r+4] = 0;
335
rowlb_[r+5] = 0;
336
}
337
338
// for each S[t+2]M[t+1] - S[t+1]*(I+M[t]) + S[t] - e[t] <= 0 condition
339
for (int t = 0; t < N-2; ++t, r += 6)
340
{
341
Mat_<float> M0 = at(t,M), M1 = at(t+1,M);
342
343
c = 4*t;
344
set(r, c, 1);
345
set(r+1, c+1, 1);
346
set(r+2, c+2, 1);
347
set(r+3, c+1, -1);
348
set(r+4, c, 1);
349
set(r+5, c+3, 1);
350
351
c = 4*(t+1);
352
set(r, c, -M0(0,0)-1); set(r, c+1, -M0(1,0));
353
set(r+1, c, -M0(0,1)); set(r+1, c+1, -M0(1,1)-1);
354
set(r+2, c, -M0(0,2)); set(r+2, c+1, -M0(1,2)); set(r+2, c+2, -2);
355
set(r+3, c, -M0(1,0)); set(r+3, c+1, M0(0,0)+1);
356
set(r+4, c, -M0(1,1)-1); set(r+4, c+1, M0(0,1));
357
set(r+5, c, -M0(1,2)); set(r+5, c+1, M0(0,2)); set(r+5, c+3, -2);
358
359
c = 4*(t+2);
360
set(r, c, M1(0,0)); set(r, c+1, M1(1,0));
361
set(r+1, c, M1(0,1)); set(r+1, c+1, M1(1,1));
362
set(r+2, c, M1(0,2)); set(r+2, c+1, M1(1,2)); set(r+2, c+2, 1);
363
set(r+3, c, M1(1,0)); set(r+3, c+1, -M1(0,0));
364
set(r+4, c, M1(1,1)); set(r+4, c+1, -M1(0,1));
365
set(r+5, c, M1(1,2)); set(r+5, c+1, -M1(0,2)); set(r+5, c+3, 1);
366
367
c = 4*N + 6*(N-1) + 6*t;
368
for (int i = 0; i < 6; ++i)
369
set(r+i, c+i, -1);
370
371
rowub_[r] = 0;
372
rowub_[r+1] = 0;
373
rowub_[r+2] = 0;
374
rowub_[r+3] = 0;
375
rowub_[r+4] = 0;
376
rowub_[r+5] = 0;
377
}
378
379
// for each 0 <= S[t+2]M[t+1]] - S[t+1]*(I+M[t]) + S[t] + e[t] condition
380
for (int t = 0; t < N-2; ++t, r += 6)
381
{
382
Mat_<float> M0 = at(t,M), M1 = at(t+1,M);
383
384
c = 4*t;
385
set(r, c, 1);
386
set(r+1, c+1, 1);
387
set(r+2, c+2, 1);
388
set(r+3, c+1, -1);
389
set(r+4, c, 1);
390
set(r+5, c+3, 1);
391
392
c = 4*(t+1);
393
set(r, c, -M0(0,0)-1); set(r, c+1, -M0(1,0));
394
set(r+1, c, -M0(0,1)); set(r+1, c+1, -M0(1,1)-1);
395
set(r+2, c, -M0(0,2)); set(r+2, c+1, -M0(1,2)); set(r+2, c+2, -2);
396
set(r+3, c, -M0(1,0)); set(r+3, c+1, M0(0,0)+1);
397
set(r+4, c, -M0(1,1)-1); set(r+4, c+1, M0(0,1));
398
set(r+5, c, -M0(1,2)); set(r+5, c+1, M0(0,2)); set(r+5, c+3, -2);
399
400
c = 4*(t+2);
401
set(r, c, M1(0,0)); set(r, c+1, M1(1,0));
402
set(r+1, c, M1(0,1)); set(r+1, c+1, M1(1,1));
403
set(r+2, c, M1(0,2)); set(r+2, c+1, M1(1,2)); set(r+2, c+2, 1);
404
set(r+3, c, M1(1,0)); set(r+3, c+1, -M1(0,0));
405
set(r+4, c, M1(1,1)); set(r+4, c+1, -M1(0,1));
406
set(r+5, c, M1(1,2)); set(r+5, c+1, -M1(0,2)); set(r+5, c+3, 1);
407
408
c = 4*N + 6*(N-1) + 6*t;
409
for (int i = 0; i < 6; ++i)
410
set(r+i, c+i, 1);
411
412
rowlb_[r] = 0;
413
rowlb_[r+1] = 0;
414
rowlb_[r+2] = 0;
415
rowlb_[r+3] = 0;
416
rowlb_[r+4] = 0;
417
rowlb_[r+5] = 0;
418
}
419
420
// for each S[t+3]M[t+2] - S[t+2]*(I+2M[t+1]) + S[t+1]*(2*I+M[t]) - S[t] - e[t] <= 0 condition
421
for (int t = 0; t < N-3; ++t, r += 6)
422
{
423
Mat_<float> M0 = at(t,M), M1 = at(t+1,M), M2 = at(t+2,M);
424
425
c = 4*t;
426
set(r, c, -1);
427
set(r+1, c+1, -1);
428
set(r+2, c+2, -1);
429
set(r+3, c+1, 1);
430
set(r+4, c, -1);
431
set(r+5, c+3, -1);
432
433
c = 4*(t+1);
434
set(r, c, M0(0,0)+2); set(r, c+1, M0(1,0));
435
set(r+1, c, M0(0,1)); set(r+1, c+1, M0(1,1)+2);
436
set(r+2, c, M0(0,2)); set(r+2, c+1, M0(1,2)); set(r+2, c+2, 3);
437
set(r+3, c, M0(1,0)); set(r+3, c+1, -M0(0,0)-2);
438
set(r+4, c, M0(1,1)+2); set(r+4, c+1, -M0(0,1));
439
set(r+5, c, M0(1,2)); set(r+5, c+1, -M0(0,2)); set(r+5, c+3, 3);
440
441
c = 4*(t+2);
442
set(r, c, -2*M1(0,0)-1); set(r, c+1, -2*M1(1,0));
443
set(r+1, c, -2*M1(0,1)); set(r+1, c+1, -2*M1(1,1)-1);
444
set(r+2, c, -2*M1(0,2)); set(r+2, c+1, -2*M1(1,2)); set(r+2, c+2, -3);
445
set(r+3, c, -2*M1(1,0)); set(r+3, c+1, 2*M1(0,0)+1);
446
set(r+4, c, -2*M1(1,1)-1); set(r+4, c+1, 2*M1(0,1));
447
set(r+5, c, -2*M1(1,2)); set(r+5, c+1, 2*M1(0,2)); set(r+5, c+3, -3);
448
449
c = 4*(t+3);
450
set(r, c, M2(0,0)); set(r, c+1, M2(1,0));
451
set(r+1, c, M2(0,1)); set(r+1, c+1, M2(1,1));
452
set(r+2, c, M2(0,2)); set(r+2, c+1, M2(1,2)); set(r+2, c+2, 1);
453
set(r+3, c, M2(1,0)); set(r+3, c+1, -M2(0,0));
454
set(r+4, c, M2(1,1)); set(r+4, c+1, -M2(0,1));
455
set(r+5, c, M2(1,2)); set(r+5, c+1, -M2(0,2)); set(r+5, c+3, 1);
456
457
c = 4*N + 6*(N-1) + 6*(N-2) + 6*t;
458
for (int i = 0; i < 6; ++i)
459
set(r+i, c+i, -1);
460
461
rowub_[r] = 0;
462
rowub_[r+1] = 0;
463
rowub_[r+2] = 0;
464
rowub_[r+3] = 0;
465
rowub_[r+4] = 0;
466
rowub_[r+5] = 0;
467
}
468
469
// for each 0 <= S[t+3]M[t+2] - S[t+2]*(I+2M[t+1]) + S[t+1]*(2*I+M[t]) + e[t] condition
470
for (int t = 0; t < N-3; ++t, r += 6)
471
{
472
Mat_<float> M0 = at(t,M), M1 = at(t+1,M), M2 = at(t+2,M);
473
474
c = 4*t;
475
set(r, c, -1);
476
set(r+1, c+1, -1);
477
set(r+2, c+2, -1);
478
set(r+3, c+1, 1);
479
set(r+4, c, -1);
480
set(r+5, c+3, -1);
481
482
c = 4*(t+1);
483
set(r, c, M0(0,0)+2); set(r, c+1, M0(1,0));
484
set(r+1, c, M0(0,1)); set(r+1, c+1, M0(1,1)+2);
485
set(r+2, c, M0(0,2)); set(r+2, c+1, M0(1,2)); set(r+2, c+2, 3);
486
set(r+3, c, M0(1,0)); set(r+3, c+1, -M0(0,0)-2);
487
set(r+4, c, M0(1,1)+2); set(r+4, c+1, -M0(0,1));
488
set(r+5, c, M0(1,2)); set(r+5, c+1, -M0(0,2)); set(r+5, c+3, 3);
489
490
c = 4*(t+2);
491
set(r, c, -2*M1(0,0)-1); set(r, c+1, -2*M1(1,0));
492
set(r+1, c, -2*M1(0,1)); set(r+1, c+1, -2*M1(1,1)-1);
493
set(r+2, c, -2*M1(0,2)); set(r+2, c+1, -2*M1(1,2)); set(r+2, c+2, -3);
494
set(r+3, c, -2*M1(1,0)); set(r+3, c+1, 2*M1(0,0)+1);
495
set(r+4, c, -2*M1(1,1)-1); set(r+4, c+1, 2*M1(0,1));
496
set(r+5, c, -2*M1(1,2)); set(r+5, c+1, 2*M1(0,2)); set(r+5, c+3, -3);
497
498
c = 4*(t+3);
499
set(r, c, M2(0,0)); set(r, c+1, M2(1,0));
500
set(r+1, c, M2(0,1)); set(r+1, c+1, M2(1,1));
501
set(r+2, c, M2(0,2)); set(r+2, c+1, M2(1,2)); set(r+2, c+2, 1);
502
set(r+3, c, M2(1,0)); set(r+3, c+1, -M2(0,0));
503
set(r+4, c, M2(1,1)); set(r+4, c+1, -M2(0,1));
504
set(r+5, c, M2(1,2)); set(r+5, c+1, -M2(0,2)); set(r+5, c+3, 1);
505
506
c = 4*N + 6*(N-1) + 6*(N-2) + 6*t;
507
for (int i = 0; i < 6; ++i)
508
set(r+i, c+i, 1);
509
510
rowlb_[r] = 0;
511
rowlb_[r+1] = 0;
512
rowlb_[r+2] = 0;
513
rowlb_[r+3] = 0;
514
rowlb_[r+4] = 0;
515
rowlb_[r+5] = 0;
516
}
517
518
// solve
519
520
CoinPackedMatrix A(true, &rows_[0], &cols_[0], &elems_[0], elems_.size());
521
A.setDimensions(nrows, ncols);
522
523
ClpSimplex model(false);
524
model.loadProblem(A, &collb_[0], &colub_[0], &obj_[0], &rowlb_[0], &rowub_[0]);
525
526
ClpDualRowSteepest dualSteep(1);
527
model.setDualRowPivotAlgorithm(dualSteep);
528
529
ClpPrimalColumnSteepest primalSteep(1);
530
model.setPrimalColumnPivotAlgorithm(primalSteep);
531
532
model.scaling(1);
533
534
ClpPresolve presolveInfo;
535
Ptr<ClpSimplex> presolvedModel(presolveInfo.presolvedModel(model));
536
537
if (presolvedModel)
538
{
539
presolvedModel->dual();
540
presolveInfo.postsolve(true);
541
model.checkSolution();
542
model.primal(1);
543
}
544
else
545
{
546
model.dual();
547
model.checkSolution();
548
model.primal(1);
549
}
550
551
// save results
552
553
const double *sol = model.getColSolution();
554
c = 0;
555
556
for (int t = 0; t < N; ++t, c += 4)
557
{
558
Mat_<float> S0 = Mat::eye(3, 3, CV_32F);
559
S0(1,1) = S0(0,0) = sol[c];
560
S0(0,1) = sol[c+1];
561
S0(1,0) = -sol[c+1];
562
S0(0,2) = sol[c+2];
563
S0(1,2) = sol[c+3];
564
S[t] = S0;
565
}
566
}
567
#endif // #ifndef HAVE_CLP
568
569
570
static inline int areaSign(Point2f a, Point2f b, Point2f c)
571
{
572
double area = (b-a).cross(c-a);
573
if (area < -1e-5) return -1;
574
if (area > 1e-5) return 1;
575
return 0;
576
}
577
578
579
static inline bool segmentsIntersect(Point2f a, Point2f b, Point2f c, Point2f d)
580
{
581
return areaSign(a,b,c) * areaSign(a,b,d) < 0 &&
582
areaSign(c,d,a) * areaSign(c,d,b) < 0;
583
}
584
585
586
// Checks if rect a (with sides parallel to axis) is inside rect b (arbitrary).
587
// Rects must be passed in the [(0,0), (w,0), (w,h), (0,h)] order.
588
static inline bool isRectInside(const Point2f a[4], const Point2f b[4])
589
{
590
for (int i = 0; i < 4; ++i)
591
if (b[i].x > a[0].x && b[i].x < a[2].x && b[i].y > a[0].y && b[i].y < a[2].y)
592
return false;
593
for (int i = 0; i < 4; ++i)
594
for (int j = 0; j < 4; ++j)
595
if (segmentsIntersect(a[i], a[(i+1)%4], b[j], b[(j+1)%4]))
596
return false;
597
return true;
598
}
599
600
601
static inline bool isGoodMotion(const float M[], float w, float h, float dx, float dy)
602
{
603
Point2f pt[4] = {Point2f(0,0), Point2f(w,0), Point2f(w,h), Point2f(0,h)};
604
Point2f Mpt[4];
605
606
for (int i = 0; i < 4; ++i)
607
{
608
Mpt[i].x = M[0]*pt[i].x + M[1]*pt[i].y + M[2];
609
Mpt[i].y = M[3]*pt[i].x + M[4]*pt[i].y + M[5];
610
float z = M[6]*pt[i].x + M[7]*pt[i].y + M[8];
611
Mpt[i].x /= z;
612
Mpt[i].y /= z;
613
}
614
615
pt[0] = Point2f(dx, dy);
616
pt[1] = Point2f(w - dx, dy);
617
pt[2] = Point2f(w - dx, h - dy);
618
pt[3] = Point2f(dx, h - dy);
619
620
return isRectInside(pt, Mpt);
621
}
622
623
624
static inline void relaxMotion(const float M[], float t, float res[])
625
{
626
res[0] = M[0]*(1.f-t) + t;
627
res[1] = M[1]*(1.f-t);
628
res[2] = M[2]*(1.f-t);
629
res[3] = M[3]*(1.f-t);
630
res[4] = M[4]*(1.f-t) + t;
631
res[5] = M[5]*(1.f-t);
632
res[6] = M[6]*(1.f-t);
633
res[7] = M[7]*(1.f-t);
634
res[8] = M[8]*(1.f-t) + t;
635
}
636
637
638
Mat ensureInclusionConstraint(const Mat &M, Size size, float trimRatio)
639
{
640
CV_INSTRUMENT_REGION();
641
642
CV_Assert(M.size() == Size(3,3) && M.type() == CV_32F);
643
644
const float w = static_cast<float>(size.width);
645
const float h = static_cast<float>(size.height);
646
const float dx = floor(w * trimRatio);
647
const float dy = floor(h * trimRatio);
648
const float srcM[] =
649
{M.at<float>(0,0), M.at<float>(0,1), M.at<float>(0,2),
650
M.at<float>(1,0), M.at<float>(1,1), M.at<float>(1,2),
651
M.at<float>(2,0), M.at<float>(2,1), M.at<float>(2,2)};
652
653
float curM[9];
654
float t = 0;
655
relaxMotion(srcM, t, curM);
656
if (isGoodMotion(curM, w, h, dx, dy))
657
return M;
658
659
float l = 0, r = 1;
660
while (r - l > 1e-3f)
661
{
662
t = (l + r) * 0.5f;
663
relaxMotion(srcM, t, curM);
664
if (isGoodMotion(curM, w, h, dx, dy))
665
r = t;
666
else
667
l = t;
668
}
669
670
return (1 - r) * M + r * Mat::eye(3, 3, CV_32F);
671
}
672
673
674
// TODO can be estimated for O(1) time
675
float estimateOptimalTrimRatio(const Mat &M, Size size)
676
{
677
CV_INSTRUMENT_REGION();
678
679
CV_Assert(M.size() == Size(3,3) && M.type() == CV_32F);
680
681
const float w = static_cast<float>(size.width);
682
const float h = static_cast<float>(size.height);
683
Mat_<float> M_(M);
684
685
Point2f pt[4] = {Point2f(0,0), Point2f(w,0), Point2f(w,h), Point2f(0,h)};
686
Point2f Mpt[4];
687
float z;
688
689
for (int i = 0; i < 4; ++i)
690
{
691
Mpt[i].x = M_(0,0)*pt[i].x + M_(0,1)*pt[i].y + M_(0,2);
692
Mpt[i].y = M_(1,0)*pt[i].x + M_(1,1)*pt[i].y + M_(1,2);
693
z = M_(2,0)*pt[i].x + M_(2,1)*pt[i].y + M_(2,2);
694
Mpt[i].x /= z;
695
Mpt[i].y /= z;
696
}
697
698
float l = 0, r = 0.5f;
699
while (r - l > 1e-3f)
700
{
701
float t = (l + r) * 0.5f;
702
float dx = floor(w * t);
703
float dy = floor(h * t);
704
pt[0] = Point2f(dx, dy);
705
pt[1] = Point2f(w - dx, dy);
706
pt[2] = Point2f(w - dx, h - dy);
707
pt[3] = Point2f(dx, h - dy);
708
if (isRectInside(pt, Mpt))
709
r = t;
710
else
711
l = t;
712
}
713
714
return r;
715
}
716
717
} // namespace videostab
718
} // namespace cv
719
720