00001 #ifndef _PEH_H_
00002 #define _PEH_H_
00003
00004 #include <frame_common/frame.h>
00005 #include <boost/shared_ptr.hpp>
00006 #include <posest/pe.h>
00007 #include <cv.h>
00008 #include <cstdlib>
00009 #include <math.h>
00010 #include <frame_common/frame.h>
00011
00012 namespace fc = frame_common;
00013 using namespace std;
00014 namespace pe
00015 {
00016 class HowardDescriptorExtractor : public cv::DescriptorExtractor
00017 {
00018 public:
00019 HowardDescriptorExtractor(int _neighborhoodSize = 7): neighborhoodSize(_neighborhoodSize)
00020 {
00021 CV_Assert(neighborhoodSize/2 != 0);
00022 }
00023
00024 virtual void read(const cv::FileNode &fn)
00025 {
00026 neighborhoodSize = fn["neighborhoodSize"];
00027 }
00028 virtual void write(cv::FileStorage &fs) const
00029 {
00030 fs << "neighborhoodSize" << neighborhoodSize;
00031 }
00032
00033 virtual int descriptorSize() const
00034 {
00035 return neighborhoodSize*neighborhoodSize - 1;
00036 }
00037 virtual int descriptorType() const
00038 {
00039 return CV_8UC1;
00040 }
00041
00042 protected:
00043 int neighborhoodSize;
00044 virtual void computeImpl(const cv::Mat& image, vector<cv::KeyPoint>& keypoints, cv::Mat& descriptors) const
00045 {
00046 cv::Mat im;
00047 if (image.channels() > 1)
00048 {
00049 cv::cvtColor(image, im, CV_BGR2GRAY);
00050 }
00051 else
00052 im = image;
00053 int borderSize = neighborhoodSize/2;
00054
00055
00056 descriptors.create(keypoints.size(), descriptorSize(), descriptorType());
00057 descriptors.setTo(cv::Scalar(0));
00058
00059 for (size_t keypointInd = 0; keypointInd < keypoints.size(); keypointInd++)
00060 {
00061 int index = 0;
00062 for(int y = keypoints[keypointInd].pt.y - borderSize; y < keypoints[keypointInd].pt.y + borderSize; y++)
00063 {
00064 for(int x = keypoints[keypointInd].pt.x - borderSize; x < keypoints[keypointInd].pt.x + borderSize; x++)
00065 {
00066 if (x == keypoints[keypointInd].pt.x && y == keypoints[keypointInd].pt.y)
00067 {
00068 continue;
00069 }
00070
00071 if (x < 0 || x >= image.cols || y < 0 || y >= image.rows)
00072 continue;
00073 descriptors.at<unsigned char>(keypointInd, index++) = im.at<unsigned char>(y, x);
00074 }
00075 }
00076 }
00077 }
00078 };
00079
00080
00081 class HowardStereoMatcher
00082 {
00083 public:
00084 HowardStereoMatcher(float thresh, int descriptorSize): threshold(thresh), descriptorSize(descriptorSize)
00085 {
00086 extractor = new HowardDescriptorExtractor(descriptorSize);
00087 }
00088
00089 void match(const frame_common::Frame& prevFrame, const frame_common::Frame& frame,
00090 vector<cv::DMatch>& matches, vector<int>& filteredIndices, const cv::Mat& mask)
00091 {
00092 if (mask.empty())
00093 {
00094 windowedMask = cv::Mat(prevFrame.kpts.size(), frame.kpts.size(), CV_8UC1, cv::Scalar::all(1));
00095 }
00096 else
00097 {
00098 mask.copyTo(windowedMask);
00099 }
00100
00101 extractor->compute(prevFrame.img, const_cast<vector<cv::KeyPoint>&>(prevFrame.kpts), prevFrameDtors);
00102 filterKpts(prevFrame.img, prevFrame.kpts, true);
00103 extractor->compute(frame.img, const_cast<vector<cv::KeyPoint>&>(frame.kpts), frameDtors);
00104 filterKpts(frame.img, frame.kpts, false);
00105
00106 cv::Mat scoreMatrix;
00107 calculateScoreMatrix(scoreMatrix);
00108 calculateCrossCheckMatches(scoreMatrix, matches);
00109
00110 cout << "After crosscheck = " << matches.size() << endl;
00111 if (matches.size())
00112 {
00113 cv::Mat consistMatrix;
00114 calculateConsistMatrix(matches, prevFrame, frame, consistMatrix);
00115 filterMatches(consistMatrix, filteredIndices);
00116 }
00117 cout << "After filtering = " << filteredIndices.size() << endl;
00118 }
00119
00120 private:
00121 void filterKpts(const cv::Mat& img, const vector<cv::KeyPoint>& kpts, bool orientation)
00122 {
00123 int border = descriptorSize/2;
00124 for (size_t ind = 0; ind < kpts.size(); ind++)
00125 {
00126 const cv::Point& kpt = kpts[ind].pt;
00127 if (kpt.x < border || kpt.x >= img.cols - border || kpt.y < border || kpt.y >= img.rows - border)
00128 {
00129 if (orientation)
00130 windowedMask.row(ind).setTo(cv::Scalar::all(0));
00131 else
00132 windowedMask.col(ind).setTo(cv::Scalar::all(0));
00133 }
00134 }
00135 }
00136
00137 void calculateScoreMatrix(cv::Mat& scoreMatrix)
00138 {
00139 scoreMatrix.create(prevFrameDtors.rows, frameDtors.rows, CV_32S);
00140 scoreMatrix.setTo(-1);
00141
00142 for (int row = 0; row < prevFrameDtors.rows; row++)
00143 for (int col = 0; col < frameDtors.rows; col++)
00144 {
00145 if (windowedMask.at<unsigned char>(row, col))
00146 {
00147
00148 scoreMatrix.at<int>(row, col) = cv::sum(cv::abs((prevFrameDtors.row(row) - frameDtors.row(col))))[0];
00149 }
00150 }
00151 }
00152
00153 void calculateCrossCheckMatches(const cv::Mat& scoreMatrix, vector<cv::DMatch>& matches)
00154 {
00155 cv::Point minIndex;
00156 vector<int> matches1to2(scoreMatrix.rows);
00157 for (int row = 0; row < scoreMatrix.rows; row++)
00158 {
00159 cv::minMaxLoc(scoreMatrix.row(row), 0, 0, &minIndex, 0, windowedMask.row(row));
00160 matches1to2[row] = minIndex.x;
00161 }
00162 vector<int> matches2to1(scoreMatrix.cols);
00163 for (int col = 0; col < scoreMatrix.cols; col++)
00164 {
00165 cv::minMaxLoc(scoreMatrix.col(col), 0, 0, &minIndex, 0, windowedMask.col(col));
00166 matches2to1[col] = minIndex.y;
00167 }
00168
00169 for (size_t mIndex = 0; mIndex < matches1to2.size(); mIndex++)
00170 {
00171 if (matches2to1[matches1to2[mIndex]] == (int)mIndex)
00172 {
00173 cv::DMatch match;
00174 match.trainIdx = matches1to2[mIndex];
00175 match.queryIdx = mIndex;
00176 matches.push_back(match);
00177 }
00178 }
00179 }
00180
00181
00182 void calculateConsistMatrix(const vector<cv::DMatch>& matches, const frame_common::Frame& prevFrame,
00183 const frame_common::Frame& frame, cv::Mat& consistMatrix)
00184 {
00185 consistMatrix.create(matches.size(), matches.size(), CV_8UC1);
00186 for (int row = 0; row < consistMatrix.rows; row++)
00187 {
00188 if (!prevFrame.goodPts[matches[row].queryIdx])
00189 {
00190 consistMatrix.row(row).setTo(cv::Scalar(0));
00191 consistMatrix.col(row).setTo(cv::Scalar(0));
00192 }
00193 else
00194 {
00195 for (int col = 0; col < row; col++)
00196 {
00197 unsigned char consistent = 0;
00198 if (frame.goodPts[matches[col].trainIdx])
00199 {
00200 Eigen::Vector4d vec = prevFrame.pts[matches[row].queryIdx];
00201 cv::Point3f p11(vec(0), vec(1), vec(2));
00202 vec = prevFrame.pts[matches[col].queryIdx];
00203 cv::Point3f p21(vec(0), vec(1), vec(2));
00204
00205 vec = frame.pts[matches[row].trainIdx];
00206 cv::Point3f p12(vec(0), vec(1), vec(2));
00207 vec = frame.pts[matches[col].trainIdx];
00208 cv::Point3f p22(vec(0), vec(1), vec(2));
00209
00210 cv::Point3f diff1 = p11 - p21;
00211 cv::Point3f diff2 = p12 - p22;
00212 if (abs(norm(diff1) - norm(diff2)) < threshold)
00213 consistent = 1;
00214 }
00215 consistMatrix.at<unsigned char>(row, col) = consistMatrix.at<unsigned char>(col, row) = consistent;
00216 }
00217 }
00218 consistMatrix.at<unsigned char>(row, row) = 1;
00219 }
00220 }
00221
00222 void filterMatches(const cv::Mat& consistMatrix, vector<int>& filteredIndices)
00223 {
00224 std::vector<int> indices;
00225
00226 cv::Mat sums(1, consistMatrix.rows, CV_32S);
00227 for (int row = 0; row < consistMatrix.rows; row++)
00228 sums.at<int>(0, row) = cv::sum(consistMatrix.row(row))[0];
00229 cv::Point maxIndex;
00230 cv::minMaxLoc(sums, 0, 0, 0, &maxIndex, cv::Mat());
00231 indices.push_back(maxIndex.x);
00232
00233 int lastAddedIndex = maxIndex.x;
00234
00235
00236 vector<int> compatibleMatches, sizes;
00237 for (int mIndex = 0; mIndex < consistMatrix.cols; mIndex++)
00238 {
00239 if (consistMatrix.at<unsigned char>(lastAddedIndex, mIndex))
00240 {
00241 compatibleMatches.push_back(mIndex);
00242 sizes.push_back(sum(consistMatrix.row(mIndex))[0]);
00243 }
00244 }
00245
00246 while(true)
00247 {
00248 vector<int>::iterator cmIter, sizeIter;
00249 if (lastAddedIndex != maxIndex.x)
00250 {
00251 for (cmIter = compatibleMatches.begin(), sizeIter = sizes.begin();
00252 cmIter != compatibleMatches.end(), sizeIter != sizes.end();)
00253 {
00254 if (consistMatrix.at<unsigned char>(lastAddedIndex, *cmIter))
00255 {
00256 cmIter++;
00257 sizeIter++;
00258 }
00259 else
00260 {
00261 cmIter = compatibleMatches.erase(cmIter);
00262 sizeIter = sizes.erase(sizeIter);
00263 }
00264 }
00265 }
00266 if (!compatibleMatches.size())
00267 break;
00268 vector<int>::iterator maxIter = compatibleMatches.end(), maxSizeIter = sizes.end();
00269 int maxSize = 0;
00270 for (cmIter = compatibleMatches.begin(), sizeIter = sizes.begin();
00271 cmIter != compatibleMatches.end(), sizeIter != sizes.end(); cmIter++, sizeIter++)
00272 {
00273 if (*sizeIter > maxSize)
00274 {
00275 maxSize = *sizeIter;
00276 maxSizeIter = sizeIter;
00277 maxIter = cmIter;
00278 }
00279 }
00280 indices.push_back(*maxIter);
00281 lastAddedIndex = *maxIter;
00282 compatibleMatches.erase(maxIter);
00283 sizes.erase(maxSizeIter);
00284 }
00285
00286 filteredIndices = indices;
00287 }
00288
00289 private:
00290 float threshold;
00291 int descriptorSize;
00292 cv::Mat prevFrameDtors, frameDtors;
00293 cv::Ptr<cv::DescriptorExtractor> extractor;
00294 cv::Mat windowedMask;
00295 };
00296
00297 class PoseEstimatorH : public PoseEstimator
00298 {
00299 public:
00300 using PoseEstimator::estimate;
00301
00302 PoseEstimatorH(int NRansac, bool LMpolish, double mind,
00303 double maxidx, double maxidd, float matcherThreshold, int minMatchesCount, int descriptorSize) :
00304 PoseEstimator(NRansac, LMpolish, mind, maxidx, maxidd), minMatchesCount(minMatchesCount)
00305 {
00306 usedMethod = Stereo;
00307 howardMatcher = new HowardStereoMatcher(matcherThreshold, descriptorSize);
00308 };
00309 ~PoseEstimatorH() { };
00310
00311 virtual int estimate(const fc::Frame& frame1, const fc::Frame& frame2);
00312
00313 virtual int estimate(const fc::Frame& frame1, const fc::Frame& frame2,
00314 const std::vector<cv::DMatch> &matches);
00315
00316 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00317 private:
00318 cv::Ptr<HowardStereoMatcher> howardMatcher;
00319 int minMatchesCount;
00320 std::vector<int> filteredIndices;
00321 };
00322
00323 }
00324 #endif // _PEH_H_