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