geometry_util.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //
00028 // *****************************************************************************
00029 
00030 #include <swri_image_util/geometry_util.h>
00031 
00032 #include <cmath>
00033 #include <limits>
00034 #include <vector>
00035 
00036 #include <opencv2/imgproc/imgproc.hpp>
00037 
00038 #include <Eigen/Dense>
00039 #include <Eigen/SVD>
00040 
00041 #include <swri_geometry_util/intersection.h>
00042 #include <swri_math_util/constants.h>
00043 
00044 namespace swri_image_util
00045 {
00046   bool Intersects(const BoundingBox& box1, const BoundingBox& box2)
00047   {
00048     return (box1 & box2).area() > 0;
00049   }
00050 
00051   double GetOverlappingArea(const cv::Rect& rect, const cv::Mat& rigid_transform)
00052   {
00053     // List of points corresponding to the input rectangle.
00054     std::vector<cv::Vec2d> points;
00055 
00056     // List of points correspondng to the transformed rectangle.
00057     std::vector<cv::Vec2d> points_t;
00058 
00059     // Create a point for each corner of the input rectangle.
00060     points.push_back(cv::Vec2d(rect.x, rect.y));
00061     points.push_back(cv::Vec2d(rect.x + rect.width, rect.y));
00062     points.push_back(cv::Vec2d(rect.x + rect.width, rect.y + rect.height));
00063     points.push_back(cv::Vec2d(rect.x, rect.y + rect.height));
00064 
00065     // Transform the input points to the transformed points using the rigid
00066     // transform.
00067     cv::transform(cv::InputArray(points), cv::OutputArray(points_t), rigid_transform);
00068 
00069     // Use swri_geometry_util to get the overlapping area
00070     return swri_geometry_util::PolygonIntersectionArea(points, points_t);
00071   }
00072 
00073   cv::Mat ProjectEllipsoid(const cv::Mat& ellipsoid)
00074   {
00075     cv::Mat ellipse;
00076 
00077     if (ellipsoid.rows == 3 && ellipsoid.cols == 3 && ellipsoid.type() == CV_32FC1)
00078     {
00079       if (ellipsoid.at<float>(2, 2) >= std::numeric_limits<double>::max() * 0.5)
00080       {
00081         ellipse.create(2, 2, CV_32FC1);
00082         ellipse.at<float>(0, 0) = ellipsoid.at<float>(0, 0);
00083         ellipse.at<float>(0, 1) = ellipsoid.at<float>(0, 1);
00084         ellipse.at<float>(1, 0) = ellipsoid.at<float>(1, 0);
00085         ellipse.at<float>(1, 1) = ellipsoid.at<float>(1, 1);
00086 
00087         return ellipse;
00088       }
00089 
00090       Eigen::Matrix3d A;
00091       for (size_t r = 0; r < 3; r++)
00092       {
00093         for (size_t c = 0; c < 3; c++)
00094         {
00095           A(r, c) = ellipsoid.at<float>(r, c);
00096         }
00097       }
00098 
00099       // Specify the main vector directions (x and y)
00100       Eigen::Vector3d ax1;
00101       Eigen::Vector3d ax2;
00102       ax1 << 1, 0, 0;
00103       ax2 << 0, 1, 0;
00104 
00105       // Initialize the normal vector (here the normal vector, in the state
00106       // space is in the theta direction).
00107       Eigen::Vector3d n_ax;
00108       n_ax << 0, 0, 1;
00109 
00111       // Calculate A prime //
00113 
00114       Eigen::Matrix3d A_sym_temp = A.transpose() + A;
00115 
00116       // N_ax_temp = (n_ax*n_ax')
00117       Eigen::Matrix3d N_ax_temp = n_ax * n_ax.transpose();
00118 
00119       // A_prime_1 = A_sym_temp*N_ax_temp
00120       //           = (A+A')*(n_ax*n_ax')
00121       Eigen::Matrix3d A_prime_1 = A_sym_temp * N_ax_temp;
00122 
00123       // A_prime_2 = A_prime_1*A_sym_temp
00124       //           = (A+A')*(n_ax*n_ax')*(A+A')
00125       Eigen::Matrix3d A_prime_2 = A_prime_1 * A_sym_temp;
00126 
00127       // scale_1 = n_ax'*A
00128       Eigen::RowVector3d scale_1 = n_ax.transpose() * A;
00129 
00130       // scale_2 = (scale_1*n_ax)*-4
00131       //         = (n_ax'*A*n_ax)*-4
00132       double scale = (scale_1 * n_ax)(0,0) * -4.0;
00133 
00134       // A_temp = scale*A_temp
00135       //        = scale_2*A = -4*(n_ax'*A*n_ax)*A
00136       Eigen::Matrix3d A_temp = A * scale;
00137 
00138       // Aprime = A_prime_2 + A_temp
00139       //        = (A+A')*(n_ax*n_ax')*(A+A') - 4*(n_ax'*A*n_ax)*A
00140       Eigen::Matrix3d Aprime = A_prime_2 + A_temp;
00141 
00143       // Calculate C prime //
00145 
00146       // C_temp = n_ax'*A
00147       Eigen::RowVector3d C_temp = n_ax.transpose() * A;
00148 
00149       // Cprime = -4.0*C_temp*n_ax
00150       //        = -4.0*n_ax'*A*n_ax
00151       double cp = (-4.0 * C_temp) * n_ax;
00152 
00153       // Bprime = Aprime/Cprime;
00154       Eigen::Matrix3d Bprime = Aprime / cp;
00155 
00156       // Jp = axes_def;
00157       //    = [ax1(:),ax2(:)] = [1,0;0,1;0,0];
00158       Eigen::Matrix<double, 3, 2> Jp;
00159       Jp << 1, 0,
00160             0, 1,
00161             0, 0;
00162 
00164       // Calculate D prime //
00166 
00167       // Dprime_temp = Jp'*Bprime
00168       Eigen::Matrix<double, 2, 3> Dprime_temp = Jp.transpose() * Bprime;
00169 
00170       // Dprime = Dprime_temp * Jp
00171       //        = Jp'*Bprime*Jp
00172       Eigen::Matrix2d Dprime = Dprime_temp * Jp;
00173 
00174       for (size_t r = 0; r < 2; r++)
00175       {
00176         for (size_t c = 0; c < 2; c++)
00177         {
00178           if (Dprime(r, c) != Dprime(r, c))
00179           {
00180             return ellipse;
00181           }
00182         }
00183       }
00184 
00185       ellipse.create(2, 2, CV_32FC1);
00186       ellipse.at<float>(0, 0) = Dprime(0, 0);
00187       ellipse.at<float>(0, 1) = Dprime(0, 1);
00188       ellipse.at<float>(1, 0) = Dprime(1, 0);
00189       ellipse.at<float>(1, 1) = Dprime(1, 1);
00190     }
00191 
00192     return ellipse;
00193   }
00194 
00195   std::vector<tf::Vector3> GetEllipsePoints(
00196       const cv::Mat& ellipse,
00197       const tf::Vector3& center,
00198       double scale,
00199       int32_t num_points)
00200   {
00201     std::vector<tf::Vector3> perimeter;
00202 
00203     if (ellipse.rows == 2 && ellipse.cols == 2 && ellipse.type() == CV_32FC1 &&
00204         num_points > 2)
00205     {
00206       Eigen::Matrix2d Dprime;
00207       Dprime(0, 0) = ellipse.at<float>(0, 0);
00208       Dprime(0, 1) = ellipse.at<float>(0, 1);
00209       Dprime(1, 0) = ellipse.at<float>(1, 0);
00210       Dprime(1, 1) = ellipse.at<float>(1, 1);
00211 
00212       Eigen::JacobiSVD<Eigen::Matrix2d> svd(Dprime, Eigen::ComputeFullV);
00213 
00214       Eigen::Vector2d Sigma = svd.singularValues();
00215       Eigen::Matrix2d Vt = svd.matrixV().transpose();
00216 
00217       double xprime_scale = std::sqrt(Sigma(0));
00218       double yprime_scale = std::sqrt(Sigma(1));
00219 
00220       if (xprime_scale <= 0 || yprime_scale <= 0)
00221       {
00222         return perimeter;
00223       }
00224 
00225       Eigen::MatrixX2d Xp1(num_points, 2);
00226       for (int32_t i = 0; i < num_points; i++)
00227       {
00228         double phi =
00229             (static_cast<double>(i) / static_cast<double>(num_points))
00230             * swri_math_util::_2pi;
00231 
00232         Xp1(i, 0) = xprime_scale * std::cos(phi) * scale;
00233         Xp1(i, 1) = yprime_scale * std::sin(phi) * scale;
00234       }
00235 
00236       // Xell = Xp1*(V')'
00237       Eigen::MatrixX2d Xell = Xp1 * Vt;
00238 
00239       perimeter.resize(num_points);
00240       for (int32_t i = 0; i < num_points; i++)
00241       {
00242         perimeter[i].setX(Xell(i, 0) + center.x());
00243         perimeter[i].setY(Xell(i, 1) + center.y());
00244       }
00245     }
00246 
00247     return perimeter;
00248   }
00249 }


swri_image_util
Author(s): Kris Kozak
autogenerated on Tue Oct 3 2017 03:19:34