Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
fcd999ae
Commit
fcd999ae
authored
Aug 08, 2011
by
Maria Dimashova
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added SL2 (squared L2 distance) and implemented the descriptors matching in L2 using SL2
parent
a9fdc1bd
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
145 additions
and
74 deletions
+145
-74
common_interfaces_of_descriptor_matchers.rst
...atures2d/doc/common_interfaces_of_descriptor_matchers.rst
+14
-2
features2d.hpp
modules/features2d/include/opencv2/features2d/features2d.hpp
+88
-67
matchers.cpp
modules/features2d/src/matchers.cpp
+43
-5
No files found.
modules/features2d/doc/common_interfaces_of_descriptor_matchers.rst
View file @
fcd999ae
...
...
@@ -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;
};
/*
* 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
...
...
@@ -311,7 +325,6 @@ For efficiency, ``BruteForceMatcher`` is used as a template parameterized with t
typedef typename Accumulator<T>::Type ResultType;
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
ResultType operator()( const unsigned char* a, const unsigned char* b,
int size ) const;
...
};
...
...
modules/features2d/include/opencv2/features2d/features2d.hpp
View file @
fcd999ae
...
...
@@ -2083,6 +2083,27 @@ template<> struct Accumulator<unsigned short> { typedef float Type; };
template
<>
struct
Accumulator
<
char
>
{
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
*/
...
...
@@ -2395,77 +2416,77 @@ template<class Distance>
inline
void
BruteForceMatcher
<
Distance
>::
commonKnnMatchImpl
(
BruteForceMatcher
<
Distance
>&
matcher
,
const
Mat
&
queryDescriptors
,
vector
<
vector
<
DMatch
>
>&
matches
,
int
knn
,
const
vector
<
Mat
>&
masks
,
bool
compactResult
)
{
typedef
typename
Distance
::
ValueType
ValueType
;
typedef
typename
Distance
::
ResultType
DistanceType
;
CV_DbgAssert
(
!
queryDescriptors
.
empty
()
);
CV_Assert
(
DataType
<
ValueType
>::
type
==
queryDescriptors
.
type
()
);
{
typedef
typename
Distance
::
ValueType
ValueType
;
typedef
typename
Distance
::
ResultType
DistanceType
;
CV_DbgAssert
(
!
queryDescriptors
.
empty
()
);
CV_Assert
(
DataType
<
ValueType
>::
type
==
queryDescriptors
.
type
()
);
int
dimension
=
queryDescriptors
.
cols
;
matches
.
reserve
(
queryDescriptors
.
rows
);
int
dimension
=
queryDescriptors
.
cols
;
matches
.
reserve
(
queryDescriptors
.
rows
);
size_t
imgCount
=
matcher
.
trainDescCollection
.
size
();
vector
<
Mat
>
allDists
(
imgCount
);
// distances between one query descriptor and all train descriptors
for
(
size_t
i
=
0
;
i
<
imgCount
;
i
++
)
size_t
imgCount
=
matcher
.
trainDescCollection
.
size
();
vector
<
Mat
>
allDists
(
imgCount
);
// distances between one query descriptor and all train descriptors
for
(
size_t
i
=
0
;
i
<
imgCount
;
i
++
)
allDists
[
i
]
=
Mat
(
1
,
matcher
.
trainDescCollection
[
i
].
rows
,
DataType
<
DistanceType
>::
type
);
for
(
int
qIdx
=
0
;
qIdx
<
queryDescriptors
.
rows
;
qIdx
++
)
{
if
(
matcher
.
isMaskedOut
(
masks
,
qIdx
)
)
{
if
(
!
compactResult
)
// push empty vector
matches
.
push_back
(
vector
<
DMatch
>
()
);
}
else
{
// 1. compute distances between i-th query descriptor and all train descriptors
for
(
size_t
iIdx
=
0
;
iIdx
<
imgCount
;
iIdx
++
)
{
CV_Assert
(
DataType
<
ValueType
>::
type
==
matcher
.
trainDescCollection
[
iIdx
].
type
()
||
matcher
.
trainDescCollection
[
iIdx
].
empty
()
);
CV_Assert
(
queryDescriptors
.
cols
==
matcher
.
trainDescCollection
[
iIdx
].
cols
||
matcher
.
trainDescCollection
[
iIdx
].
empty
()
);
const
ValueType
*
d1
=
(
const
ValueType
*
)(
queryDescriptors
.
data
+
queryDescriptors
.
step
*
qIdx
);
allDists
[
iIdx
].
setTo
(
Scalar
::
all
(
std
::
numeric_limits
<
DistanceType
>::
max
())
);
for
(
int
tIdx
=
0
;
tIdx
<
matcher
.
trainDescCollection
[
iIdx
].
rows
;
tIdx
++
)
{
if
(
masks
.
empty
()
||
matcher
.
isPossibleMatch
(
masks
[
iIdx
],
qIdx
,
tIdx
)
)
{
const
ValueType
*
d2
=
(
const
ValueType
*
)(
matcher
.
trainDescCollection
[
iIdx
].
data
+
matcher
.
trainDescCollection
[
iIdx
].
step
*
tIdx
);
allDists
[
iIdx
].
at
<
DistanceType
>
(
0
,
tIdx
)
=
matcher
.
distance
(
d1
,
d2
,
dimension
);
}
}
}
// 2. choose k nearest matches for query[i]
matches
.
push_back
(
vector
<
DMatch
>
()
);
vector
<
vector
<
DMatch
>
>::
reverse_iterator
curMatches
=
matches
.
rbegin
();
for
(
int
k
=
0
;
k
<
knn
;
k
++
)
{
DMatch
bestMatch
;
bestMatch
.
distance
=
std
::
numeric_limits
<
float
>::
max
();
for
(
size_t
iIdx
=
0
;
iIdx
<
imgCount
;
iIdx
++
)
{
if
(
!
allDists
[
iIdx
].
empty
()
)
{
double
minVal
;
Point
minLoc
;
minMaxLoc
(
allDists
[
iIdx
],
&
minVal
,
0
,
&
minLoc
,
0
);
if
(
minVal
<
bestMatch
.
distance
)
bestMatch
=
DMatch
(
qIdx
,
minLoc
.
x
,
(
int
)
iIdx
,
(
float
)
minVal
);
}
}
if
(
bestMatch
.
trainIdx
==
-
1
)
break
;
allDists
[
bestMatch
.
imgIdx
].
at
<
DistanceType
>
(
0
,
bestMatch
.
trainIdx
)
=
std
::
numeric_limits
<
DistanceType
>::
max
();
curMatches
->
push_back
(
bestMatch
);
}
//TODO should already be sorted at this point?
std
::
sort
(
curMatches
->
begin
(),
curMatches
->
end
()
);
}
}
for
(
int
qIdx
=
0
;
qIdx
<
queryDescriptors
.
rows
;
qIdx
++
)
{
if
(
matcher
.
isMaskedOut
(
masks
,
qIdx
)
)
{
if
(
!
compactResult
)
// push empty vector
matches
.
push_back
(
vector
<
DMatch
>
()
);
}
else
{
// 1. compute distances between i-th query descriptor and all train descriptors
for
(
size_t
iIdx
=
0
;
iIdx
<
imgCount
;
iIdx
++
)
{
CV_Assert
(
DataType
<
ValueType
>::
type
==
matcher
.
trainDescCollection
[
iIdx
].
type
()
||
matcher
.
trainDescCollection
[
iIdx
].
empty
()
);
CV_Assert
(
queryDescriptors
.
cols
==
matcher
.
trainDescCollection
[
iIdx
].
cols
||
matcher
.
trainDescCollection
[
iIdx
].
empty
()
);
const
ValueType
*
d1
=
(
const
ValueType
*
)(
queryDescriptors
.
data
+
queryDescriptors
.
step
*
qIdx
);
allDists
[
iIdx
].
setTo
(
Scalar
::
all
(
std
::
numeric_limits
<
DistanceType
>::
max
())
);
for
(
int
tIdx
=
0
;
tIdx
<
matcher
.
trainDescCollection
[
iIdx
].
rows
;
tIdx
++
)
{
if
(
masks
.
empty
()
||
matcher
.
isPossibleMatch
(
masks
[
iIdx
],
qIdx
,
tIdx
)
)
{
const
ValueType
*
d2
=
(
const
ValueType
*
)(
matcher
.
trainDescCollection
[
iIdx
].
data
+
matcher
.
trainDescCollection
[
iIdx
].
step
*
tIdx
);
allDists
[
iIdx
].
at
<
DistanceType
>
(
0
,
tIdx
)
=
matcher
.
distance
(
d1
,
d2
,
dimension
);
}
}
}
// 2. choose k nearest matches for query[i]
matches
.
push_back
(
vector
<
DMatch
>
()
);
vector
<
vector
<
DMatch
>
>::
reverse_iterator
curMatches
=
matches
.
rbegin
();
for
(
int
k
=
0
;
k
<
knn
;
k
++
)
{
DMatch
bestMatch
;
bestMatch
.
distance
=
std
::
numeric_limits
<
float
>::
max
();
for
(
size_t
iIdx
=
0
;
iIdx
<
imgCount
;
iIdx
++
)
{
if
(
!
allDists
[
iIdx
].
empty
()
)
{
double
minVal
;
Point
minLoc
;
minMaxLoc
(
allDists
[
iIdx
],
&
minVal
,
0
,
&
minLoc
,
0
);
if
(
minVal
<
bestMatch
.
distance
)
bestMatch
=
DMatch
(
qIdx
,
minLoc
.
x
,
(
int
)
iIdx
,
(
float
)
minVal
);
}
}
if
(
bestMatch
.
trainIdx
==
-
1
)
break
;
allDists
[
bestMatch
.
imgIdx
].
at
<
DistanceType
>
(
0
,
bestMatch
.
trainIdx
)
=
std
::
numeric_limits
<
DistanceType
>::
max
();
curMatches
->
push_back
(
bestMatch
);
}
//TODO should already be sorted at this point?
std
::
sort
(
curMatches
->
begin
(),
curMatches
->
end
()
);
}
}
}
template
<
class
Distance
>
...
...
modules/features2d/src/matchers.cpp
View file @
fcd999ae
...
...
@@ -328,6 +328,10 @@ Ptr<DescriptorMatcher> DescriptorMatcher::create( const string& descriptorMatche
{
dm
=
new
BruteForceMatcher
<
L2
<
float
>
>
();
}
else
if
(
!
descriptorMatcherType
.
compare
(
"BruteForce-SL2"
)
)
// Squared L2
{
dm
=
new
BruteForceMatcher
<
SL2
<
float
>
>
();
}
else
if
(
!
descriptorMatcherType
.
compare
(
"BruteForce-L1"
)
)
{
dm
=
new
BruteForceMatcher
<
L1
<
float
>
>
();
...
...
@@ -345,10 +349,10 @@ Ptr<DescriptorMatcher> DescriptorMatcher::create( const string& descriptorMatche
}
/*
* BruteForce L2 specialization
* BruteForce
SL2 and
L2 specialization
*/
template
<>
void
BruteForceMatcher
<
L2
<
float
>
>::
knnMatchImpl
(
const
Mat
&
queryDescriptors
,
vector
<
vector
<
DMatch
>
>&
matches
,
int
knn
,
void
BruteForceMatcher
<
S
L2
<
float
>
>::
knnMatchImpl
(
const
Mat
&
queryDescriptors
,
vector
<
vector
<
DMatch
>
>&
matches
,
int
knn
,
const
vector
<
Mat
>&
masks
,
bool
compactResult
)
{
#ifndef HAVE_EIGEN
...
...
@@ -427,7 +431,7 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, v
break
;
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
()
);
}
...
...
@@ -436,7 +440,7 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, v
}
template
<>
void
BruteForceMatcher
<
L2
<
float
>
>::
radiusMatchImpl
(
const
Mat
&
queryDescriptors
,
vector
<
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
void
BruteForceMatcher
<
S
L2
<
float
>
>::
radiusMatchImpl
(
const
Mat
&
queryDescriptors
,
vector
<
vector
<
DMatch
>
>&
matches
,
float
maxDistance
,
const
vector
<
Mat
>&
masks
,
bool
compactResult
)
{
#ifndef HAVE_EIGEN
...
...
@@ -492,7 +496,7 @@ void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors
{
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
)
curMatches
->
push_back
(
DMatch
(
qIdx
,
tIdx
,
iIdx
,
d
)
);
}
...
...
@@ -504,6 +508,40 @@ void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors
#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
*/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment