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
stabilize(int size,const std::vector<Mat> & motions,std::pair<int,int> range,Mat * stabilizationMotions)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
stabilize(int size,const std::vector<Mat> & motions,std::pair<int,int> range,Mat * stabilizationMotions)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
setParams(int _radius,float _stdev)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
stabilize(int idx,const std::vector<Mat> & motions,std::pair<int,int> range)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
LpMotionStabilizer(MotionModel model)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
stabilize(int,const std::vector<Mat> &,std::pair<int,int>,Mat *)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
stabilize(int size,const std::vector<Mat> & motions,std::pair<int,int>,Mat * stabilizationMotions)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
areaSign(Point2f a,Point2f b,Point2f c)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
segmentsIntersect(Point2f a,Point2f b,Point2f c,Point2f d)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.
isRectInside(const Point2f a[4],const Point2f b[4])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
isGoodMotion(const float M[],float w,float h,float dx,float dy)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 float z;
606
607 for (int i = 0; i < 4; ++i)
608 {
609 Mpt[i].x = M[0]*pt[i].x + M[1]*pt[i].y + M[2];
610 Mpt[i].y = M[3]*pt[i].x + M[4]*pt[i].y + M[5];
611 z = M[6]*pt[i].x + M[7]*pt[i].y + M[8];
612 Mpt[i].x /= z;
613 Mpt[i].y /= z;
614 }
615
616 pt[0] = Point2f(dx, dy);
617 pt[1] = Point2f(w - dx, dy);
618 pt[2] = Point2f(w - dx, h - dy);
619 pt[3] = Point2f(dx, h - dy);
620
621 return isRectInside(pt, Mpt);
622 }
623
624
relaxMotion(const float M[],float t,float res[])625 static inline void relaxMotion(const float M[], float t, float res[])
626 {
627 res[0] = M[0]*(1.f-t) + t;
628 res[1] = M[1]*(1.f-t);
629 res[2] = M[2]*(1.f-t);
630 res[3] = M[3]*(1.f-t);
631 res[4] = M[4]*(1.f-t) + t;
632 res[5] = M[5]*(1.f-t);
633 res[6] = M[6]*(1.f-t);
634 res[7] = M[7]*(1.f-t);
635 res[8] = M[8]*(1.f-t) + t;
636 }
637
638
ensureInclusionConstraint(const Mat & M,Size size,float trimRatio)639 Mat ensureInclusionConstraint(const Mat &M, Size size, float trimRatio)
640 {
641 CV_Assert(M.size() == Size(3,3) && M.type() == CV_32F);
642
643 const float w = static_cast<float>(size.width);
644 const float h = static_cast<float>(size.height);
645 const float dx = floor(w * trimRatio);
646 const float dy = floor(h * trimRatio);
647 const float srcM[] =
648 {M.at<float>(0,0), M.at<float>(0,1), M.at<float>(0,2),
649 M.at<float>(1,0), M.at<float>(1,1), M.at<float>(1,2),
650 M.at<float>(2,0), M.at<float>(2,1), M.at<float>(2,2)};
651
652 float curM[9];
653 float t = 0;
654 relaxMotion(srcM, t, curM);
655 if (isGoodMotion(curM, w, h, dx, dy))
656 return M;
657
658 float l = 0, r = 1;
659 while (r - l > 1e-3f)
660 {
661 t = (l + r) * 0.5f;
662 relaxMotion(srcM, t, curM);
663 if (isGoodMotion(curM, w, h, dx, dy))
664 r = t;
665 else
666 l = t;
667 }
668
669 return (1 - r) * M + r * Mat::eye(3, 3, CV_32F);
670 }
671
672
673 // TODO can be estimated for O(1) time
estimateOptimalTrimRatio(const Mat & M,Size size)674 float estimateOptimalTrimRatio(const Mat &M, Size size)
675 {
676 CV_Assert(M.size() == Size(3,3) && M.type() == CV_32F);
677
678 const float w = static_cast<float>(size.width);
679 const float h = static_cast<float>(size.height);
680 Mat_<float> M_(M);
681
682 Point2f pt[4] = {Point2f(0,0), Point2f(w,0), Point2f(w,h), Point2f(0,h)};
683 Point2f Mpt[4];
684 float z;
685
686 for (int i = 0; i < 4; ++i)
687 {
688 Mpt[i].x = M_(0,0)*pt[i].x + M_(0,1)*pt[i].y + M_(0,2);
689 Mpt[i].y = M_(1,0)*pt[i].x + M_(1,1)*pt[i].y + M_(1,2);
690 z = M_(2,0)*pt[i].x + M_(2,1)*pt[i].y + M_(2,2);
691 Mpt[i].x /= z;
692 Mpt[i].y /= z;
693 }
694
695 float l = 0, r = 0.5f;
696 while (r - l > 1e-3f)
697 {
698 float t = (l + r) * 0.5f;
699 float dx = floor(w * t);
700 float dy = floor(h * t);
701 pt[0] = Point2f(dx, dy);
702 pt[1] = Point2f(w - dx, dy);
703 pt[2] = Point2f(w - dx, h - dy);
704 pt[3] = Point2f(dx, h - dy);
705 if (isRectInside(pt, Mpt))
706 r = t;
707 else
708 l = t;
709 }
710
711 return r;
712 }
713
714 } // namespace videostab
715 } // namespace cv
716