Commit fcd999ae authored by Maria Dimashova's avatar Maria Dimashova

added SL2 (squared L2 distance) and implemented the descriptors matching in L2 using SL2

parent a9fdc1bd
...@@ -300,6 +300,20 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t ...@@ -300,6 +300,20 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t
ResultType operator()( const T* a, const T* b, int size ) const; ResultType operator()( const T* a, const T* b, int size ) const;
}; };
/*
* Squared Euclidean distance functor
*/
template<class T>
struct SL2
{
typedef T ValueType;
typedef typename Accumulator<T>::Type ResultType;
ResultType operator()( const T* a, const T* b, int size ) const;
};
// Note: in case of SL2 distance a parameter maxDistance in the method DescriptorMatcher::radiusMatch
// is a squared maximum distance in L2.
/* /*
* Manhattan distance (city block distance) functor * Manhattan distance (city block distance) functor
...@@ -311,7 +325,6 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t ...@@ -311,7 +325,6 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t
typedef typename Accumulator<T>::Type ResultType; typedef typename Accumulator<T>::Type ResultType;
ResultType operator()( const T* a, const T* b, int size ) const; ResultType operator()( const T* a, const T* b, int size ) const;
...
}; };
/* /*
...@@ -334,7 +347,6 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t ...@@ -334,7 +347,6 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t
ResultType operator()( const unsigned char* a, const unsigned char* b, ResultType operator()( const unsigned char* a, const unsigned char* b,
int size ) const; int size ) const;
...
}; };
......
...@@ -2083,6 +2083,27 @@ template<> struct Accumulator<unsigned short> { typedef float Type; }; ...@@ -2083,6 +2083,27 @@ template<> struct Accumulator<unsigned short> { typedef float Type; };
template<> struct Accumulator<char> { typedef float Type; }; template<> struct Accumulator<char> { typedef float Type; };
template<> struct Accumulator<short> { typedef float Type; }; template<> struct Accumulator<short> { typedef float Type; };
/*
* Squeared Euclidean distance functor
*/
template<class T>
struct CV_EXPORTS SL2
{
typedef T ValueType;
typedef typename Accumulator<T>::Type ResultType;
ResultType operator()( const T* a, const T* b, int size ) const
{
ResultType result = ResultType();
for( int i = 0; i < size; i++ )
{
ResultType diff = (ResultType)(a[i] - b[i]);
result += diff*diff;
}
return result;
}
};
/* /*
* Euclidean distance functor * Euclidean distance functor
*/ */
...@@ -2395,77 +2416,77 @@ template<class Distance> ...@@ -2395,77 +2416,77 @@ template<class Distance>
inline void BruteForceMatcher<Distance>::commonKnnMatchImpl( BruteForceMatcher<Distance>& matcher, inline void BruteForceMatcher<Distance>::commonKnnMatchImpl( BruteForceMatcher<Distance>& matcher,
const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn, const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn,
const vector<Mat>& masks, bool compactResult ) const vector<Mat>& masks, bool compactResult )
{ {
typedef typename Distance::ValueType ValueType; typedef typename Distance::ValueType ValueType;
typedef typename Distance::ResultType DistanceType; typedef typename Distance::ResultType DistanceType;
CV_DbgAssert( !queryDescriptors.empty() ); CV_DbgAssert( !queryDescriptors.empty() );
CV_Assert( DataType<ValueType>::type == queryDescriptors.type() ); CV_Assert( DataType<ValueType>::type == queryDescriptors.type() );
int dimension = queryDescriptors.cols; int dimension = queryDescriptors.cols;
matches.reserve(queryDescriptors.rows); matches.reserve(queryDescriptors.rows);
size_t imgCount = matcher.trainDescCollection.size(); size_t imgCount = matcher.trainDescCollection.size();
vector<Mat> allDists( imgCount ); // distances between one query descriptor and all train descriptors vector<Mat> allDists( imgCount ); // distances between one query descriptor and all train descriptors
for( size_t i = 0; i < imgCount; i++ ) for( size_t i = 0; i < imgCount; i++ )
allDists[i] = Mat( 1, matcher.trainDescCollection[i].rows, DataType<DistanceType>::type ); allDists[i] = Mat( 1, matcher.trainDescCollection[i].rows, DataType<DistanceType>::type );
for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ ) for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
{ {
if( matcher.isMaskedOut( masks, qIdx ) ) if( matcher.isMaskedOut( masks, qIdx ) )
{ {
if( !compactResult ) // push empty vector if( !compactResult ) // push empty vector
matches.push_back( vector<DMatch>() ); matches.push_back( vector<DMatch>() );
} }
else else
{ {
// 1. compute distances between i-th query descriptor and all train descriptors // 1. compute distances between i-th query descriptor and all train descriptors
for( size_t iIdx = 0; iIdx < imgCount; iIdx++ ) for( size_t iIdx = 0; iIdx < imgCount; iIdx++ )
{ {
CV_Assert( DataType<ValueType>::type == matcher.trainDescCollection[iIdx].type() || matcher.trainDescCollection[iIdx].empty() ); CV_Assert( DataType<ValueType>::type == matcher.trainDescCollection[iIdx].type() || matcher.trainDescCollection[iIdx].empty() );
CV_Assert( queryDescriptors.cols == matcher.trainDescCollection[iIdx].cols || CV_Assert( queryDescriptors.cols == matcher.trainDescCollection[iIdx].cols ||
matcher.trainDescCollection[iIdx].empty() ); matcher.trainDescCollection[iIdx].empty() );
const ValueType* d1 = (const ValueType*)(queryDescriptors.data + queryDescriptors.step*qIdx); const ValueType* d1 = (const ValueType*)(queryDescriptors.data + queryDescriptors.step*qIdx);
allDists[iIdx].setTo( Scalar::all(std::numeric_limits<DistanceType>::max()) ); allDists[iIdx].setTo( Scalar::all(std::numeric_limits<DistanceType>::max()) );
for( int tIdx = 0; tIdx < matcher.trainDescCollection[iIdx].rows; tIdx++ ) for( int tIdx = 0; tIdx < matcher.trainDescCollection[iIdx].rows; tIdx++ )
{ {
if( masks.empty() || matcher.isPossibleMatch(masks[iIdx], qIdx, tIdx) ) if( masks.empty() || matcher.isPossibleMatch(masks[iIdx], qIdx, tIdx) )
{ {
const ValueType* d2 = (const ValueType*)(matcher.trainDescCollection[iIdx].data + const ValueType* d2 = (const ValueType*)(matcher.trainDescCollection[iIdx].data +
matcher.trainDescCollection[iIdx].step*tIdx); matcher.trainDescCollection[iIdx].step*tIdx);
allDists[iIdx].at<DistanceType>(0, tIdx) = matcher.distance(d1, d2, dimension); allDists[iIdx].at<DistanceType>(0, tIdx) = matcher.distance(d1, d2, dimension);
} }
} }
} }
// 2. choose k nearest matches for query[i] // 2. choose k nearest matches for query[i]
matches.push_back( vector<DMatch>() ); matches.push_back( vector<DMatch>() );
vector<vector<DMatch> >::reverse_iterator curMatches = matches.rbegin(); vector<vector<DMatch> >::reverse_iterator curMatches = matches.rbegin();
for( int k = 0; k < knn; k++ ) for( int k = 0; k < knn; k++ )
{ {
DMatch bestMatch; DMatch bestMatch;
bestMatch.distance = std::numeric_limits<float>::max(); bestMatch.distance = std::numeric_limits<float>::max();
for( size_t iIdx = 0; iIdx < imgCount; iIdx++ ) for( size_t iIdx = 0; iIdx < imgCount; iIdx++ )
{ {
if( !allDists[iIdx].empty() ) if( !allDists[iIdx].empty() )
{ {
double minVal; double minVal;
Point minLoc; Point minLoc;
minMaxLoc( allDists[iIdx], &minVal, 0, &minLoc, 0 ); minMaxLoc( allDists[iIdx], &minVal, 0, &minLoc, 0 );
if( minVal < bestMatch.distance ) if( minVal < bestMatch.distance )
bestMatch = DMatch( qIdx, minLoc.x, (int)iIdx, (float)minVal ); bestMatch = DMatch( qIdx, minLoc.x, (int)iIdx, (float)minVal );
} }
} }
if( bestMatch.trainIdx == -1 ) if( bestMatch.trainIdx == -1 )
break; break;
allDists[bestMatch.imgIdx].at<DistanceType>(0, bestMatch.trainIdx) = std::numeric_limits<DistanceType>::max(); allDists[bestMatch.imgIdx].at<DistanceType>(0, bestMatch.trainIdx) = std::numeric_limits<DistanceType>::max();
curMatches->push_back( bestMatch ); curMatches->push_back( bestMatch );
} }
//TODO should already be sorted at this point? //TODO should already be sorted at this point?
std::sort( curMatches->begin(), curMatches->end() ); std::sort( curMatches->begin(), curMatches->end() );
} }
} }
} }
template<class Distance> template<class Distance>
......
...@@ -328,6 +328,10 @@ Ptr<DescriptorMatcher> DescriptorMatcher::create( const string& descriptorMatche ...@@ -328,6 +328,10 @@ Ptr<DescriptorMatcher> DescriptorMatcher::create( const string& descriptorMatche
{ {
dm = new BruteForceMatcher<L2<float> >(); dm = new BruteForceMatcher<L2<float> >();
} }
else if( !descriptorMatcherType.compare( "BruteForce-SL2" ) ) // Squared L2
{
dm = new BruteForceMatcher<SL2<float> >();
}
else if( !descriptorMatcherType.compare( "BruteForce-L1" ) ) else if( !descriptorMatcherType.compare( "BruteForce-L1" ) )
{ {
dm = new BruteForceMatcher<L1<float> >(); dm = new BruteForceMatcher<L1<float> >();
...@@ -345,10 +349,10 @@ Ptr<DescriptorMatcher> DescriptorMatcher::create( const string& descriptorMatche ...@@ -345,10 +349,10 @@ Ptr<DescriptorMatcher> DescriptorMatcher::create( const string& descriptorMatche
} }
/* /*
* BruteForce L2 specialization * BruteForce SL2 and L2 specialization
*/ */
template<> template<>
void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn, void BruteForceMatcher<SL2<float> >::knnMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn,
const vector<Mat>& masks, bool compactResult ) const vector<Mat>& masks, bool compactResult )
{ {
#ifndef HAVE_EIGEN #ifndef HAVE_EIGEN
...@@ -427,7 +431,7 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, v ...@@ -427,7 +431,7 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, v
break; break;
e_allDists[bestImgIdx](bestTrainIdx) = -std::numeric_limits<float>::max(); e_allDists[bestImgIdx](bestTrainIdx) = -std::numeric_limits<float>::max();
curMatches->push_back( DMatch(qIdx, bestTrainIdx, bestImgIdx, sqrt((-2)*totalMaxCoeff + queryNorm2)) ); curMatches->push_back( DMatch(qIdx, bestTrainIdx, bestImgIdx, (-2)*totalMaxCoeff + queryNorm2) );
} }
std::sort( curMatches->begin(), curMatches->end() ); std::sort( curMatches->begin(), curMatches->end() );
} }
...@@ -436,7 +440,7 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, v ...@@ -436,7 +440,7 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, v
} }
template<> template<>
void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance, void BruteForceMatcher<SL2<float> >::radiusMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance,
const vector<Mat>& masks, bool compactResult ) const vector<Mat>& masks, bool compactResult )
{ {
#ifndef HAVE_EIGEN #ifndef HAVE_EIGEN
...@@ -492,7 +496,7 @@ void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors ...@@ -492,7 +496,7 @@ void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors
{ {
if( masks.empty() || isPossibleMatch(masks[iIdx], qIdx, tIdx) ) if( masks.empty() || isPossibleMatch(masks[iIdx], qIdx, tIdx) )
{ {
float d = sqrt((-2)*e_allDists[iIdx](tIdx) + queryNorm2); float d = (-2)*e_allDists[iIdx](tIdx) + queryNorm2;
if( d < maxDistance ) if( d < maxDistance )
curMatches->push_back( DMatch( qIdx, tIdx, iIdx, d ) ); curMatches->push_back( DMatch( qIdx, tIdx, iIdx, d ) );
} }
...@@ -504,6 +508,40 @@ void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors ...@@ -504,6 +508,40 @@ void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors
#endif #endif
} }
inline void sqrtDistance( vector<vector<DMatch> >& matches )
{
for( size_t imgIdx = 0; imgIdx < matches.size(); imgIdx++ )
{
for( size_t matchIdx = 0; matchIdx < matches[imgIdx].size(); matchIdx++ )
{
matches[imgIdx][matchIdx].distance = std::sqrt( matches[imgIdx][matchIdx].distance );
}
}
}
template<>
void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn,
const vector<Mat>& masks, bool compactResult )
{
BruteForceMatcher<SL2<float> > matcherSL2;
matcherSL2.add( getTrainDescriptors() );
matcherSL2.knnMatch( queryDescriptors, matches, knn, masks, compactResult );
sqrtDistance( matches );
}
template<>
void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance,
const vector<Mat>& masks, bool compactResult )
{
const float maxDistance2 = maxDistance * maxDistance;
BruteForceMatcher<SL2<float> > matcherSL2;
matcherSL2.add( getTrainDescriptors() );
matcherSL2.radiusMatch( queryDescriptors, matches, maxDistance2, masks, compactResult );
sqrtDistance( matches );
}
/* /*
* Flann based matcher * Flann based matcher
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment