estimate_rigid_transform.cpp
Go to the documentation of this file.
00001 /*M///////////////////////////////////////////////////////////////////////////////////////
00002 //
00003 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
00004 //
00005 //  By downloading, copying, installing or using the software you agree to this
00006 license.
00007 //  If you do not agree to this license, do not download, install,
00008 //  copy or use the software.
00009 //
00010 //
00011 //                           License Agreement
00012 //                For Open Source Computer Vision Library
00013 //
00014 // Copyright (C) 2000, Intel Corporation, all rights reserved.
00015 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
00016 // Copyright (C) 2016, Jiri Horner, all rights reserved.
00017 // Third party copyrights are property of their respective owners.
00018 //
00019 // Redistribution and use in source and binary forms, with or without
00020 modification,
00021 // are permitted provided that the following conditions are met:
00022 //
00023 //   * Redistribution's of source code must retain the above copyright notice,
00024 //     this list of conditions and the following disclaimer.
00025 //
00026 //   * Redistribution's in binary form must reproduce the above copyright
00027 notice,
00028 //     this list of conditions and the following disclaimer in the documentation
00029 //     and/or other materials provided with the distribution.
00030 //
00031 //   * The name of the copyright holders may not be used to endorse or promote
00032 products
00033 //     derived from this software without specific prior written permission.
00034 //
00035 // This software is provided by the copyright holders and contributors "as is"
00036 and
00037 // any express or implied warranties, including, but not limited to, the implied
00038 // warranties of merchantability and fitness for a particular purpose are
00039 disclaimed.
00040 // In no event shall the Intel Corporation or contributors be liable for any
00041 direct,
00042 // indirect, incidental, special, exemplary, or consequential damages
00043 // (including, but not limited to, procurement of substitute goods or services;
00044 // loss of use, data, or profits; or business interruption) however caused
00045 // and on any theory of liability, whether in contract, strict liability,
00046 // or tort (including negligence or otherwise) arising in any way out of
00047 // the use of this software, even if advised of the possibility of such damage.
00048 //
00049 //M*/
00050 
00051 #include <combine_grids/estimate_rigid_transform.h>
00052 
00053 #include <opencv2/video/tracking.hpp>
00054 
00055 namespace cv
00056 {
00057 /* copied from opencv source as this fuction is not exported */
00058 static void getRTMatrix(const Point2f* a, const Point2f* b, int count, Mat& M,
00059                         bool fullAffine)
00060 {
00061   CV_Assert(M.isContinuous());
00062 
00063   if (fullAffine) {
00064     double sa[6][6] = {{0.}}, sb[6] = {0.};
00065     Mat A(6, 6, CV_64F, &sa[0][0]), B(6, 1, CV_64F, sb);
00066     Mat MM = M.reshape(1, 6);
00067 
00068     for (int i = 0; i < count; i++) {
00069       sa[0][0] += a[i].x * a[i].x;
00070       sa[0][1] += a[i].y * a[i].x;
00071       sa[0][2] += a[i].x;
00072 
00073       sa[1][1] += a[i].y * a[i].y;
00074       sa[1][2] += a[i].y;
00075 
00076       sa[2][2] += 1;
00077 
00078       sb[0] += a[i].x * b[i].x;
00079       sb[1] += a[i].y * b[i].x;
00080       sb[2] += b[i].x;
00081       sb[3] += a[i].x * b[i].y;
00082       sb[4] += a[i].y * b[i].y;
00083       sb[5] += b[i].y;
00084     }
00085 
00086     sa[3][4] = sa[4][3] = sa[1][0] = sa[0][1];
00087     sa[3][5] = sa[5][3] = sa[2][0] = sa[0][2];
00088     sa[4][5] = sa[5][4] = sa[2][1] = sa[1][2];
00089 
00090     sa[3][3] = sa[0][0];
00091     sa[4][4] = sa[1][1];
00092     sa[5][5] = sa[2][2];
00093 
00094     solve(A, B, MM, DECOMP_EIG);
00095   } else {
00096     double sa[4][4] = {{0.}}, sb[4] = {0.}, m[4];
00097     Mat A(4, 4, CV_64F, sa), B(4, 1, CV_64F, sb);
00098     Mat MM(4, 1, CV_64F, m);
00099 
00100     for (int i = 0; i < count; i++) {
00101       sa[0][0] += a[i].x * a[i].x + a[i].y * a[i].y;
00102       sa[0][2] += a[i].x;
00103       sa[0][3] += a[i].y;
00104 
00105       sa[2][1] += -a[i].y;
00106       sa[2][2] += 1;
00107 
00108       sa[3][0] += a[i].y;
00109       sa[3][1] += a[i].x;
00110       sa[3][3] += 1;
00111 
00112       sb[0] += a[i].x * b[i].x + a[i].y * b[i].y;
00113       sb[1] += a[i].x * b[i].y - a[i].y * b[i].x;
00114       sb[2] += b[i].x;
00115       sb[3] += b[i].y;
00116     }
00117 
00118     sa[1][1] = sa[0][0];
00119     sa[2][1] = sa[1][2] = -sa[0][3];
00120     sa[3][1] = sa[1][3] = sa[2][0] = sa[0][2];
00121     sa[2][2] = sa[3][3] = count;
00122     sa[3][0] = sa[0][3];
00123 
00124     solve(A, B, MM, DECOMP_EIG);
00125 
00126     double* om = M.ptr<double>();
00127     om[0] = om[4] = m[0];
00128     om[1] = -m[1];
00129     om[3] = m[1];
00130     om[2] = m[2];
00131     om[5] = m[3];
00132   }
00133 }
00134 
00135 /* modified version of opencv function */
00136 Mat estimateRigidTransform(InputArray src1, InputArray src2,
00137                            OutputArray _inliers_mask, bool fullAffine)
00138 {
00139   Mat M(2, 3, CV_64F), A = src1.getMat(), B = src2.getMat();
00140 
00141   const int RANSAC_MAX_ITERS = 500;
00142   const int RANSAC_SIZE0 = 3;
00143   const double RANSAC_GOOD_RATIO = 0.5;
00144 
00145   std::vector<Point2f> pA, pB;
00146   std::vector<size_t> good_idx;
00147   Mat inliers_mask;
00148 
00149   double scale = 1.;
00150   size_t i, j, k, k1;
00151 
00152   RNG rng(static_cast<uint64>(-1));
00153   size_t good_count = 0;
00154 
00155   if (A.size() != B.size())
00156     CV_Error(Error::StsUnmatchedSizes, "Both input images must have the same "
00157                                        "size");
00158 
00159   if (A.type() != B.type())
00160     CV_Error(Error::StsUnmatchedFormats, "Both input images must have the same "
00161                                          "data type");
00162 
00163   // returns negative if not vector
00164   int vector_size = A.checkVector(2);
00165 
00166   if (vector_size > 0) {
00167     A.reshape(2, vector_size).convertTo(pA, CV_32F);
00168     B.reshape(2, vector_size).convertTo(pB, CV_32F);
00169   } else {
00170     CV_Error(Error::StsUnsupportedFormat, "This function does not support "
00171                                           "images as input.");
00172   }
00173   size_t count = static_cast<size_t>(vector_size);
00174 
00175   good_idx.resize(count);
00176   inliers_mask = Mat::zeros(static_cast<int>(count), 1, CV_8U);
00177 
00178   if (count < RANSAC_SIZE0)
00179     return Mat();
00180 
00181   Rect brect = boundingRect(pB);
00182 
00183   // RANSAC stuff:
00184   // 1. find the consensus
00185   for (k = 0; k < RANSAC_MAX_ITERS; k++) {
00186     size_t idx[RANSAC_SIZE0];
00187     Point2f a[RANSAC_SIZE0];
00188     Point2f b[RANSAC_SIZE0];
00189 
00190     // choose random 3 non-complanar points from A & B
00191     for (i = 0; i < RANSAC_SIZE0; i++) {
00192       for (k1 = 0; k1 < RANSAC_MAX_ITERS; k1++) {
00193         idx[i] = static_cast<size_t>(rng.uniform(0, static_cast<int>(count)));
00194 
00195         for (j = 0; j < i; j++) {
00196           if (idx[j] == idx[i])
00197             break;
00198           // check that the points are not very close one each other
00199           if (fabs(pA[idx[i]].x - pA[idx[j]].x) +
00200                   fabs(pA[idx[i]].y - pA[idx[j]].y) <
00201               FLT_EPSILON)
00202             break;
00203           if (fabs(pB[idx[i]].x - pB[idx[j]].x) +
00204                   fabs(pB[idx[i]].y - pB[idx[j]].y) <
00205               FLT_EPSILON)
00206             break;
00207         }
00208 
00209         if (j < i)
00210           continue;
00211 
00212         if (i + 1 == RANSAC_SIZE0) {
00213           // additional check for non-complanar vectors
00214           a[0] = pA[idx[0]];
00215           a[1] = pA[idx[1]];
00216           a[2] = pA[idx[2]];
00217 
00218           b[0] = pB[idx[0]];
00219           b[1] = pB[idx[1]];
00220           b[2] = pB[idx[2]];
00221 
00222           double dax1 = a[1].x - a[0].x, day1 = a[1].y - a[0].y;
00223           double dax2 = a[2].x - a[0].x, day2 = a[2].y - a[0].y;
00224           double dbx1 = b[1].x - b[0].x, dby1 = b[1].y - b[0].y;
00225           double dbx2 = b[2].x - b[0].x, dby2 = b[2].y - b[0].y;
00226           const double eps = 0.01;
00227 
00228           if (fabs(dax1 * day2 - day1 * dax2) <
00229                   eps * std::sqrt(dax1 * dax1 + day1 * day1) *
00230                       std::sqrt(dax2 * dax2 + day2 * day2) ||
00231               fabs(dbx1 * dby2 - dby1 * dbx2) <
00232                   eps * std::sqrt(dbx1 * dbx1 + dby1 * dby1) *
00233                       std::sqrt(dbx2 * dbx2 + dby2 * dby2))
00234             continue;
00235         }
00236         break;
00237       }
00238 
00239       if (k1 >= RANSAC_MAX_ITERS)
00240         break;
00241     }
00242 
00243     if (i < RANSAC_SIZE0)
00244       continue;
00245 
00246     // estimate the transformation using 3 points
00247     getRTMatrix(a, b, 3, M, fullAffine);
00248 
00249     const double* m = M.ptr<double>();
00250     for (i = 0, good_count = 0; i < count; i++) {
00251       if (std::abs(m[0] * pA[i].x + m[1] * pA[i].y + m[2] - pB[i].x) +
00252               std::abs(m[3] * pA[i].x + m[4] * pA[i].y + m[5] - pB[i].y) <
00253           std::max(brect.width, brect.height) * 0.05) {
00254         good_idx[good_count++] = i;
00255         inliers_mask.data[i] = true;
00256       }
00257     }
00258 
00259     if (good_count >= count * RANSAC_GOOD_RATIO)
00260       break;
00261   }
00262 
00263   if (k >= RANSAC_MAX_ITERS)
00264     return Mat();
00265 
00266   if (good_count < count) {
00267     for (i = 0; i < good_count; i++) {
00268       j = good_idx[i];
00269       pA[i] = pA[j];
00270       pB[i] = pB[j];
00271     }
00272   }
00273 
00274   getRTMatrix(&pA[0], &pB[0], static_cast<int>(good_count), M, fullAffine);
00275   M.at<double>(0, 2) /= scale;
00276   M.at<double>(1, 2) /= scale;
00277 
00278   // return inliers mask
00279   if (_inliers_mask.needed()) {
00280     inliers_mask.copyTo(_inliers_mask);
00281   }
00282 
00283   return M;
00284 }
00285 
00286 }  // namespace cv


map_merge
Author(s): Jiri Horner
autogenerated on Sun Mar 26 2017 03:48:10