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