IsometricPatternMatcher/HexGridFitting.h (134 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. // // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. #pragma once #include <ceres/solver.h> #include <Eigen/Core> #include <sophus/se3.hpp> namespace surreal_opensource { class HexGridFitting { // generate the storage map of the pattern with detected image points public: HexGridFitting() {} // this constructor is used for one image input isometric pattern detection HexGridFitting(const Eigen::Matrix2Xd& imageDots, const Eigen::Vector2d& centerXY, double focalLength, const Eigen::VectorXd& intensity, bool ifDistort, bool ifTwoShot = false, bool ifPoseMerge = false, double spacing = 1.0, int numNeighboursForPoseEst = 3, int numberSegX = 3, int numberSegY = 3, double perPointSearchRadius = 0.5, int numNeighbourLayer = 2); // this constructor is used for two-shot isometric pattern detection HexGridFitting(const Eigen::Matrix2Xd& imageDots, const Eigen::Vector2d& centerXY, double focalLength, const Eigen::VectorXi& dotLabels, bool ifDistort, bool ifTwoShot = true, bool ifPoseMerge = false, double goodPoseInlierRatio = 0.2, double spacing = 1.0, int numNeighboursForPoseEst = 3, int numberSegX = 3, int numberSegY = 3, double perPointSearchRadius = 0.5, int numNeighbourLayer = 2); void Clear(); void setParams(const Eigen::Vector2d& centerXY, double focalLength, bool ifDistort, bool ifTwoShot = false, bool ifPoseMerge = false, double spacing = 1.0, int numNeighboursForPoseEst = 3, int numberSegX = 3, int numberSegY = 3, double perPointSearchRadius = 0.5, int numNeighbourLayer = 2); void setImageDots(const Eigen::Matrix2Xd& imageDots); void setTransferedDots(const Eigen::Matrix2Xd& transferedDots); void setIntensity(const Eigen::VectorXd& intensity); void setIndexMap(const Eigen::MatrixXi& indexMap); // Each matrix2Xd stores the ith dot and its numberNeighbour-1 closest // neighbours found in images std::vector<Eigen::Matrix2Xd> imageNeighbourMatrix(int numberNeighours); template <typename T> void getSortIndx(const T& coords, std::vector<int>& idx); // calculateSubregionPosesAndBestIndex calculates pose in each subregion // (block) and returns pose index based on the number of inliers // that each pose has in an acsent order, i.e. index.back() is best pose index std::vector<int> calculateSubregionPosesAndBestIndex( const ceres::Solver::Options& solverOption, const Sophus::Plane3d& plane, const std::vector<Eigen::Matrix2Xd>& neighbourDots, const Sophus::SE3d& initT_camera_target, std::vector<Sophus::SE3d>& Ts_camera_targetForSubregions, std::vector<std::vector<int>>& inliersIndx); // findGoodPoseIndex returns a vector of good poses index based on number of // inliers in descent order, e.g. returned poseIdx[0] is best pose index, the // unselected pose index will be just assigned as -1 Eigen::VectorXi findGoodPoseIndex(double goodPoseInlierRatio, const ceres::Solver::Options& solverOption, const Sophus::SE3d& initT_camera_target = Sophus::SE3d::trans(0.1, 0.1, 0.3)); // selectIndx is used to select poses as final camera pose for merge grid // grow algorithm, if selectIndx = -1, we will use best pose with most inliers // as final camera pose void findPoseAndCamModel(const ceres::Solver::Options& solverOption, int selectIndx = -1, const Sophus::SE3d& initT_camera_target = Sophus::SE3d::trans(0.1, 0.1, 0.3)); bool findT_camera_target(const ceres::Solver::Options& solverOption, const std::vector<Eigen::Matrix2Xd>& neighbourDots, const std::vector<int>& sampleIndx, double inlierThreshold, const Sophus::Plane3d& plane, Sophus::SE3d& T_camera_target, std::vector<int>& inliersIndx); // For KB3 camera distortion bool findKb3DistortionParams( const ceres::Solver::Options& solverOption, const std::vector<Eigen::Matrix2Xd>& neighbourDots, const std::vector<int>& sampleIndx, double inlierThreshold, const Sophus::Plane3d& plane, Sophus::SE3d& T_camera_target, std::vector<double>& distortionParams, std::vector<int>& inliersIndx); std::vector<int> findInliers( const std::vector<Eigen::Matrix2Xd>& neighbourDots, const Sophus::SE3d& T_camera_target, const Eigen::Vector4d& distortionParams, double inlierThreshold); Eigen::Matrix2Xd reprojectDots(const Sophus::SE3d& T_camera_target, const Eigen::Vector4d& distortionParams, const Eigen::Matrix2Xd& imageDots); void getStorageMap(); // merge results from multiple poses void buildBinaryCode(const Eigen::Matrix3Xi& cubeCoor, int maxX, int minX, int maxZ, int minZ); int getCubeCoordinate(const Eigen::Matrix2Xd& transferDots, int& minX, int& maxX, int& minZ, int& maxZ, Eigen::Matrix3Xi& cubeCoor, std::vector<int>& bfsProcessSeq); // merge cube coordinate cubeCoor2 into cubeCoor1's coordinate system with // outputs of merged cube coordinate and update X,Z coordinate // boundaries (minX, maxX, minZ, maxZ) Eigen::Matrix3Xi mergeCubeCoordinate(const Eigen::Matrix3Xi& cubeCoor1, const Eigen::Matrix3Xi& cubeCoor2, int startIdx1, int startIdx2, int& minX, int& maxX, int& minZ, int& maxZ, int poseIdx); // Rotate cube coordinate with rotIdx * 60 degrees counter-clockwise Eigen::Vector3i doLeftRotate(const Eigen::Vector3i& coord, size_t rotIdx); // Rotate cube coordinate with rotIdx * 60 degrees clockwise Eigen::Vector3i doRightRotate(const Eigen::Vector3i& coord, size_t rotIdx); // determine rotation between cube coordinates cubeCoor1 and cubeCoor2 int determineRotation(const Eigen::Matrix3Xi& cubeCoor1, const Eigen::Matrix3Xi& cubeCoor2, const Eigen::Matrix3Xi& cubeCoorDiff); void getStorageMapFromPoseSeq( const std::vector<Eigen::Matrix2Xd>& transferDotsGroup); bool neighboursIdxInArea(const Eigen::Matrix2Xd& dotMatrix, const Eigen::Vector2d& center, double searchRadius, Eigen::VectorXi& result); Eigen::Matrix2Xd getDirections(int startIndx); int findOffset(const std::array<Eigen::MatrixXi, 6>& patternReference, const Eigen::MatrixXi& pattern, Eigen::Vector2i& bestOffset, int& bestIndx) const; int getBinarycode(const Eigen::Vector2i& centerRQ, int layer); inline Sophus::SE3d T_camera_target() const { return T_camera_target_; } inline Eigen::Vector4d distortionParams() const { return distortionParams_; } inline Eigen::Matrix2Xd transferDots() const { return transferDots_; } inline Eigen::MatrixXi detectPattern() const { return detectPattern_; } // 2D map stores the index of column of detected dots inline Eigen::MatrixXi indexMap() const { return indexMap_; } inline Eigen::VectorXi binaryCode() const { return binaryCode_; } inline Eigen::Matrix2Xd searchDirectionsOnPattern() const { return searchDirectionsOnPattern_; } inline std::vector<int> bfsProcessSeq() const { return bfsProcessSeq_; } Eigen::Matrix2Xd inlierPose; Eigen::Matrix2Xd inlierDistortion; private: double spacing_; int numNeighboursForPoseEst_; // needs to be <=6 int numberSegX_; int numberSegY_; Eigen::Matrix2Xd imageDots_; Eigen::VectorXd intensity_; Eigen::VectorXi dotLabels_; Eigen::VectorXi binaryCode_; double perPointSearchRadius_; int numNeighbourLayer_; Sophus::SE3d T_camera_target_; double focalLength_; Eigen::Vector2d centerXY_; Eigen::Vector4d distortionParams_; Eigen::Matrix2Xd transferDots_; Eigen::MatrixXi detectPattern_; Eigen::MatrixXi indexMap_; Eigen::Matrix2Xd searchDirectionsOnPattern_; std::vector<int> bfsProcessSeq_; bool ifDistort_; bool ifTwoShot_; bool ifPoseMerge_; }; } // namespace surreal_opensource