Path: blob/master/modules/videostab/src/motion_stabilizing.cpp
16354 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#include "precomp.hpp"43#include "opencv2/videostab/motion_stabilizing.hpp"44#include "opencv2/videostab/global_motion.hpp"45#include "opencv2/videostab/ring_buffer.hpp"46#include "clp.hpp"4748namespace cv49{50namespace videostab51{5253void MotionStabilizationPipeline::stabilize(54int size, const std::vector<Mat> &motions, std::pair<int,int> range, Mat *stabilizationMotions)55{56std::vector<Mat> updatedMotions(motions.size());57for (size_t i = 0; i < motions.size(); ++i)58updatedMotions[i] = motions[i].clone();5960std::vector<Mat> stabilizationMotions_(size);6162for (int i = 0; i < size; ++i)63stabilizationMotions[i] = Mat::eye(3, 3, CV_32F);6465for (size_t i = 0; i < stabilizers_.size(); ++i)66{67stabilizers_[i]->stabilize(size, updatedMotions, range, &stabilizationMotions_[0]);6869for (int k = 0; k < size; ++k)70stabilizationMotions[k] = stabilizationMotions_[k] * stabilizationMotions[k];7172for (int j = 0; j + 1 < size; ++j)73{74Mat S0 = stabilizationMotions[j];75Mat S1 = stabilizationMotions[j+1];76at(j, updatedMotions) = S1 * at(j, updatedMotions) * S0.inv();77}78}79}808182void MotionFilterBase::stabilize(83int size, const std::vector<Mat> &motions, std::pair<int,int> range, Mat *stabilizationMotions)84{85for (int i = 0; i < size; ++i)86stabilizationMotions[i] = stabilize(i, motions, range);87}888990void GaussianMotionFilter::setParams(int _radius, float _stdev)91{92radius_ = _radius;93stdev_ = _stdev > 0.f ? _stdev : std::sqrt(static_cast<float>(_radius));9495float sum = 0;96weight_.resize(2*radius_ + 1);97for (int i = -radius_; i <= radius_; ++i)98sum += weight_[radius_ + i] = std::exp(-i*i/(stdev_*stdev_));99for (int i = -radius_; i <= radius_; ++i)100weight_[radius_ + i] /= sum;101}102103104Mat GaussianMotionFilter::stabilize(int idx, const std::vector<Mat> &motions, std::pair<int,int> range)105{106const Mat &cur = at(idx, motions);107Mat res = Mat::zeros(cur.size(), cur.type());108float sum = 0.f;109int iMin = std::max(idx - radius_, range.first);110int iMax = std::min(idx + radius_, range.second);111for (int i = iMin; i <= iMax; ++i)112{113res += weight_[radius_ + i - idx] * getMotion(idx, i, motions);114sum += weight_[radius_ + i - idx];115}116return sum > 0.f ? res / sum : Mat::eye(cur.size(), cur.type());117}118119120LpMotionStabilizer::LpMotionStabilizer(MotionModel model)121{122setMotionModel(model);123setFrameSize(Size(0,0));124setTrimRatio(0.1f);125setWeight1(1);126setWeight2(10);127setWeight3(100);128setWeight4(100);129}130131132#ifndef HAVE_CLP133134void LpMotionStabilizer::stabilize(int, const std::vector<Mat>&, std::pair<int,int>, Mat*)135{136CV_Error(Error::StsError, "The library is built without Clp support");137}138139#else140141void LpMotionStabilizer::stabilize(142int size, const std::vector<Mat> &motions, std::pair<int,int> /*range*/, Mat *stabilizationMotions)143{144CV_Assert(model_ <= MM_AFFINE);145146int N = size;147const std::vector<Mat> &M = motions;148Mat *S = stabilizationMotions;149150double w = frameSize_.width, h = frameSize_.height;151double tw = w * trimRatio_, th = h * trimRatio_;152153int ncols = 4*N + 6*(N-1) + 6*(N-2) + 6*(N-3);154int nrows = 8*N + 2*6*(N-1) + 2*6*(N-2) + 2*6*(N-3);155156rows_.clear();157cols_.clear();158elems_.clear();159160obj_.assign(ncols, 0);161collb_.assign(ncols, -INF);162colub_.assign(ncols, INF);163int c = 4*N;164165// for each slack variable e[t] (error bound)166for (int t = 0; t < N-1; ++t, c += 6)167{168// e[t](0,0)169obj_[c] = w4_*w1_;170collb_[c] = 0;171172// e[t](0,1)173obj_[c+1] = w4_*w1_;174collb_[c+1] = 0;175176// e[t](0,2)177obj_[c+2] = w1_;178collb_[c+2] = 0;179180// e[t](1,0)181obj_[c+3] = w4_*w1_;182collb_[c+3] = 0;183184// e[t](1,1)185obj_[c+4] = w4_*w1_;186collb_[c+4] = 0;187188// e[t](1,2)189obj_[c+5] = w1_;190collb_[c+5] = 0;191}192for (int t = 0; t < N-2; ++t, c += 6)193{194// e[t](0,0)195obj_[c] = w4_*w2_;196collb_[c] = 0;197198// e[t](0,1)199obj_[c+1] = w4_*w2_;200collb_[c+1] = 0;201202// e[t](0,2)203obj_[c+2] = w2_;204collb_[c+2] = 0;205206// e[t](1,0)207obj_[c+3] = w4_*w2_;208collb_[c+3] = 0;209210// e[t](1,1)211obj_[c+4] = w4_*w2_;212collb_[c+4] = 0;213214// e[t](1,2)215obj_[c+5] = w2_;216collb_[c+5] = 0;217}218for (int t = 0; t < N-3; ++t, c += 6)219{220// e[t](0,0)221obj_[c] = w4_*w3_;222collb_[c] = 0;223224// e[t](0,1)225obj_[c+1] = w4_*w3_;226collb_[c+1] = 0;227228// e[t](0,2)229obj_[c+2] = w3_;230collb_[c+2] = 0;231232// e[t](1,0)233obj_[c+3] = w4_*w3_;234collb_[c+3] = 0;235236// e[t](1,1)237obj_[c+4] = w4_*w3_;238collb_[c+4] = 0;239240// e[t](1,2)241obj_[c+5] = w3_;242collb_[c+5] = 0;243}244245elems_.clear();246rowlb_.assign(nrows, -INF);247rowub_.assign(nrows, INF);248249int r = 0;250251// frame corners252const Point2d pt[] = {Point2d(0,0), Point2d(w,0), Point2d(w,h), Point2d(0,h)};253254// for each frame255for (int t = 0; t < N; ++t)256{257c = 4*t;258259// for each frame corner260for (int i = 0; i < 4; ++i, r += 2)261{262set(r, c, pt[i].x); set(r, c+1, pt[i].y); set(r, c+2, 1);263set(r+1, c, pt[i].y); set(r+1, c+1, -pt[i].x); set(r+1, c+3, 1);264rowlb_[r] = pt[i].x-tw;265rowub_[r] = pt[i].x+tw;266rowlb_[r+1] = pt[i].y-th;267rowub_[r+1] = pt[i].y+th;268}269}270271// for each S[t+1]M[t] - S[t] - e[t] <= 0 condition272for (int t = 0; t < N-1; ++t, r += 6)273{274Mat_<float> M0 = at(t,M);275276c = 4*t;277set(r, c, -1);278set(r+1, c+1, -1);279set(r+2, c+2, -1);280set(r+3, c+1, 1);281set(r+4, c, -1);282set(r+5, c+3, -1);283284c = 4*(t+1);285set(r, c, M0(0,0)); set(r, c+1, M0(1,0));286set(r+1, c, M0(0,1)); set(r+1, c+1, M0(1,1));287set(r+2, c, M0(0,2)); set(r+2, c+1, M0(1,2)); set(r+2, c+2, 1);288set(r+3, c, M0(1,0)); set(r+3, c+1, -M0(0,0));289set(r+4, c, M0(1,1)); set(r+4, c+1, -M0(0,1));290set(r+5, c, M0(1,2)); set(r+5, c+1, -M0(0,2)); set(r+5, c+3, 1);291292c = 4*N + 6*t;293for (int i = 0; i < 6; ++i)294set(r+i, c+i, -1);295296rowub_[r] = 0;297rowub_[r+1] = 0;298rowub_[r+2] = 0;299rowub_[r+3] = 0;300rowub_[r+4] = 0;301rowub_[r+5] = 0;302}303304// for each 0 <= S[t+1]M[t] - S[t] + e[t] condition305for (int t = 0; t < N-1; ++t, r += 6)306{307Mat_<float> M0 = at(t,M);308309c = 4*t;310set(r, c, -1);311set(r+1, c+1, -1);312set(r+2, c+2, -1);313set(r+3, c+1, 1);314set(r+4, c, -1);315set(r+5, c+3, -1);316317c = 4*(t+1);318set(r, c, M0(0,0)); set(r, c+1, M0(1,0));319set(r+1, c, M0(0,1)); set(r+1, c+1, M0(1,1));320set(r+2, c, M0(0,2)); set(r+2, c+1, M0(1,2)); set(r+2, c+2, 1);321set(r+3, c, M0(1,0)); set(r+3, c+1, -M0(0,0));322set(r+4, c, M0(1,1)); set(r+4, c+1, -M0(0,1));323set(r+5, c, M0(1,2)); set(r+5, c+1, -M0(0,2)); set(r+5, c+3, 1);324325c = 4*N + 6*t;326for (int i = 0; i < 6; ++i)327set(r+i, c+i, 1);328329rowlb_[r] = 0;330rowlb_[r+1] = 0;331rowlb_[r+2] = 0;332rowlb_[r+3] = 0;333rowlb_[r+4] = 0;334rowlb_[r+5] = 0;335}336337// for each S[t+2]M[t+1] - S[t+1]*(I+M[t]) + S[t] - e[t] <= 0 condition338for (int t = 0; t < N-2; ++t, r += 6)339{340Mat_<float> M0 = at(t,M), M1 = at(t+1,M);341342c = 4*t;343set(r, c, 1);344set(r+1, c+1, 1);345set(r+2, c+2, 1);346set(r+3, c+1, -1);347set(r+4, c, 1);348set(r+5, c+3, 1);349350c = 4*(t+1);351set(r, c, -M0(0,0)-1); set(r, c+1, -M0(1,0));352set(r+1, c, -M0(0,1)); set(r+1, c+1, -M0(1,1)-1);353set(r+2, c, -M0(0,2)); set(r+2, c+1, -M0(1,2)); set(r+2, c+2, -2);354set(r+3, c, -M0(1,0)); set(r+3, c+1, M0(0,0)+1);355set(r+4, c, -M0(1,1)-1); set(r+4, c+1, M0(0,1));356set(r+5, c, -M0(1,2)); set(r+5, c+1, M0(0,2)); set(r+5, c+3, -2);357358c = 4*(t+2);359set(r, c, M1(0,0)); set(r, c+1, M1(1,0));360set(r+1, c, M1(0,1)); set(r+1, c+1, M1(1,1));361set(r+2, c, M1(0,2)); set(r+2, c+1, M1(1,2)); set(r+2, c+2, 1);362set(r+3, c, M1(1,0)); set(r+3, c+1, -M1(0,0));363set(r+4, c, M1(1,1)); set(r+4, c+1, -M1(0,1));364set(r+5, c, M1(1,2)); set(r+5, c+1, -M1(0,2)); set(r+5, c+3, 1);365366c = 4*N + 6*(N-1) + 6*t;367for (int i = 0; i < 6; ++i)368set(r+i, c+i, -1);369370rowub_[r] = 0;371rowub_[r+1] = 0;372rowub_[r+2] = 0;373rowub_[r+3] = 0;374rowub_[r+4] = 0;375rowub_[r+5] = 0;376}377378// for each 0 <= S[t+2]M[t+1]] - S[t+1]*(I+M[t]) + S[t] + e[t] condition379for (int t = 0; t < N-2; ++t, r += 6)380{381Mat_<float> M0 = at(t,M), M1 = at(t+1,M);382383c = 4*t;384set(r, c, 1);385set(r+1, c+1, 1);386set(r+2, c+2, 1);387set(r+3, c+1, -1);388set(r+4, c, 1);389set(r+5, c+3, 1);390391c = 4*(t+1);392set(r, c, -M0(0,0)-1); set(r, c+1, -M0(1,0));393set(r+1, c, -M0(0,1)); set(r+1, c+1, -M0(1,1)-1);394set(r+2, c, -M0(0,2)); set(r+2, c+1, -M0(1,2)); set(r+2, c+2, -2);395set(r+3, c, -M0(1,0)); set(r+3, c+1, M0(0,0)+1);396set(r+4, c, -M0(1,1)-1); set(r+4, c+1, M0(0,1));397set(r+5, c, -M0(1,2)); set(r+5, c+1, M0(0,2)); set(r+5, c+3, -2);398399c = 4*(t+2);400set(r, c, M1(0,0)); set(r, c+1, M1(1,0));401set(r+1, c, M1(0,1)); set(r+1, c+1, M1(1,1));402set(r+2, c, M1(0,2)); set(r+2, c+1, M1(1,2)); set(r+2, c+2, 1);403set(r+3, c, M1(1,0)); set(r+3, c+1, -M1(0,0));404set(r+4, c, M1(1,1)); set(r+4, c+1, -M1(0,1));405set(r+5, c, M1(1,2)); set(r+5, c+1, -M1(0,2)); set(r+5, c+3, 1);406407c = 4*N + 6*(N-1) + 6*t;408for (int i = 0; i < 6; ++i)409set(r+i, c+i, 1);410411rowlb_[r] = 0;412rowlb_[r+1] = 0;413rowlb_[r+2] = 0;414rowlb_[r+3] = 0;415rowlb_[r+4] = 0;416rowlb_[r+5] = 0;417}418419// 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 condition420for (int t = 0; t < N-3; ++t, r += 6)421{422Mat_<float> M0 = at(t,M), M1 = at(t+1,M), M2 = at(t+2,M);423424c = 4*t;425set(r, c, -1);426set(r+1, c+1, -1);427set(r+2, c+2, -1);428set(r+3, c+1, 1);429set(r+4, c, -1);430set(r+5, c+3, -1);431432c = 4*(t+1);433set(r, c, M0(0,0)+2); set(r, c+1, M0(1,0));434set(r+1, c, M0(0,1)); set(r+1, c+1, M0(1,1)+2);435set(r+2, c, M0(0,2)); set(r+2, c+1, M0(1,2)); set(r+2, c+2, 3);436set(r+3, c, M0(1,0)); set(r+3, c+1, -M0(0,0)-2);437set(r+4, c, M0(1,1)+2); set(r+4, c+1, -M0(0,1));438set(r+5, c, M0(1,2)); set(r+5, c+1, -M0(0,2)); set(r+5, c+3, 3);439440c = 4*(t+2);441set(r, c, -2*M1(0,0)-1); set(r, c+1, -2*M1(1,0));442set(r+1, c, -2*M1(0,1)); set(r+1, c+1, -2*M1(1,1)-1);443set(r+2, c, -2*M1(0,2)); set(r+2, c+1, -2*M1(1,2)); set(r+2, c+2, -3);444set(r+3, c, -2*M1(1,0)); set(r+3, c+1, 2*M1(0,0)+1);445set(r+4, c, -2*M1(1,1)-1); set(r+4, c+1, 2*M1(0,1));446set(r+5, c, -2*M1(1,2)); set(r+5, c+1, 2*M1(0,2)); set(r+5, c+3, -3);447448c = 4*(t+3);449set(r, c, M2(0,0)); set(r, c+1, M2(1,0));450set(r+1, c, M2(0,1)); set(r+1, c+1, M2(1,1));451set(r+2, c, M2(0,2)); set(r+2, c+1, M2(1,2)); set(r+2, c+2, 1);452set(r+3, c, M2(1,0)); set(r+3, c+1, -M2(0,0));453set(r+4, c, M2(1,1)); set(r+4, c+1, -M2(0,1));454set(r+5, c, M2(1,2)); set(r+5, c+1, -M2(0,2)); set(r+5, c+3, 1);455456c = 4*N + 6*(N-1) + 6*(N-2) + 6*t;457for (int i = 0; i < 6; ++i)458set(r+i, c+i, -1);459460rowub_[r] = 0;461rowub_[r+1] = 0;462rowub_[r+2] = 0;463rowub_[r+3] = 0;464rowub_[r+4] = 0;465rowub_[r+5] = 0;466}467468// 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] condition469for (int t = 0; t < N-3; ++t, r += 6)470{471Mat_<float> M0 = at(t,M), M1 = at(t+1,M), M2 = at(t+2,M);472473c = 4*t;474set(r, c, -1);475set(r+1, c+1, -1);476set(r+2, c+2, -1);477set(r+3, c+1, 1);478set(r+4, c, -1);479set(r+5, c+3, -1);480481c = 4*(t+1);482set(r, c, M0(0,0)+2); set(r, c+1, M0(1,0));483set(r+1, c, M0(0,1)); set(r+1, c+1, M0(1,1)+2);484set(r+2, c, M0(0,2)); set(r+2, c+1, M0(1,2)); set(r+2, c+2, 3);485set(r+3, c, M0(1,0)); set(r+3, c+1, -M0(0,0)-2);486set(r+4, c, M0(1,1)+2); set(r+4, c+1, -M0(0,1));487set(r+5, c, M0(1,2)); set(r+5, c+1, -M0(0,2)); set(r+5, c+3, 3);488489c = 4*(t+2);490set(r, c, -2*M1(0,0)-1); set(r, c+1, -2*M1(1,0));491set(r+1, c, -2*M1(0,1)); set(r+1, c+1, -2*M1(1,1)-1);492set(r+2, c, -2*M1(0,2)); set(r+2, c+1, -2*M1(1,2)); set(r+2, c+2, -3);493set(r+3, c, -2*M1(1,0)); set(r+3, c+1, 2*M1(0,0)+1);494set(r+4, c, -2*M1(1,1)-1); set(r+4, c+1, 2*M1(0,1));495set(r+5, c, -2*M1(1,2)); set(r+5, c+1, 2*M1(0,2)); set(r+5, c+3, -3);496497c = 4*(t+3);498set(r, c, M2(0,0)); set(r, c+1, M2(1,0));499set(r+1, c, M2(0,1)); set(r+1, c+1, M2(1,1));500set(r+2, c, M2(0,2)); set(r+2, c+1, M2(1,2)); set(r+2, c+2, 1);501set(r+3, c, M2(1,0)); set(r+3, c+1, -M2(0,0));502set(r+4, c, M2(1,1)); set(r+4, c+1, -M2(0,1));503set(r+5, c, M2(1,2)); set(r+5, c+1, -M2(0,2)); set(r+5, c+3, 1);504505c = 4*N + 6*(N-1) + 6*(N-2) + 6*t;506for (int i = 0; i < 6; ++i)507set(r+i, c+i, 1);508509rowlb_[r] = 0;510rowlb_[r+1] = 0;511rowlb_[r+2] = 0;512rowlb_[r+3] = 0;513rowlb_[r+4] = 0;514rowlb_[r+5] = 0;515}516517// solve518519CoinPackedMatrix A(true, &rows_[0], &cols_[0], &elems_[0], elems_.size());520A.setDimensions(nrows, ncols);521522ClpSimplex model(false);523model.loadProblem(A, &collb_[0], &colub_[0], &obj_[0], &rowlb_[0], &rowub_[0]);524525ClpDualRowSteepest dualSteep(1);526model.setDualRowPivotAlgorithm(dualSteep);527528ClpPrimalColumnSteepest primalSteep(1);529model.setPrimalColumnPivotAlgorithm(primalSteep);530531model.scaling(1);532533ClpPresolve presolveInfo;534Ptr<ClpSimplex> presolvedModel(presolveInfo.presolvedModel(model));535536if (presolvedModel)537{538presolvedModel->dual();539presolveInfo.postsolve(true);540model.checkSolution();541model.primal(1);542}543else544{545model.dual();546model.checkSolution();547model.primal(1);548}549550// save results551552const double *sol = model.getColSolution();553c = 0;554555for (int t = 0; t < N; ++t, c += 4)556{557Mat_<float> S0 = Mat::eye(3, 3, CV_32F);558S0(1,1) = S0(0,0) = sol[c];559S0(0,1) = sol[c+1];560S0(1,0) = -sol[c+1];561S0(0,2) = sol[c+2];562S0(1,2) = sol[c+3];563S[t] = S0;564}565}566#endif // #ifndef HAVE_CLP567568569static inline int areaSign(Point2f a, Point2f b, Point2f c)570{571double area = (b-a).cross(c-a);572if (area < -1e-5) return -1;573if (area > 1e-5) return 1;574return 0;575}576577578static inline bool segmentsIntersect(Point2f a, Point2f b, Point2f c, Point2f d)579{580return areaSign(a,b,c) * areaSign(a,b,d) < 0 &&581areaSign(c,d,a) * areaSign(c,d,b) < 0;582}583584585// Checks if rect a (with sides parallel to axis) is inside rect b (arbitrary).586// Rects must be passed in the [(0,0), (w,0), (w,h), (0,h)] order.587static inline bool isRectInside(const Point2f a[4], const Point2f b[4])588{589for (int i = 0; i < 4; ++i)590if (b[i].x > a[0].x && b[i].x < a[2].x && b[i].y > a[0].y && b[i].y < a[2].y)591return false;592for (int i = 0; i < 4; ++i)593for (int j = 0; j < 4; ++j)594if (segmentsIntersect(a[i], a[(i+1)%4], b[j], b[(j+1)%4]))595return false;596return true;597}598599600static inline bool isGoodMotion(const float M[], float w, float h, float dx, float dy)601{602Point2f pt[4] = {Point2f(0,0), Point2f(w,0), Point2f(w,h), Point2f(0,h)};603Point2f Mpt[4];604605for (int i = 0; i < 4; ++i)606{607Mpt[i].x = M[0]*pt[i].x + M[1]*pt[i].y + M[2];608Mpt[i].y = M[3]*pt[i].x + M[4]*pt[i].y + M[5];609float z = M[6]*pt[i].x + M[7]*pt[i].y + M[8];610Mpt[i].x /= z;611Mpt[i].y /= z;612}613614pt[0] = Point2f(dx, dy);615pt[1] = Point2f(w - dx, dy);616pt[2] = Point2f(w - dx, h - dy);617pt[3] = Point2f(dx, h - dy);618619return isRectInside(pt, Mpt);620}621622623static inline void relaxMotion(const float M[], float t, float res[])624{625res[0] = M[0]*(1.f-t) + t;626res[1] = M[1]*(1.f-t);627res[2] = M[2]*(1.f-t);628res[3] = M[3]*(1.f-t);629res[4] = M[4]*(1.f-t) + t;630res[5] = M[5]*(1.f-t);631res[6] = M[6]*(1.f-t);632res[7] = M[7]*(1.f-t);633res[8] = M[8]*(1.f-t) + t;634}635636637Mat ensureInclusionConstraint(const Mat &M, Size size, float trimRatio)638{639CV_INSTRUMENT_REGION();640641CV_Assert(M.size() == Size(3,3) && M.type() == CV_32F);642643const float w = static_cast<float>(size.width);644const float h = static_cast<float>(size.height);645const float dx = floor(w * trimRatio);646const float dy = floor(h * trimRatio);647const float srcM[] =648{M.at<float>(0,0), M.at<float>(0,1), M.at<float>(0,2),649M.at<float>(1,0), M.at<float>(1,1), M.at<float>(1,2),650M.at<float>(2,0), M.at<float>(2,1), M.at<float>(2,2)};651652float curM[9];653float t = 0;654relaxMotion(srcM, t, curM);655if (isGoodMotion(curM, w, h, dx, dy))656return M;657658float l = 0, r = 1;659while (r - l > 1e-3f)660{661t = (l + r) * 0.5f;662relaxMotion(srcM, t, curM);663if (isGoodMotion(curM, w, h, dx, dy))664r = t;665else666l = t;667}668669return (1 - r) * M + r * Mat::eye(3, 3, CV_32F);670}671672673// TODO can be estimated for O(1) time674float estimateOptimalTrimRatio(const Mat &M, Size size)675{676CV_INSTRUMENT_REGION();677678CV_Assert(M.size() == Size(3,3) && M.type() == CV_32F);679680const float w = static_cast<float>(size.width);681const float h = static_cast<float>(size.height);682Mat_<float> M_(M);683684Point2f pt[4] = {Point2f(0,0), Point2f(w,0), Point2f(w,h), Point2f(0,h)};685Point2f Mpt[4];686float z;687688for (int i = 0; i < 4; ++i)689{690Mpt[i].x = M_(0,0)*pt[i].x + M_(0,1)*pt[i].y + M_(0,2);691Mpt[i].y = M_(1,0)*pt[i].x + M_(1,1)*pt[i].y + M_(1,2);692z = M_(2,0)*pt[i].x + M_(2,1)*pt[i].y + M_(2,2);693Mpt[i].x /= z;694Mpt[i].y /= z;695}696697float l = 0, r = 0.5f;698while (r - l > 1e-3f)699{700float t = (l + r) * 0.5f;701float dx = floor(w * t);702float dy = floor(h * t);703pt[0] = Point2f(dx, dy);704pt[1] = Point2f(w - dx, dy);705pt[2] = Point2f(w - dx, h - dy);706pt[3] = Point2f(dx, h - dy);707if (isRectInside(pt, Mpt))708r = t;709else710l = t;711}712713return r;714}715716} // namespace videostab717} // namespace cv718719720