Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv_contrib
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_contrib
Commits
f9bbe706
Commit
f9bbe706
authored
Dec 17, 2019
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2383 from catree:feat_LOGOS_matching
parents
8a7a625a
a9c1cfcb
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1050 additions
and
5 deletions
+1050
-5
xfeatures2d.bib
modules/xfeatures2d/doc/xfeatures2d.bib
+9
-0
xfeatures2d.hpp
modules/xfeatures2d/include/opencv2/xfeatures2d.hpp
+21
-5
logos.cpp
modules/xfeatures2d/src/logos.cpp
+69
-0
Logos.cpp
modules/xfeatures2d/src/logos/Logos.cpp
+189
-0
Logos.hpp
modules/xfeatures2d/src/logos/Logos.hpp
+87
-0
Match.cpp
modules/xfeatures2d/src/logos/Match.cpp
+103
-0
Match.hpp
modules/xfeatures2d/src/logos/Match.hpp
+73
-0
Point.cpp
modules/xfeatures2d/src/logos/Point.cpp
+120
-0
Point.hpp
modules/xfeatures2d/src/logos/Point.hpp
+79
-0
PointPair.cpp
modules/xfeatures2d/src/logos/PointPair.cpp
+77
-0
PointPair.hpp
modules/xfeatures2d/src/logos/PointPair.hpp
+71
-0
test_logos_matcher.cpp
modules/xfeatures2d/test/test_logos_matcher.cpp
+152
-0
No files found.
modules/xfeatures2d/doc/xfeatures2d.bib
View file @
f9bbe706
...
@@ -71,6 +71,15 @@
...
@@ -71,6 +71,15 @@
publisher = {Kluwer Academic Publishers}
publisher = {Kluwer Academic Publishers}
}
}
@article{Lowry2018LOGOSLG,
title = {LOGOS: Local Geometric Support for High-Outlier Spatial Verification},
author = {Stephanie Lowry and Henrik Andreasson},
journal = {2018 IEEE International Conference on Robotics and Automation (ICRA)},
year = {2018},
pages = {7262-7269},
doi = {10.1109/ICRA.2018.8460988},
}
@article{Mikolajczyk2004,
@article{Mikolajczyk2004,
title = {Scale \& affine invariant interest point detectors},
title = {Scale \& affine invariant interest point detectors},
author = {Mikolajczyk, Krystian and Schmid, Cordelia},
author = {Mikolajczyk, Krystian and Schmid, Cordelia},
...
...
modules/xfeatures2d/include/opencv2/xfeatures2d.hpp
View file @
f9bbe706
...
@@ -55,7 +55,9 @@ known to be patented. You need to set the OPENCV_ENABLE_NONFREE option in cmake
...
@@ -55,7 +55,9 @@ known to be patented. You need to set the OPENCV_ENABLE_NONFREE option in cmake
@defgroup xfeatures2d_match Experimental 2D Features Matching Algorithm
@defgroup xfeatures2d_match Experimental 2D Features Matching Algorithm
This section describes the GMS (Grid-based Motion Statistics) matching strategy.
This section describes the following matching strategies:
- GMS: Grid-based Motion Statistics, @cite Bian2017gms
- LOGOS: Local geometric support for high-outlier spatial verification, @cite Lowry2018LOGOSLG
@}
@}
*/
*/
...
@@ -969,7 +971,7 @@ CV_EXPORTS void FASTForPointSet( InputArray image, CV_IN_OUT std::vector<KeyPoin
...
@@ -969,7 +971,7 @@ CV_EXPORTS void FASTForPointSet( InputArray image, CV_IN_OUT std::vector<KeyPoin
//! @addtogroup xfeatures2d_match
//! @addtogroup xfeatures2d_match
//! @{
//! @{
/** @brief GMS
(Grid-based Motion Statistics) feature matching strategy by
@cite Bian2017gms .
/** @brief GMS
(Grid-based Motion Statistics) feature matching strategy described in
@cite Bian2017gms .
@param size1 Input size of image1.
@param size1 Input size of image1.
@param size2 Input size of image2.
@param size2 Input size of image2.
@param keypoints1 Input keypoints of image1.
@param keypoints1 Input keypoints of image1.
...
@@ -984,10 +986,24 @@ CV_EXPORTS void FASTForPointSet( InputArray image, CV_IN_OUT std::vector<KeyPoin
...
@@ -984,10 +986,24 @@ CV_EXPORTS void FASTForPointSet( InputArray image, CV_IN_OUT std::vector<KeyPoin
If matching results are not satisfying, please add more features. (We use 10000 for images with 640 X 480).
If matching results are not satisfying, please add more features. (We use 10000 for images with 640 X 480).
If your images have big rotation and scale changes, please set withRotation or withScale to true.
If your images have big rotation and scale changes, please set withRotation or withScale to true.
*/
*/
CV_EXPORTS_W
void
matchGMS
(
const
Size
&
size1
,
const
Size
&
size2
,
const
std
::
vector
<
KeyPoint
>&
keypoints1
,
const
std
::
vector
<
KeyPoint
>&
keypoints2
,
CV_EXPORTS_W
void
matchGMS
(
const
Size
&
size1
,
const
Size
&
size2
,
const
std
::
vector
<
KeyPoint
>&
keypoints1
,
const
std
::
vector
<
KeyPoint
>&
keypoints2
,
const
std
::
vector
<
DMatch
>&
matches1to2
,
CV_OUT
std
::
vector
<
DMatch
>&
matchesGMS
,
const
bool
withRotation
=
false
,
const
std
::
vector
<
DMatch
>&
matches1to2
,
CV_OUT
std
::
vector
<
DMatch
>&
matchesGMS
,
const
bool
withRotation
=
false
,
const
bool
withScale
=
false
,
const
double
thresholdFactor
=
6.0
);
const
bool
withScale
=
false
,
const
double
thresholdFactor
=
6.0
);
/** @brief LOGOS (Local geometric support for high-outlier spatial verification) feature matching strategy described in @cite Lowry2018LOGOSLG .
@param keypoints1 Input keypoints of image1.
@param keypoints2 Input keypoints of image2.
@param nn1 Index to the closest BoW centroid for each descriptors of image1.
@param nn2 Index to the closest BoW centroid for each descriptors of image2.
@param matches1to2 Matches returned by the LOGOS matching strategy.
@note
This matching strategy is suitable for features matching against large scale database.
First step consists in constructing the bag-of-words (BoW) from a representative image database.
Image descriptors are then represented by their closest codevector (nearest BoW centroid).
*/
CV_EXPORTS_W
void
matchLOGOS
(
const
std
::
vector
<
KeyPoint
>&
keypoints1
,
const
std
::
vector
<
KeyPoint
>&
keypoints2
,
const
std
::
vector
<
int
>&
nn1
,
const
std
::
vector
<
int
>&
nn2
,
std
::
vector
<
DMatch
>&
matches1to2
);
//! @}
//! @}
...
...
modules/xfeatures2d/src/logos.cpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "logos/Logos.hpp"
namespace
cv
{
namespace
xfeatures2d
{
void
matchLOGOS
(
const
std
::
vector
<
KeyPoint
>&
keypoints1
,
const
std
::
vector
<
KeyPoint
>&
keypoints2
,
const
std
::
vector
<
int
>&
nn1
,
const
std
::
vector
<
int
>&
nn2
,
std
::
vector
<
DMatch
>&
matches1to2
)
{
CV_CheckEQ
(
keypoints1
.
size
(),
nn1
.
size
(),
"Number of keypoints1 must be equal to the number of nn1."
);
CV_CheckEQ
(
keypoints2
.
size
(),
nn2
.
size
(),
"Number of keypoints2 must be equal to the number of nn2."
);
if
(
keypoints1
.
empty
()
||
keypoints2
.
empty
())
{
return
;
}
std
::
vector
<
logos
::
Point
*>
vP1
,
vP2
;
vP1
.
reserve
(
keypoints1
.
size
());
vP2
.
reserve
(
keypoints2
.
size
());
for
(
size_t
i
=
0
;
i
<
keypoints1
.
size
();
i
++
)
{
logos
::
Point
*
pt1
=
new
logos
::
Point
(
keypoints1
[
i
].
pt
.
x
,
keypoints1
[
i
].
pt
.
y
,
static_cast
<
float
>
(
keypoints1
[
i
].
angle
*
CV_PI
/
180
),
keypoints1
[
i
].
size
,
nn1
[
i
]);
vP1
.
push_back
(
pt1
);
}
for
(
size_t
i
=
0
;
i
<
keypoints2
.
size
();
i
++
)
{
logos
::
Point
*
pt2
=
new
logos
::
Point
(
keypoints2
[
i
].
pt
.
x
,
keypoints2
[
i
].
pt
.
y
,
static_cast
<
float
>
(
keypoints2
[
i
].
angle
*
CV_PI
/
180
),
keypoints2
[
i
].
size
,
nn2
[
i
]);
vP2
.
push_back
(
pt2
);
}
logos
::
Logos
logos
;
std
::
vector
<
logos
::
PointPair
*>
globalMatches
;
logos
.
estimateMatches
(
vP1
,
vP2
,
globalMatches
);
matches1to2
.
clear
();
matches1to2
.
reserve
(
globalMatches
.
size
());
for
(
size_t
i
=
0
;
i
<
globalMatches
.
size
();
i
++
)
{
logos
::
PointPair
*
pp
=
globalMatches
[
i
];
matches1to2
.
push_back
(
DMatch
(
pp
->
getPos1
(),
pp
->
getPos2
(),
0
));
}
for
(
size_t
i
=
0
;
i
<
globalMatches
.
size
();
i
++
)
{
delete
globalMatches
[
i
];
}
for
(
size_t
i
=
0
;
i
<
vP1
.
size
();
i
++
)
{
delete
vP1
[
i
];
}
for
(
size_t
i
=
0
;
i
<
vP2
.
size
();
i
++
)
{
delete
vP2
[
i
];
}
}
}
//namespace xfeatures2d
}
//namespace cv
modules/xfeatures2d/src/logos/Logos.cpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
/*
* MIT License
*
* Copyright (c) 2018 Stephanie Lowry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <cmath>
#include "Logos.hpp"
#include <opencv2/core.hpp>
namespace
logos
{
Logos
::
Logos
()
{
LogosParameters
defaultParams
;
init
(
defaultParams
);
}
Logos
::
Logos
(
const
LogosParameters
&
p
)
{
init
(
p
);
}
void
Logos
::
init
(
const
LogosParameters
&
p
)
{
setParams
(
p
);
LB
=
static_cast
<
float
>
(
-
CV_PI
);
BINSIZE
=
logosParams
.
GLOBALORILIMIT
/
3
;
BINNUMBER
=
static_cast
<
unsigned
int
>
(
ceil
(
2
*
CV_PI
/
BINSIZE
));
bins
.
resize
(
BINNUMBER
);
std
::
fill
(
bins
.
begin
(),
bins
.
end
(),
0
);
}
int
Logos
::
estimateMatches
(
std
::
vector
<
Point
*>
vP1
,
std
::
vector
<
Point
*>
vP2
,
std
::
vector
<
PointPair
*>&
globalmatches
)
{
matches
.
clear
();
// for each point
int
count1
=
0
;
for
(
std
::
vector
<
Point
*>::
iterator
pit1
=
vP1
.
begin
();
pit1
!=
vP1
.
end
();
++
pit1
,
count1
++
)
{
(
*
pit1
)
->
nearestNeighbours
(
vP1
,
count1
,
getNum1
());
int
count2
=
0
;
// find possible matches
for
(
std
::
vector
<
Point
*>::
iterator
pit2
=
vP2
.
begin
();
pit2
!=
vP2
.
end
();
++
pit2
,
count2
++
)
{
if
((
*
pit1
)
->
getLabel
()
!=
(
*
pit2
)
->
getLabel
())
{
continue
;
}
// this is a possible match in Image 2
// get nearest neighbours
(
*
pit2
)
->
nearestNeighbours
(
vP2
,
count2
,
getNum2
());
PointPair
*
ptpr
=
new
PointPair
(
*
pit1
,
*
pit2
);
ptpr
->
addPositions
(
count1
,
count2
);
ptpr
->
computeLocalSupport
(
pp
,
getNum2
());
// calc matches
int
support
=
0
;
for
(
std
::
vector
<
PointPair
*>::
const_iterator
it
=
pp
.
begin
();
it
<
pp
.
end
();
++
it
)
{
Match
m
(
ptpr
,
*
it
);
if
(
evaluateMatch
(
m
))
{
support
++
;
}
}
for
(
size_t
i
=
0
;
i
<
pp
.
size
();
i
++
)
{
delete
pp
[
i
];
}
pp
.
clear
();
if
(
support
>
0
)
{
ptpr
->
setSupport
(
support
);
matches
.
push_back
(
ptpr
);
updateBin
(
ptpr
->
getRelOri
());
}
else
{
delete
ptpr
;
ptpr
=
NULL
;
}
}
}
// do global orientation
double
maxang
=
calcGlobalOrientation
();
// find which matches are within global orientation limit
int
numinliers
=
0
;
globalmatches
.
clear
();
for
(
std
::
vector
<
PointPair
*>::
iterator
it
=
matches
.
begin
();
it
!=
matches
.
end
();
++
it
)
{
if
(
std
::
fabs
((
*
it
)
->
getRelOri
()
-
maxang
)
<
logosParams
.
GLOBALORILIMIT
)
{
numinliers
++
;
globalmatches
.
push_back
(
*
it
);
}
else
{
delete
*
it
;
*
it
=
NULL
;
}
}
return
numinliers
;
}
bool
Logos
::
evaluateMatch
(
const
Match
&
m
)
const
{
return
((
m
.
getRelOrientation
()
<
getIntraOriLimit
())
&&
(
m
.
getRelScale
()
<
getIntraScaleLimit
())
&&
(
m
.
getInterOrientation
()
<
getInterOriLimit
())
&&
(
m
.
getInterScale
()
<
getInterScaleLimit
()));
}
void
Logos
::
updateBin
(
float
input
)
{
unsigned
int
binnumber
=
static_cast
<
unsigned
int
>
(
cvFloor
((
input
-
LB
)
/
BINSIZE
));
// compare binnumber to BINNUMBER
if
(
binnumber
<
BINNUMBER
)
{
bins
[
binnumber
]
++
;
}
else
{
bins
[
BINNUMBER
-
1
]
++
;
}
}
float
Logos
::
calcGlobalOrientation
()
{
// find max bin
// check BINNUMBER is big enough
if
(
BINNUMBER
<
3
)
{
return
0
;
}
std
::
vector
<
int
>
bins2
(
BINNUMBER
);
int
maxval
=
0
;
unsigned
int
maxix
=
0
;
bins2
[
0
]
=
bins
[
0
]
+
bins
[
1
]
+
bins
[
BINNUMBER
-
1
];
maxval
=
bins2
[
0
];
for
(
unsigned
int
i
=
1
;
i
<
BINNUMBER
;
i
++
)
{
if
(
i
==
BINNUMBER
-
1
)
{
bins2
[
i
]
=
bins
[
i
]
+
bins
[
i
-
1
]
+
bins
[
0
];
}
else
{
bins2
[
i
]
=
bins
[
i
]
+
bins
[
i
-
1
]
+
bins
[
i
+
1
];
}
if
(
bins2
[
i
]
>
maxval
)
{
maxval
=
bins2
[
i
];
maxix
=
i
;
}
}
// convert to an angle
return
LB
+
maxix
*
BINSIZE
+
BINSIZE
/
2
;
}
}
modules/xfeatures2d/src/logos/Logos.hpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
/*
* MIT License
*
* Copyright (c) 2018 Stephanie Lowry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef LOGOS_HPP
#define LOGOS_HPP
#include "Point.hpp"
#include "Match.hpp"
#include "PointPair.hpp"
namespace
logos
{
struct
LogosParameters
{
LogosParameters
()
:
INTRAORILIMIT
(
0.1
f
),
INTRASCALELIMIT
(
0.1
f
),
INTERORILIMIT
(
0.1
f
),
INTERSCALELIMIT
(
0.1
f
),
GLOBALORILIMIT
(
0.1
f
),
NUM1
(
5
),
NUM2
(
5
)
{}
float
INTRAORILIMIT
;
float
INTRASCALELIMIT
;
float
INTERORILIMIT
;
float
INTERSCALELIMIT
;
float
GLOBALORILIMIT
;
int
NUM1
;
int
NUM2
;
};
class
Logos
{
private
:
std
::
vector
<
PointPair
*>
pp
;
std
::
vector
<
PointPair
*>
matches
;
LogosParameters
logosParams
;
float
LB
;
float
BINSIZE
;
unsigned
int
BINNUMBER
;
std
::
vector
<
int
>
bins
;
public
:
Logos
();
Logos
(
const
LogosParameters
&
p
);
void
init
(
const
LogosParameters
&
p
);
int
estimateMatches
(
std
::
vector
<
Point
*>
vP1
,
std
::
vector
<
Point
*>
vP2
,
std
::
vector
<
PointPair
*>&
globalmatches
);
bool
evaluateMatch
(
const
Match
&
m
)
const
;
inline
float
getIntraOriLimit
()
const
{
return
logosParams
.
INTRAORILIMIT
;
}
inline
float
getIntraScaleLimit
()
const
{
return
logosParams
.
INTRASCALELIMIT
;
}
inline
float
getInterOriLimit
()
const
{
return
logosParams
.
INTERORILIMIT
;
}
inline
float
getInterScaleLimit
()
const
{
return
logosParams
.
INTERSCALELIMIT
;
}
inline
float
getGlobalOriLimit
()
const
{
return
logosParams
.
GLOBALORILIMIT
;
}
inline
int
getNum1
()
const
{
return
logosParams
.
NUM1
;
}
inline
int
getNum2
()
const
{
return
logosParams
.
NUM2
;
}
void
updateBin
(
float
input
);
float
calcGlobalOrientation
();
inline
void
setParams
(
const
LogosParameters
&
p
)
{
logosParams
=
p
;
}
};
}
#endif
modules/xfeatures2d/src/logos/Match.cpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
/*
* MIT License
*
* Copyright (c) 2018 Stephanie Lowry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <algorithm> // std::min
#include <cmath> // log, acos
#include <iostream>
#include <opencv2/core.hpp>
#include "Match.hpp"
namespace
logos
{
Match
::
Match
(
PointPair
*
r_
,
PointPair
*
s_
)
:
r
(
r_
),
s
(
s_
)
{
calculateInternalVariables
();
setRelOrientation
();
setRelScale
();
interOrientationAndScale
();
}
void
Match
::
calculateInternalVariables
()
{
vijx
=
r
->
getx1
()
-
s
->
getx1
();
vijy
=
r
->
gety1
()
-
s
->
gety1
();
vmnx
=
r
->
getx2
()
-
s
->
getx2
();
vmny
=
r
->
gety2
()
-
s
->
gety2
();
}
void
Match
::
setRelOrientation
()
{
relOrientation
=
angleAbsDiff
(
r
->
getRelOri
(),
s
->
getRelOri
());
}
void
Match
::
setRelScale
()
{
relScale
=
std
::
fabs
(
r
->
getRelScale
()
-
s
->
getRelScale
());
}
float
Match
::
angleAbsDiff
(
float
a1
,
float
a2
)
{
float
ad
=
std
::
fabs
(
a1
-
a2
);
while
(
ad
>
2
*
CV_PI
)
{
ad
=
static_cast
<
float
>
(
ad
-
2
*
CV_PI
);
}
ad
=
std
::
min
(
std
::
fabs
(
ad
),
std
::
fabs
(
static_cast
<
float
>
(
2
*
CV_PI
-
std
::
fabs
(
ad
))));
return
ad
;
}
void
Match
::
interOrientationAndScale
()
{
float
cp
=
vijx
*
vmny
-
vijy
*
vmnx
;
// analogous to 2D cross product
float
nmij
=
std
::
sqrt
(
vijx
*
vijx
+
vijy
*
vijy
);
float
nmnm
=
std
::
sqrt
(
vmnx
*
vmnx
+
vmny
*
vmny
);
float
fr
=
(
vijx
*
vmnx
+
vijy
*
vmny
)
/
(
nmij
*
nmnm
);
// numerator equivalent to dot product
fr
=
std
::
min
(
std
::
max
(
fr
,
-
1.0
f
),
1.0
f
);
ro3
=
std
::
acos
(
fr
)
*
sign
(
cp
);
rs3
=
std
::
log
(
nmij
)
-
std
::
log
(
nmnm
);
interOrientation
=
angleAbsDiff
(
r
->
getRelOri
(),
ro3
);
interScale
=
std
::
fabs
(
r
->
getRelScale
()
-
rs3
);
}
void
Match
::
printMatch
()
const
{
std
::
cout
<<
"Relative Orientation: "
<<
relOrientation
<<
std
::
endl
;
std
::
cout
<<
"Relative Scale: "
<<
relScale
<<
std
::
endl
;
std
::
cout
<<
"Inter Orientation: "
<<
interOrientation
<<
std
::
endl
;
std
::
cout
<<
"Inter Scale: "
<<
interScale
<<
std
::
endl
;
std
::
cout
<<
"Global Relative Orientation: "
<<
r
->
getRelOri
()
<<
std
::
endl
;
}
int
Match
::
sign
(
float
x
)
{
return
(
x
>
0
)
-
(
x
<
0
);
}
}
modules/xfeatures2d/src/logos/Match.hpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
/*
* MIT License
*
* Copyright (c) 2018 Stephanie Lowry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef MATCH_HPP
#define MATCH_HPP
#include "PointPair.hpp"
namespace
logos
{
class
Match
{
private
:
PointPair
*
r
;
PointPair
*
s
;
float
relOrientation
;
float
relScale
;
float
interOrientation
;
float
interScale
;
// Internal variables
float
ro3
;
float
rs3
;
float
vijx
;
float
vijy
;
float
vmnx
;
float
vmny
;
// Internal functions
void
calculateInternalVariables
();
void
setRelOrientation
();
void
setRelScale
();
float
angleDiff
(
float
a1
,
float
a2
);
float
angleAbsDiff
(
float
a1
,
float
a2
);
void
interOrientationAndScale
();
int
sign
(
float
x
);
public
:
Match
(
PointPair
*
r
,
PointPair
*
s
);
inline
float
getRelOrientation
()
const
{
return
relOrientation
;
}
inline
float
getRelScale
()
const
{
return
relScale
;
}
inline
float
getInterOrientation
()
const
{
return
interOrientation
;
}
inline
float
getInterScale
()
const
{
return
interScale
;
}
void
printMatch
()
const
;
};
}
#endif
modules/xfeatures2d/src/logos/Point.cpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
/*
* MIT License
*
* Copyright (c) 2018 Stephanie Lowry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <iostream>
#include <algorithm> // std::sort
#include "Point.hpp"
namespace
logos
{
static
bool
cMP
(
const
MatchPoint
&
m
,
const
MatchPoint
&
n
)
{
return
(
m
.
sd
<
n
.
sd
);
}
Point
::
Point
()
:
x
(
0
),
y
(
0
),
orientation
(
0
),
scale
(
1
),
nnVector
(),
nnFound
(
false
),
label
(
0
)
{
}
Point
::
Point
(
float
x_
,
float
y_
,
float
orientation_
,
float
scale_
,
int
label_
)
:
x
(
x_
),
y
(
y_
),
orientation
(
orientation_
),
scale
(
scale_
),
nnVector
(),
nnFound
(
false
),
label
(
label_
)
{
}
void
Point
::
nearestNeighbours
(
const
std
::
vector
<
Point
*>&
vP
,
int
index
,
int
N
)
{
nearestNeighboursNaive
(
vP
,
index
,
N
);
}
void
Point
::
nearestNeighboursNaive
(
const
std
::
vector
<
Point
*>&
vP
,
int
index
,
int
N
)
{
// only want to calculate once.
if
(
nnFound
)
{
return
;
}
std
::
vector
<
MatchPoint
>
minMatch
;
minMatch
.
reserve
(
vP
.
size
());
int
i
=
0
;
for
(
std
::
vector
<
Point
*>::
const_iterator
it
=
vP
.
begin
();
it
!=
vP
.
end
();
++
it
,
i
++
)
{
// A point is not it's own neighbour
if
(
i
==
index
)
{
continue
;
}
float
sd
=
squareDist
(
getx
(),
gety
(),
(
*
it
)
->
getx
(),
(
*
it
)
->
gety
());
MatchPoint
mP
(
sd
,
i
);
minMatch
.
push_back
(
mP
);
}
std
::
sort
(
minMatch
.
begin
(),
minMatch
.
end
(),
cMP
);
nnVector
.
resize
(
static_cast
<
size_t
>
(
N
));
int
count
=
0
;
for
(
std
::
vector
<
MatchPoint
>::
const_iterator
mmit
=
minMatch
.
begin
();
count
<
N
;
++
mmit
,
count
++
)
{
nnVector
[
static_cast
<
size_t
>
(
count
)]
=
vP
[
static_cast
<
size_t
>
(
mmit
->
index
)];
}
nnFound
=
true
;
}
void
Point
::
matchLabel
(
int
label_
,
std
::
vector
<
Point
*>&
matchNN
)
{
for
(
std
::
vector
<
Point
*>::
const_iterator
nnIterator
=
nnVector
.
begin
();
nnIterator
!=
nnVector
.
end
();
++
nnIterator
)
{
if
((
*
nnIterator
)
->
label
==
label_
)
{
matchNN
.
push_back
(
*
nnIterator
);
}
}
}
void
Point
::
printPoint
()
const
{
std
::
cout
<<
getx
()
<<
" "
<<
gety
()
<<
" "
<<
getOrientation
()
<<
" "
<<
getScale
()
<<
" "
<<
getLabel
()
<<
std
::
endl
;
}
void
Point
::
printNN
()
const
{
for
(
std
::
vector
<
Point
*>::
const_iterator
nnIterator
=
nnVector
.
begin
();
nnIterator
!=
nnVector
.
end
();
++
nnIterator
)
{
(
*
nnIterator
)
->
printPoint
();
}
}
float
Point
::
squareDist
(
float
x1
,
float
y1
,
float
x2
,
float
y2
)
{
return
(
x1
-
x2
)
*
(
x1
-
x2
)
+
(
y1
-
y2
)
*
(
y1
-
y2
);
}
}
modules/xfeatures2d/src/logos/Point.hpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
/*
* MIT License
*
* Copyright (c) 2018 Stephanie Lowry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef POINT_HPP
#define POINT_HPP
#include <vector>
namespace
logos
{
struct
MatchPoint
{
float
sd
;
int
index
;
MatchPoint
(
float
sd_
,
int
idx
)
:
sd
(
sd_
),
index
(
idx
)
{}
};
class
Point
{
private
:
float
x
;
float
y
;
float
orientation
;
float
scale
;
std
::
vector
<
Point
*>
nnVector
;
bool
nnFound
;
int
label
;
public
:
Point
();
Point
(
float
x_
,
float
y_
,
float
orientation_
,
float
scale_
,
int
label_
=
0
);
inline
float
getx
()
const
{
return
x
;
}
inline
float
gety
()
const
{
return
y
;
}
inline
float
getOrientation
()
const
{
return
orientation
;
}
inline
float
getScale
()
const
{
return
scale
;
}
inline
int
getLabel
()
const
{
return
label
;
}
inline
void
setLabel
(
int
label_
)
{
label
=
label_
;
}
inline
void
getNNVector
(
std
::
vector
<
Point
*>&
nnv
)
const
{
nnv
=
nnVector
;
}
void
matchLabel
(
int
label
,
std
::
vector
<
Point
*>&
mNN
);
void
nearestNeighbours
(
const
std
::
vector
<
Point
*>&
vP
,
int
index
,
int
N
);
void
nearestNeighboursNaive
(
const
std
::
vector
<
Point
*>&
vP
,
int
index
,
int
N
);
void
printPoint
()
const
;
void
printNN
()
const
;
float
squareDist
(
float
x1
,
float
y1
,
float
x2
,
float
y2
);
};
}
#endif
modules/xfeatures2d/src/logos/PointPair.cpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
/*
* MIT License
*
* Copyright (c) 2018 Stephanie Lowry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <opencv2/core.hpp>
#include "PointPair.hpp"
namespace
logos
{
PointPair
::
PointPair
(
Point
*
p_
,
Point
*
q_
)
:
p
(
p_
),
q
(
q_
),
support
(
0
),
pos1
(
0
),
pos2
(
0
)
{
calculateInternalVariables
();
}
void
PointPair
::
computeLocalSupport
(
std
::
vector
<
PointPair
*>&
pp
,
int
N
)
{
std
::
vector
<
Point
*>
nnVector
;
p
->
getNNVector
(
nnVector
);
// Exposes the nearest neighbours
// for each nearest neighbour
for
(
std
::
vector
<
Point
*>::
iterator
nnIterator
=
nnVector
.
begin
();
nnIterator
!=
nnVector
.
end
();
++
nnIterator
)
{
// is there a matching nearestNeighbour?
std
::
vector
<
Point
*>
matchNN
;
matchNN
.
reserve
(
static_cast
<
size_t
>
(
N
));
q
->
matchLabel
((
*
nnIterator
)
->
getLabel
(),
matchNN
);
for
(
std
::
vector
<
Point
*>::
const_iterator
mit
=
matchNN
.
begin
();
mit
!=
matchNN
.
end
();
++
mit
)
{
PointPair
*
m
=
new
PointPair
(
*
nnIterator
,
*
mit
);
pp
.
push_back
(
m
);
}
}
}
void
PointPair
::
calculateInternalVariables
()
{
relOri
=
angleDiff
(
p
->
getOrientation
(),
q
->
getOrientation
());
relScale
=
std
::
log
(
p
->
getScale
())
-
std
::
log
(
q
->
getScale
());
}
float
PointPair
::
angleDiff
(
float
a1
,
float
a2
)
{
float
ad
=
a1
-
a2
;
while
(
ad
>
CV_PI
)
{
ad
=
static_cast
<
float
>
(
ad
-
2
*
CV_PI
);
}
while
(
ad
<
-
CV_PI
)
{
ad
=
static_cast
<
float
>
(
ad
+
2
*
CV_PI
);
}
return
ad
;
}
}
modules/xfeatures2d/src/logos/PointPair.hpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
/*
* MIT License
*
* Copyright (c) 2018 Stephanie Lowry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef POINTPAIR_HPP
#define POINTPAIR_HPP
#include "Point.hpp"
namespace
logos
{
class
PointPair
{
private
:
Point
*
p
;
Point
*
q
;
int
support
;
float
relOri
;
float
relScale
;
int
pos1
;
int
pos2
;
float
angleDiff
(
float
a1
,
float
a2
);
public
:
PointPair
(
Point
*
p_
,
Point
*
q_
);
void
computeLocalSupport
(
std
::
vector
<
PointPair
*>&
pp
,
int
N
);
void
calculateInternalVariables
();
float
getRelOri
()
const
{
return
relOri
;
}
float
getRelScale
()
const
{
return
relScale
;
}
float
getx1
()
const
{
return
p
->
getx
();
}
float
getx2
()
const
{
return
q
->
getx
();
}
float
gety1
()
const
{
return
p
->
gety
();
}
float
gety2
()
const
{
return
q
->
gety
();
}
void
addPositions
(
int
pos1_
,
int
pos2_
)
{
pos1
=
pos1_
;
pos2
=
pos2_
;
}
int
getPos1
()
const
{
return
pos1
;
}
int
getPos2
()
const
{
return
pos2
;
}
int
getSupport
()
const
{
return
support
;
}
void
setSupport
(
int
support_
)
{
support
=
support_
;
}
};
}
#endif
modules/xfeatures2d/test/test_logos_matcher.cpp
0 → 100644
View file @
f9bbe706
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
namespace
opencv_test
{
namespace
{
static
void
loadKeypoints
(
const
std
::
string
&
vP_path
,
const
std
::
string
&
oP_path
,
const
std
::
string
&
sP_path
,
const
std
::
string
&
w_path
,
std
::
vector
<
cv
::
KeyPoint
>&
keypoints
,
std
::
vector
<
int
>&
nn
)
{
{
std
::
ifstream
file
(
vP_path
.
c_str
());
if
(
file
.
is_open
())
{
float
x
=
0
,
y
=
0
;
while
(
file
>>
x
>>
y
)
{
keypoints
.
push_back
(
cv
::
KeyPoint
(
x
,
y
,
0
));
}
}
}
{
std
::
ifstream
file
(
oP_path
.
c_str
());
if
(
file
.
is_open
())
{
float
orientation
=
0
;
size_t
idx
=
0
;
while
(
file
>>
orientation
)
{
keypoints
[
idx
].
angle
=
static_cast
<
float
>
(
orientation
*
180.0
/
CV_PI
);
idx
++
;
}
}
}
{
std
::
ifstream
file
(
sP_path
.
c_str
());
if
(
file
.
is_open
())
{
float
scale
=
0
;
size_t
idx
=
0
;
while
(
file
>>
scale
)
{
keypoints
[
idx
].
size
=
scale
;
idx
++
;
}
}
}
{
std
::
ifstream
file
(
w_path
.
c_str
());
if
(
file
.
is_open
())
{
int
neighborIdx
=
0
;
while
(
file
>>
neighborIdx
)
{
nn
.
push_back
(
neighborIdx
);
}
}
}
ASSERT_TRUE
(
!
keypoints
.
empty
());
}
static
void
loadGroundTruth
(
const
std
::
string
&
d1_path
,
const
std
::
string
&
b1_path
,
std
::
vector
<
cv
::
DMatch
>&
groundTruth
)
{
std
::
vector
<
int
>
d1_vec
;
{
std
::
ifstream
file
(
d1_path
.
c_str
());
if
(
file
.
is_open
())
{
int
idx
=
0
;
while
(
file
>>
idx
)
{
d1_vec
.
push_back
(
idx
-
1
);
}
}
}
std
::
vector
<
int
>
b1_vec
;
{
std
::
ifstream
file
(
b1_path
.
c_str
());
if
(
file
.
is_open
())
{
int
idx
=
0
;
while
(
file
>>
idx
)
{
b1_vec
.
push_back
(
idx
-
1
);
}
}
}
ASSERT_TRUE
(
!
d1_vec
.
empty
());
ASSERT_EQ
(
d1_vec
.
size
(),
b1_vec
.
size
());
for
(
size_t
i
=
0
;
i
<
d1_vec
.
size
();
i
++
)
{
groundTruth
.
push_back
(
cv
::
DMatch
(
d1_vec
[
i
],
b1_vec
[
i
],
0
));
}
}
TEST
(
XFeatures2d_LogosMatcher
,
logos_matcher_regression
)
{
const
std
::
string
vP1_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/vP1.txt"
);
const
std
::
string
oP1_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/oP1.txt"
);
const
std
::
string
sP1_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/sP1.txt"
);
const
std
::
string
w1_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/w1.txt"
);
const
std
::
string
vP2_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/vP2.txt"
);
const
std
::
string
oP2_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/oP2.txt"
);
const
std
::
string
sP2_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/sP2.txt"
);
const
std
::
string
w2_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/w2.txt"
);
std
::
vector
<
cv
::
KeyPoint
>
keypoints1
,
keypoints2
;
std
::
vector
<
int
>
nn1
,
nn2
;
loadKeypoints
(
vP1_path
,
oP1_path
,
sP1_path
,
w1_path
,
keypoints1
,
nn1
);
loadKeypoints
(
vP2_path
,
oP2_path
,
sP2_path
,
w2_path
,
keypoints2
,
nn2
);
std
::
vector
<
cv
::
DMatch
>
matchesLogos
;
matchLOGOS
(
keypoints1
,
keypoints2
,
nn1
,
nn2
,
matchesLogos
);
std
::
vector
<
cv
::
DMatch
>
groundTruth
;
const
std
::
string
d1_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/d1.txt"
);
const
std
::
string
b1_path
=
cvtest
::
findDataFile
(
"detectors_descriptors_evaluation/matching/LOGOS/b1.txt"
);
loadGroundTruth
(
d1_path
,
b1_path
,
groundTruth
);
int
correctMatches
=
0
;
for
(
size_t
i
=
0
;
i
<
matchesLogos
.
size
();
i
++
)
{
for
(
size_t
j
=
0
;
j
<
groundTruth
.
size
();
j
++
)
{
if
(
groundTruth
[
j
].
queryIdx
==
matchesLogos
[
i
].
queryIdx
&&
groundTruth
[
j
].
trainIdx
==
matchesLogos
[
j
].
trainIdx
)
{
correctMatches
++
;
break
;
}
}
}
ASSERT_EQ
(
static_cast
<
int
>
(
groundTruth
.
size
()),
correctMatches
)
<<
"groundTruth: "
<<
groundTruth
.
size
()
<<
" ; matchesLogos: "
<<
matchesLogos
.
size
()
<<
" ; correctMatches: "
<<
correctMatches
;
}
}}
// namespace
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