Home | History | Annotate | Download | only in src
      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     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 
    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 
    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
    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