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
49namespace cv
50{
51namespace videostab
52{
53
54void 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
83void 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
91void 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
105Mat 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
121LpMotionStabilizer::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
135void 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
142void 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
570static 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
579static 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.
588static 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
601static 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
625static 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
639Mat 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
674float 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