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