From f6fc39ce8ff602302b6f2be1890bf1fd96ea5868 Mon Sep 17 00:00:00 2001 From: Juan Manuel Perez Date: Wed, 25 Sep 2013 23:25:10 +0200 Subject: [PATCH] Putting definitions of SCD and SCDMatcher separated from sc_dis.cpp file --- modules/shape/src/sc_dis.cpp | 989 ++++++++++++++++++++---------------------- modules/shape/src/scd_def.hpp | 128 ++++++ 2 files changed, 589 insertions(+), 528 deletions(-) create mode 100644 modules/shape/src/scd_def.hpp diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp index f19080b..fc5ed42 100644 --- a/modules/shape/src/sc_dis.cpp +++ b/modules/shape/src/sc_dis.cpp @@ -46,532 +46,7 @@ */ #include "precomp.hpp" #include "opencv2/core.hpp" -/* - * ShapeContextDescriptor class - */ -class SCD -{ -public: - //! the full constructor taking all the necessary parameters - explicit SCD(int _nAngularBins=12, int _nRadialBins=5, - double _innerRadius=0.1, double _outerRadius=1, bool _rotationInvariant=false) - { - setAngularBins(_nAngularBins); - setRadialBins(_nRadialBins); - setInnerRadius(_innerRadius); - setOuterRadius(_outerRadius); - setRotationInvariant(_rotationInvariant); - } - - void extractSCD(cv::Mat& contour, cv::Mat& descriptors, - const std::vector& queryInliers=std::vector(), - const float _meanDistance=-1) - { - cv::Mat contourMat = contour; - cv::Mat disMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); - cv::Mat angleMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); - - std::vector logspaces, angspaces; - logarithmicSpaces(logspaces); - angularSpaces(angspaces); - buildNormalizedDistanceMatrix(contourMat, disMatrix, queryInliers, _meanDistance); - buildAngleMatrix(contourMat, angleMatrix); - - // Now, build the descriptor matrix (each row is a point) // - descriptors = cv::Mat::zeros(contourMat.cols, descriptorSize(), CV_32F); - - for (int ptidx=0; ptidx0) - { - if (queryInliers[ptidx]==0 || queryInliers[cmp]==0) continue; //avoid outliers - } - - int angidx=-1, radidx=-1; - for (int i=0; i(ptidx, cmp)(ptidx, cmp)(ptidx, idx)++; - } - } - } - } - - int descriptorSize() {return nAngularBins*nRadialBins;} - void setAngularBins(int angularBins) { nAngularBins=angularBins; } - void setRadialBins(int radialBins) { nRadialBins=radialBins; } - void setInnerRadius(double _innerRadius) { innerRadius=_innerRadius; } - void setOuterRadius(double _outerRadius) { outerRadius=_outerRadius; } - void setRotationInvariant(bool _rotationInvariant) { rotationInvariant=_rotationInvariant; } - int getAngularBins() const { return nAngularBins; } - int getRadialBins() const { return nRadialBins; } - double getInnerRadius() const { return innerRadius; } - double getOuterRadius() const { return outerRadius; } - bool getRotationInvariant() const { return rotationInvariant; } - float getMeanDistance() const { return meanDistance; } - -private: - int nAngularBins; - int nRadialBins; - double innerRadius; - double outerRadius; - bool rotationInvariant; - float meanDistance; - -protected: - void logarithmicSpaces(std::vector& vecSpaces) const - { - double logmin=log10(innerRadius); - double logmax=log10(outerRadius); - double delta=(logmax-logmin)/(nRadialBins-1); - double accdelta=0; - - for (int i=0; i& vecSpaces) const - { - double delta=2*CV_PI/nAngularBins; - double val=0; - - for (int i=0; i &queryInliers, - const float _meanDistance=-1) - { - cv::Mat contourMat = contour; - cv::Mat mask(disMatrix.rows, disMatrix.cols, CV_8U); - - for (int i=0; i(i,j) = (float)norm( cv::Mat(contourMat.at(0,i)-contourMat.at(0,j)), cv::NORM_L2 ); - if (_meanDistance<0) - { - if (queryInliers.size()>0) - { - mask.at(i,j)=char(queryInliers[j] && queryInliers[i]); - } - else - { - mask.at(i,j)=1; - } - } - } - } - - if (_meanDistance<0) - { - meanDistance=(float)mean(disMatrix, mask)[0]; - } - else - { - meanDistance=_meanDistance; - } - disMatrix/=meanDistance+FLT_EPSILON; - } - - void buildAngleMatrix(cv::Mat& contour, - cv::Mat& angleMatrix) const - { - cv::Mat contourMat = contour; - - // if descriptor is rotationInvariant compute massCenter // - cv::Point2f massCenter(0,0); - if (rotationInvariant) - { - for (int i=0; i(0,i); - } - massCenter.x=massCenter.x/(float)contourMat.cols; - massCenter.y=massCenter.y/(float)contourMat.cols; - } - - - for (int i=0; i(i,j)=0.0; - } - else - { - cv::Point2f dif = contourMat.at(0,i) - contourMat.at(0,j); - angleMatrix.at(i,j) = std::atan2(dif.y, dif.x); - - if (rotationInvariant) - { - cv::Point2f refPt = contourMat.at(0,i) - massCenter; - float refAngle = atan2(refPt.y, refPt.x); - angleMatrix.at(i,j) -= refAngle; - } - angleMatrix.at(i,j) = float(fmod(double(angleMatrix.at(i,j)+(double)FLT_EPSILON),2*CV_PI)+CV_PI); - //angleMatrix.at(i,j) = 1+floor( angleMatrix.at(i,j)*nAngularBins/(2*CV_PI) ); - } - } - } - } -}; - -/* - * Matcher - */ -class SCDMatcher -{ -public: - // the full constructor - SCDMatcher() - { - } - - // the matcher function using Hungarian method - void matchDescriptors(cv::Mat& descriptors1, cv::Mat& descriptors2, std::vector& matches, cv::Ptr& comparer, - std::vector& inliers1, std::vector &inliers2) - { - matches.clear(); - - // Build the cost Matrix between descriptors // - cv::Mat costMat; - buildCostMatrix(descriptors1, descriptors2, costMat, comparer); - - // Solve the matching problem using the hungarian method // - hungarian(costMat, matches, inliers1, inliers2, descriptors1.rows, descriptors2.rows); - } - - // matching cost - float getMatchingCost() const {return minMatchCost;} - -private: - float minMatchCost; - float betaAdditional; -protected: - void buildCostMatrix(const cv::Mat& descriptors1, const cv::Mat& descriptors2, - cv::Mat& costMatrix, cv::Ptr& comparer) const - { - comparer->buildCostMatrix(descriptors1, descriptors2, costMatrix); - } - - void hungarian(cv::Mat& costMatrix, std::vector& outMatches, std::vector &inliers1, - std::vector &inliers2, int sizeScd1=0, int sizeScd2=0) - { - std::vector free(costMatrix.rows, 0), collist(costMatrix.rows, 0); - std::vector matches(costMatrix.rows, 0), colsol(costMatrix.rows), rowsol(costMatrix.rows); - std::vector d(costMatrix.rows), pred(costMatrix.rows), v(costMatrix.rows); - - const float LOWV=1e-10; - bool unassignedfound; - int i=0, imin=0, numfree=0, prvnumfree=0, f=0, i0=0, k=0, freerow=0; - int j=0, j1=0, j2=0, endofpath=0, last=0, low=0, up=0; - float min=0, h=0, umin=0, usubmin=0, v2=0; - - // COLUMN REDUCTION // - for (j = costMatrix.rows-1; j >= 0; j--) - { - // find minimum cost over rows. - min = costMatrix.at(0,j); - imin = 0; - for (i = 1; i < costMatrix.rows; i++) - if (costMatrix.at(i,j) < min) - { - min = costMatrix.at(i,j); - imin = i; - } - v[j] = min; - - if (++matches[imin] == 1) - { - rowsol[imin] = j; - colsol[j] = imin; - } - else - { - colsol[j]=-1; - } - } - - // REDUCTION TRANSFER // - for (i=0; i::max(); - for (j=0; j(i,j)-v[j] < min) - { - min=costMatrix.at(i,j)-v[j]; - } - } - } - v[j1] = v[j1]-min; - } - } - } - // AUGMENTING ROW REDUCTION // - int loopcnt = 0; - do - { - loopcnt++; - k=0; - prvnumfree=numfree; - numfree=0; - while (k < prvnumfree) - { - i=free[k]; - k++; - umin = costMatrix.at(i,0)-v[0]; - j1=0; - usubmin = std::numeric_limits::max(); - for (j=1; j(i,j)-v[j]; - if (h < usubmin) - { - if (h >= umin) - { - usubmin = h; - j2 = j; - } - else - { - usubmin = umin; - umin = h; - j2 = j1; - j1 = j; - } - } - } - i0 = colsol[j1]; - - if (fabs(umin-usubmin) > LOWV) //if( umin < usubmin ) - { - v[j1] = v[j1] - (usubmin - umin); - } - else // minimum and subminimum equal. - { - if (i0 >= 0) // minimum column j1 is assigned. - { - j1 = j2; - i0 = colsol[j2]; - } - } - // (re-)assign i to j1, possibly de-assigning an i0. - rowsol[i]=j1; - colsol[j1]=i; - - if (i0 >= 0) - { - //if( umin < usubmin ) - if (fabs(umin-usubmin) > LOWV) - { - free[--k] = i0; - } - else - { - free[numfree++] = i0; - } - } - } - }while (loopcnt<2); // repeat once. - - // AUGMENT SOLUTION for each free row // - for (f = 0; f(freerow,j) - v[j]; - pred[j] = float(freerow); - collist[j] = j; // init column list. - } - - low=0; // columns in 0..low-1 are ready, now none. - up=0; // columns in low..up-1 are to be scanned for current minimum, now none. - unassignedfound = false; - do - { - if (up == low) - { - last=low-1; - min = d[collist[up++]]; - for (k = up; k < costMatrix.rows; k++) - { - j = collist[k]; - h = d[j]; - if (h <= min) - { - if (h < min) // new minimum. - { - up = low; // restart list at index low. - min = h; - } - collist[k] = collist[up]; - collist[up++] = j; - } - } - for (k=low; k(i,j1)-v[j1]-min; - - for (k = up; k < costMatrix.rows; k++) - { - j = collist[k]; - v2 = costMatrix.at(i,j) - v[j] - h; - if (v2 < d[j]) - { - pred[j] = float(i); - if (v2 == min) - { - if (colsol[j] < 0) - { - // if unassigned, shortest augmenting path is complete. - endofpath = j; - unassignedfound = true; - break; - } - else - { - collist[k] = collist[up]; - collist[up++] = j; - } - } - d[j] = v2; - } - } - } - }while (!unassignedfound); - - // update column prices. - for (k = 0; k <= last; k++) - { - j1 = collist[k]; - v[j1] = v[j1] + d[j1] - min; - } - - // reset row and column assignments along the alternating path. - do - { - i = int(pred[endofpath]); - colsol[endofpath] = i; - j1 = endofpath; - endofpath = rowsol[i]; - rowsol[i] = j1; - }while (i != freerow); - } - - // calculate symmetric shape context cost - cv::Mat trueCostMatrix(costMatrix, cv::Rect(0,0,sizeScd1, sizeScd2)); - float leftcost = 0; - for (int nrow=0; nrow(colsol[i],i));//queryIdx,trainIdx,distance - outMatches.push_back(singleMatch); - } - - // Update inliers - inliers1.reserve(sizeScd1); - for (size_t kc = 0; kc matches; @@ -846,3 +321,461 @@ Ptr createShapeContextDistanceExtractor(int nAng } } // cv + +//! SCD +void SCD::extractSCD(cv::Mat &contour, cv::Mat &descriptors, const std::vector &queryInliers, const float _meanDistance) +{ + cv::Mat contourMat = contour; + cv::Mat disMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); + cv::Mat angleMatrix = cv::Mat::zeros(contourMat.cols, contourMat.cols, CV_32F); + + std::vector logspaces, angspaces; + logarithmicSpaces(logspaces); + angularSpaces(angspaces); + buildNormalizedDistanceMatrix(contourMat, disMatrix, queryInliers, _meanDistance); + buildAngleMatrix(contourMat, angleMatrix); + + // Now, build the descriptor matrix (each row is a point) // + descriptors = cv::Mat::zeros(contourMat.cols, descriptorSize(), CV_32F); + + for (int ptidx=0; ptidx0) + { + if (queryInliers[ptidx]==0 || queryInliers[cmp]==0) continue; //avoid outliers + } + + int angidx=-1, radidx=-1; + for (int i=0; i(ptidx, cmp)(ptidx, cmp)(ptidx, idx)++; + } + } + } +} + +void SCD::logarithmicSpaces(std::vector &vecSpaces) const +{ + double logmin=log10(innerRadius); + double logmax=log10(outerRadius); + double delta=(logmax-logmin)/(nRadialBins-1); + double accdelta=0; + + for (int i=0; i &vecSpaces) const +{ + double delta=2*CV_PI/nAngularBins; + double val=0; + + for (int i=0; i &queryInliers, const float _meanDistance) +{ + cv::Mat contourMat = contour; + cv::Mat mask(disMatrix.rows, disMatrix.cols, CV_8U); + + for (int i=0; i(i,j) = (float)norm( cv::Mat(contourMat.at(0,i)-contourMat.at(0,j)), cv::NORM_L2 ); + if (_meanDistance<0) + { + if (queryInliers.size()>0) + { + mask.at(i,j)=char(queryInliers[j] && queryInliers[i]); + } + else + { + mask.at(i,j)=1; + } + } + } + } + + if (_meanDistance<0) + { + meanDistance=(float)mean(disMatrix, mask)[0]; + } + else + { + meanDistance=_meanDistance; + } + disMatrix/=meanDistance+FLT_EPSILON; +} + +void SCD::buildAngleMatrix(cv::Mat &contour, cv::Mat &angleMatrix) const +{ + cv::Mat contourMat = contour; + + // if descriptor is rotationInvariant compute massCenter // + cv::Point2f massCenter(0,0); + if (rotationInvariant) + { + for (int i=0; i(0,i); + } + massCenter.x=massCenter.x/(float)contourMat.cols; + massCenter.y=massCenter.y/(float)contourMat.cols; + } + + + for (int i=0; i(i,j)=0.0; + } + else + { + cv::Point2f dif = contourMat.at(0,i) - contourMat.at(0,j); + angleMatrix.at(i,j) = std::atan2(dif.y, dif.x); + + if (rotationInvariant) + { + cv::Point2f refPt = contourMat.at(0,i) - massCenter; + float refAngle = atan2(refPt.y, refPt.x); + angleMatrix.at(i,j) -= refAngle; + } + angleMatrix.at(i,j) = float(fmod(double(angleMatrix.at(i,j)+(double)FLT_EPSILON),2*CV_PI)+CV_PI); + } + } + } +} + +//! SCDMatcher +void SCDMatcher::matchDescriptors(cv::Mat &descriptors1, cv::Mat &descriptors2, std::vector &matches, + cv::Ptr &comparer, std::vector &inliers1, std::vector &inliers2) +{ + matches.clear(); + + // Build the cost Matrix between descriptors // + cv::Mat costMat; + buildCostMatrix(descriptors1, descriptors2, costMat, comparer); + + // Solve the matching problem using the hungarian method // + hungarian(costMat, matches, inliers1, inliers2, descriptors1.rows, descriptors2.rows); +} + +void SCDMatcher::buildCostMatrix(const cv::Mat &descriptors1, const cv::Mat &descriptors2, + cv::Mat &costMatrix, cv::Ptr &comparer) const +{ + comparer->buildCostMatrix(descriptors1, descriptors2, costMatrix); +} + +void SCDMatcher::hungarian(cv::Mat &costMatrix, std::vector &outMatches, std::vector &inliers1, + std::vector &inliers2, int sizeScd1, int sizeScd2) +{ + std::vector free(costMatrix.rows, 0), collist(costMatrix.rows, 0); + std::vector matches(costMatrix.rows, 0), colsol(costMatrix.rows), rowsol(costMatrix.rows); + std::vector d(costMatrix.rows), pred(costMatrix.rows), v(costMatrix.rows); + + const float LOWV=1e-10; + bool unassignedfound; + int i=0, imin=0, numfree=0, prvnumfree=0, f=0, i0=0, k=0, freerow=0; + int j=0, j1=0, j2=0, endofpath=0, last=0, low=0, up=0; + float min=0, h=0, umin=0, usubmin=0, v2=0; + + // COLUMN REDUCTION // + for (j = costMatrix.rows-1; j >= 0; j--) + { + // find minimum cost over rows. + min = costMatrix.at(0,j); + imin = 0; + for (i = 1; i < costMatrix.rows; i++) + if (costMatrix.at(i,j) < min) + { + min = costMatrix.at(i,j); + imin = i; + } + v[j] = min; + + if (++matches[imin] == 1) + { + rowsol[imin] = j; + colsol[j] = imin; + } + else + { + colsol[j]=-1; + } + } + + // REDUCTION TRANSFER // + for (i=0; i::max(); + for (j=0; j(i,j)-v[j] < min) + { + min=costMatrix.at(i,j)-v[j]; + } + } + } + v[j1] = v[j1]-min; + } + } + } + // AUGMENTING ROW REDUCTION // + int loopcnt = 0; + do + { + loopcnt++; + k=0; + prvnumfree=numfree; + numfree=0; + while (k < prvnumfree) + { + i=free[k]; + k++; + umin = costMatrix.at(i,0)-v[0]; + j1=0; + usubmin = std::numeric_limits::max(); + for (j=1; j(i,j)-v[j]; + if (h < usubmin) + { + if (h >= umin) + { + usubmin = h; + j2 = j; + } + else + { + usubmin = umin; + umin = h; + j2 = j1; + j1 = j; + } + } + } + i0 = colsol[j1]; + + if (fabs(umin-usubmin) > LOWV) //if( umin < usubmin ) + { + v[j1] = v[j1] - (usubmin - umin); + } + else // minimum and subminimum equal. + { + if (i0 >= 0) // minimum column j1 is assigned. + { + j1 = j2; + i0 = colsol[j2]; + } + } + // (re-)assign i to j1, possibly de-assigning an i0. + rowsol[i]=j1; + colsol[j1]=i; + + if (i0 >= 0) + { + //if( umin < usubmin ) + if (fabs(umin-usubmin) > LOWV) + { + free[--k] = i0; + } + else + { + free[numfree++] = i0; + } + } + } + }while (loopcnt<2); // repeat once. + + // AUGMENT SOLUTION for each free row // + for (f = 0; f(freerow,j) - v[j]; + pred[j] = float(freerow); + collist[j] = j; // init column list. + } + + low=0; // columns in 0..low-1 are ready, now none. + up=0; // columns in low..up-1 are to be scanned for current minimum, now none. + unassignedfound = false; + do + { + if (up == low) + { + last=low-1; + min = d[collist[up++]]; + for (k = up; k < costMatrix.rows; k++) + { + j = collist[k]; + h = d[j]; + if (h <= min) + { + if (h < min) // new minimum. + { + up = low; // restart list at index low. + min = h; + } + collist[k] = collist[up]; + collist[up++] = j; + } + } + for (k=low; k(i,j1)-v[j1]-min; + + for (k = up; k < costMatrix.rows; k++) + { + j = collist[k]; + v2 = costMatrix.at(i,j) - v[j] - h; + if (v2 < d[j]) + { + pred[j] = float(i); + if (v2 == min) + { + if (colsol[j] < 0) + { + // if unassigned, shortest augmenting path is complete. + endofpath = j; + unassignedfound = true; + break; + } + else + { + collist[k] = collist[up]; + collist[up++] = j; + } + } + d[j] = v2; + } + } + } + }while (!unassignedfound); + + // update column prices. + for (k = 0; k <= last; k++) + { + j1 = collist[k]; + v[j1] = v[j1] + d[j1] - min; + } + + // reset row and column assignments along the alternating path. + do + { + i = int(pred[endofpath]); + colsol[endofpath] = i; + j1 = endofpath; + endofpath = rowsol[i]; + rowsol[i] = j1; + }while (i != freerow); + } + + // calculate symmetric shape context cost + cv::Mat trueCostMatrix(costMatrix, cv::Rect(0,0,sizeScd1, sizeScd2)); + float leftcost = 0; + for (int nrow=0; nrow(colsol[i],i));//queryIdx,trainIdx,distance + outMatches.push_back(singleMatch); + } + + // Update inliers + inliers1.reserve(sizeScd1); + for (size_t kc = 0; kc +#include +#include + +/* + * ShapeContextDescriptor class + */ +class SCD +{ +public: + //! the full constructor taking all the necessary parameters + explicit SCD(int _nAngularBins=12, int _nRadialBins=5, + double _innerRadius=0.1, double _outerRadius=1, bool _rotationInvariant=false) + { + setAngularBins(_nAngularBins); + setRadialBins(_nRadialBins); + setInnerRadius(_innerRadius); + setOuterRadius(_outerRadius); + setRotationInvariant(_rotationInvariant); + } + + void extractSCD(cv::Mat& contour, cv::Mat& descriptors, + const std::vector& queryInliers=std::vector(), + const float _meanDistance=-1); + + int descriptorSize() {return nAngularBins*nRadialBins;} + void setAngularBins(int angularBins) { nAngularBins=angularBins; } + void setRadialBins(int radialBins) { nRadialBins=radialBins; } + void setInnerRadius(double _innerRadius) { innerRadius=_innerRadius; } + void setOuterRadius(double _outerRadius) { outerRadius=_outerRadius; } + void setRotationInvariant(bool _rotationInvariant) { rotationInvariant=_rotationInvariant; } + int getAngularBins() const { return nAngularBins; } + int getRadialBins() const { return nRadialBins; } + double getInnerRadius() const { return innerRadius; } + double getOuterRadius() const { return outerRadius; } + bool getRotationInvariant() const { return rotationInvariant; } + float getMeanDistance() const { return meanDistance; } + +private: + int nAngularBins; + int nRadialBins; + double innerRadius; + double outerRadius; + bool rotationInvariant; + float meanDistance; + +protected: + void logarithmicSpaces(std::vector& vecSpaces) const; + void angularSpaces(std::vector& vecSpaces) const; + + void buildNormalizedDistanceMatrix(cv::Mat& contour, + cv::Mat& disMatrix, const std::vector &queryInliers, + const float _meanDistance=-1); + + void buildAngleMatrix(cv::Mat& contour, + cv::Mat& angleMatrix) const; +}; + +/* + * Matcher + */ +class SCDMatcher +{ +public: + // the full constructor + SCDMatcher() + { + } + + // the matcher function using Hungarian method + void matchDescriptors(cv::Mat& descriptors1, cv::Mat& descriptors2, std::vector& matches, cv::Ptr& comparer, + std::vector& inliers1, std::vector &inliers2); + + // matching cost + float getMatchingCost() const {return minMatchCost;} + +private: + float minMatchCost; + float betaAdditional; +protected: + void buildCostMatrix(const cv::Mat& descriptors1, const cv::Mat& descriptors2, + cv::Mat& costMatrix, cv::Ptr& comparer) const; + void hungarian(cv::Mat& costMatrix, std::vector& outMatches, std::vector &inliers1, + std::vector &inliers2, int sizeScd1=0, int sizeScd2=0); + +}; -- 2.7.4