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
9399394e
Commit
9399394e
authored
May 31, 2012
by
Andrey Kamaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed #1996
parent
1a572c8e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
179 additions
and
131 deletions
+179
-131
fast.cpp
modules/features2d/src/fast.cpp
+32
-32
orb.cpp
modules/features2d/src/orb.cpp
+98
-99
test_features2d.cpp
modules/features2d/test/test_features2d.cpp
+49
-0
No files found.
modules/features2d/src/fast.cpp
View file @
9399394e
...
...
@@ -16,8 +16,8 @@ are met:
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
*Neither the name of the University of Cambridge nor the names of
its contributors may be used to endorse or promote products derived
*Neither the name of the University of Cambridge nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
...
...
@@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*
The references are:
* Machine learning for high-speed corner detection,
* Machine learning for high-speed corner detection,
E. Rosten and T. Drummond, ECCV 2006
* Faster and better: A machine learning approach to corner detection
E. Rosten, R. Porter and T. Drummond, PAMI, 2009
...
...
@@ -64,7 +64,7 @@ static void makeOffsets(int pixel[], int row_stride)
pixel
[
13
]
=
-
3
+
row_stride
*
1
;
pixel
[
14
]
=
-
2
+
row_stride
*
2
;
pixel
[
15
]
=
-
1
+
row_stride
*
3
;
}
}
static
int
cornerScore
(
const
uchar
*
ptr
,
const
int
pixel
[],
int
threshold
)
{
...
...
@@ -73,7 +73,7 @@ static int cornerScore(const uchar* ptr, const int pixel[], int threshold)
short
d
[
N
];
for
(
k
=
0
;
k
<
N
;
k
++
)
d
[
k
]
=
(
short
)(
v
-
ptr
[
pixel
[
k
]]);
#if CV_SSE2
__m128i
q0
=
_mm_set1_epi16
(
-
1000
),
q1
=
_mm_set1_epi16
(
1000
);
for
(
k
=
0
;
k
<
16
;
k
+=
8
)
...
...
@@ -128,7 +128,7 @@ static int cornerScore(const uchar* ptr, const int pixel[], int threshold)
a0
=
std
::
max
(
a0
,
std
::
min
(
a
,
(
int
)
d
[
k
]));
a0
=
std
::
max
(
a0
,
std
::
min
(
a
,
(
int
)
d
[
k
+
9
]));
}
int
b0
=
-
a0
;
for
(
k
=
0
;
k
<
16
;
k
+=
2
)
{
...
...
@@ -141,14 +141,14 @@ static int cornerScore(const uchar* ptr, const int pixel[], int threshold)
b
=
std
::
max
(
b
,
(
int
)
d
[
k
+
6
]);
b
=
std
::
max
(
b
,
(
int
)
d
[
k
+
7
]);
b
=
std
::
max
(
b
,
(
int
)
d
[
k
+
8
]);
b0
=
std
::
min
(
b0
,
std
::
max
(
b
,
(
int
)
d
[
k
]));
b0
=
std
::
min
(
b0
,
std
::
max
(
b
,
(
int
)
d
[
k
+
9
]));
}
threshold
=
-
b0
-
1
;
#endif
#if 0
// check that with the computed "threshold" the pixel is still a corner
// and that with the increased-by-1 "threshold" the pixel is not a corner anymore
...
...
@@ -157,7 +157,7 @@ static int cornerScore(const uchar* ptr, const int pixel[], int threshold)
int v0 = std::min(ptr[0] + threshold + delta, 255);
int v1 = std::max(ptr[0] - threshold - delta, 0);
int c0 = 0, c1 = 0;
for( int k = 0; k < N; k++ )
{
int x = ptr[pixel[k]];
...
...
@@ -184,7 +184,7 @@ static int cornerScore(const uchar* ptr, const int pixel[], int threshold)
#endif
return
threshold
;
}
void
FAST
(
InputArray
_img
,
std
::
vector
<
KeyPoint
>&
keypoints
,
int
threshold
,
bool
nonmax_suppression
)
{
...
...
@@ -214,7 +214,7 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
cpbuf
[
1
]
=
cpbuf
[
0
]
+
img
.
cols
+
1
;
cpbuf
[
2
]
=
cpbuf
[
1
]
+
img
.
cols
+
1
;
memset
(
buf
[
0
],
0
,
img
.
cols
*
3
);
for
(
i
=
3
;
i
<
img
.
rows
-
2
;
i
++
)
{
const
uchar
*
ptr
=
img
.
ptr
<
uchar
>
(
i
)
+
3
;
...
...
@@ -222,7 +222,7 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
int
*
cornerpos
=
cpbuf
[(
i
-
3
)
%
3
];
memset
(
curr
,
0
,
img
.
cols
);
int
ncorners
=
0
;
if
(
i
<
img
.
rows
-
3
)
{
j
=
3
;
...
...
@@ -233,7 +233,7 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
__m128i
v0
=
_mm_loadu_si128
((
const
__m128i
*
)
ptr
);
__m128i
v1
=
_mm_xor_si128
(
_mm_subs_epu8
(
v0
,
t
),
delta
);
v0
=
_mm_xor_si128
(
_mm_adds_epu8
(
v0
,
t
),
delta
);
__m128i
x0
=
_mm_sub_epi8
(
_mm_loadu_si128
((
const
__m128i
*
)(
ptr
+
pixel
[
0
])),
delta
);
__m128i
x1
=
_mm_sub_epi8
(
_mm_loadu_si128
((
const
__m128i
*
)(
ptr
+
pixel
[
4
])),
delta
);
__m128i
x2
=
_mm_sub_epi8
(
_mm_loadu_si128
((
const
__m128i
*
)(
ptr
+
pixel
[
8
])),
delta
);
...
...
@@ -256,24 +256,24 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
ptr
-=
8
;
continue
;
}
__m128i
c0
=
_mm_setzero_si128
(),
c1
=
c0
,
max0
=
c0
,
max1
=
c0
;
for
(
k
=
0
;
k
<
N
;
k
++
)
{
__m128i
x
=
_mm_xor_si128
(
_mm_loadu_si128
((
const
__m128i
*
)(
ptr
+
pixel
[
k
])),
delta
);
m0
=
_mm_cmpgt_epi8
(
x
,
v0
);
m1
=
_mm_cmpgt_epi8
(
v1
,
x
);
c0
=
_mm_and_si128
(
_mm_sub_epi8
(
c0
,
m0
),
m0
);
c1
=
_mm_and_si128
(
_mm_sub_epi8
(
c1
,
m1
),
m1
);
max0
=
_mm_max_epu8
(
max0
,
c0
);
max1
=
_mm_max_epu8
(
max1
,
c1
);
}
max0
=
_mm_max_epu8
(
max0
,
max1
);
int
m
=
_mm_movemask_epi8
(
_mm_cmpgt_epi8
(
max0
,
K16
));
for
(
k
=
0
;
m
>
0
&&
k
<
16
;
k
++
,
m
>>=
1
)
if
(
m
&
1
)
{
...
...
@@ -288,26 +288,26 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
int
v
=
ptr
[
0
];
const
uchar
*
tab
=
&
threshold_tab
[
0
]
-
v
+
255
;
int
d
=
tab
[
ptr
[
pixel
[
0
]]]
|
tab
[
ptr
[
pixel
[
8
]]];
if
(
d
==
0
)
continue
;
d
&=
tab
[
ptr
[
pixel
[
2
]]]
|
tab
[
ptr
[
pixel
[
10
]]];
d
&=
tab
[
ptr
[
pixel
[
4
]]]
|
tab
[
ptr
[
pixel
[
12
]]];
d
&=
tab
[
ptr
[
pixel
[
6
]]]
|
tab
[
ptr
[
pixel
[
14
]]];
if
(
d
==
0
)
continue
;
d
&=
tab
[
ptr
[
pixel
[
1
]]]
|
tab
[
ptr
[
pixel
[
9
]]];
d
&=
tab
[
ptr
[
pixel
[
3
]]]
|
tab
[
ptr
[
pixel
[
11
]]];
d
&=
tab
[
ptr
[
pixel
[
5
]]]
|
tab
[
ptr
[
pixel
[
13
]]];
d
&=
tab
[
ptr
[
pixel
[
7
]]]
|
tab
[
ptr
[
pixel
[
15
]]];
if
(
d
&
1
)
{
int
vt
=
v
-
threshold
,
count
=
0
;
for
(
k
=
0
;
k
<
N
;
k
++
)
{
int
x
=
ptr
[
pixel
[
k
]];
...
...
@@ -325,11 +325,11 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
count
=
0
;
}
}
if
(
d
&
2
)
{
int
vt
=
v
+
threshold
,
count
=
0
;
for
(
k
=
0
;
k
<
N
;
k
++
)
{
int
x
=
ptr
[
pixel
[
k
]];
...
...
@@ -349,17 +349,17 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
}
}
}
cornerpos
[
-
1
]
=
ncorners
;
if
(
i
==
3
)
continue
;
const
uchar
*
prev
=
buf
[(
i
-
4
+
3
)
%
3
];
const
uchar
*
pprev
=
buf
[(
i
-
5
+
3
)
%
3
];
cornerpos
=
cpbuf
[(
i
-
4
+
3
)
%
3
];
ncorners
=
cornerpos
[
-
1
];
for
(
k
=
0
;
k
<
ncorners
;
k
++
)
{
j
=
cornerpos
[
k
];
...
...
@@ -375,7 +375,7 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
}
}
/*
* FastFeatureDetector
*/
...
...
modules/features2d/src/orb.cpp
View file @
9399394e
...
...
@@ -53,31 +53,31 @@ static void
HarrisResponses
(
const
Mat
&
img
,
vector
<
KeyPoint
>&
pts
,
int
blockSize
,
float
harris_k
)
{
CV_Assert
(
img
.
type
()
==
CV_8UC1
&&
blockSize
*
blockSize
<=
2048
);
size_t
ptidx
,
ptsize
=
pts
.
size
();
const
uchar
*
ptr00
=
img
.
ptr
<
uchar
>
();
int
step
=
(
int
)(
img
.
step
/
img
.
elemSize1
());
int
r
=
blockSize
/
2
;
float
scale
=
(
1
<<
2
)
*
blockSize
*
255.0
f
;
scale
=
1.0
f
/
scale
;
float
scale_sq_sq
=
scale
*
scale
*
scale
*
scale
;
AutoBuffer
<
int
>
ofsbuf
(
blockSize
*
blockSize
);
int
*
ofs
=
ofsbuf
;
for
(
int
i
=
0
;
i
<
blockSize
;
i
++
)
for
(
int
j
=
0
;
j
<
blockSize
;
j
++
)
ofs
[
i
*
blockSize
+
j
]
=
(
int
)(
i
*
step
+
j
);
for
(
ptidx
=
0
;
ptidx
<
ptsize
;
ptidx
++
)
{
int
x0
=
cvRound
(
pts
[
ptidx
].
pt
.
x
-
r
);
int
y0
=
cvRound
(
pts
[
ptidx
].
pt
.
y
-
r
);
const
uchar
*
ptr0
=
ptr00
+
y0
*
step
+
x0
;
int
a
=
0
,
b
=
0
,
c
=
0
;
for
(
int
k
=
0
;
k
<
blockSize
*
blockSize
;
k
++
)
{
const
uchar
*
ptr
=
ptr0
+
ofs
[
k
];
...
...
@@ -98,13 +98,13 @@ static float IC_Angle(const Mat& image, const int half_k, Point2f pt,
const
vector
<
int
>
&
u_max
)
{
int
m_01
=
0
,
m_10
=
0
;
const
uchar
*
center
=
&
image
.
at
<
uchar
>
(
cvRound
(
pt
.
y
),
cvRound
(
pt
.
x
));
// Treat the center line differently, v=0
for
(
int
u
=
-
half_k
;
u
<=
half_k
;
++
u
)
m_10
+=
u
*
center
[
u
];
// Go line by line in the circular patch
int
step
=
(
int
)
image
.
step1
();
for
(
int
v
=
1
;
v
<=
half_k
;
++
v
)
...
...
@@ -120,7 +120,7 @@ static float IC_Angle(const Mat& image, const int half_k, Point2f pt,
}
m_01
+=
v
*
v_sum
;
}
return
fastAtan2
((
float
)
m_01
,
(
float
)
m_10
);
}
...
...
@@ -134,10 +134,10 @@ static void computeOrbDescriptor(const KeyPoint& kpt,
//angle = cvFloor(angle/12)*12.f;
angle
*=
(
float
)(
CV_PI
/
180.
f
);
float
a
=
(
float
)
cos
(
angle
),
b
=
(
float
)
sin
(
angle
);
const
uchar
*
center
=
&
img
.
at
<
uchar
>
(
cvRound
(
kpt
.
pt
.
y
),
cvRound
(
kpt
.
pt
.
x
));
int
step
=
(
int
)
img
.
step
;
#if 1
#define GET_VALUE(idx) \
center[cvRound(pattern[idx].x*b + pattern[idx].y*a)*step + \
...
...
@@ -153,7 +153,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt,
cvRound(center[iy*step + ix]*(1-x)*(1-y) + center[(iy+1)*step + ix]*(1-x)*y + \
center[iy*step + ix+1]*x*(1-y) + center[(iy+1)*step + ix+1]*x*y))
#endif
if
(
WTA_K
==
2
)
{
for
(
int
i
=
0
;
i
<
dsize
;
++
i
,
pattern
+=
16
)
...
...
@@ -175,7 +175,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt,
val
|=
(
t0
<
t1
)
<<
6
;
t0
=
GET_VALUE
(
14
);
t1
=
GET_VALUE
(
15
);
val
|=
(
t0
<
t1
)
<<
7
;
desc
[
i
]
=
(
uchar
)
val
;
}
}
...
...
@@ -186,16 +186,16 @@ static void computeOrbDescriptor(const KeyPoint& kpt,
int
t0
,
t1
,
t2
,
val
;
t0
=
GET_VALUE
(
0
);
t1
=
GET_VALUE
(
1
);
t2
=
GET_VALUE
(
2
);
val
=
t2
>
t1
?
(
t2
>
t0
?
2
:
0
)
:
(
t1
>
t0
);
t0
=
GET_VALUE
(
3
);
t1
=
GET_VALUE
(
4
);
t2
=
GET_VALUE
(
5
);
val
|=
(
t2
>
t1
?
(
t2
>
t0
?
2
:
0
)
:
(
t1
>
t0
))
<<
2
;
t0
=
GET_VALUE
(
6
);
t1
=
GET_VALUE
(
7
);
t2
=
GET_VALUE
(
8
);
val
|=
(
t2
>
t1
?
(
t2
>
t0
?
2
:
0
)
:
(
t1
>
t0
))
<<
4
;
t0
=
GET_VALUE
(
9
);
t1
=
GET_VALUE
(
10
);
t2
=
GET_VALUE
(
11
);
val
|=
(
t2
>
t1
?
(
t2
>
t0
?
2
:
0
)
:
(
t1
>
t0
))
<<
6
;
desc
[
i
]
=
(
uchar
)
val
;
}
}
...
...
@@ -211,7 +211,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt,
if
(
t3
>
t2
)
t2
=
t3
,
v
=
3
;
k
=
t0
>
t2
?
u
:
v
;
val
=
k
;
t0
=
GET_VALUE
(
4
);
t1
=
GET_VALUE
(
5
);
t2
=
GET_VALUE
(
6
);
t3
=
GET_VALUE
(
7
);
u
=
0
,
v
=
2
;
...
...
@@ -219,7 +219,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt,
if
(
t3
>
t2
)
t2
=
t3
,
v
=
3
;
k
=
t0
>
t2
?
u
:
v
;
val
|=
k
<<
2
;
t0
=
GET_VALUE
(
8
);
t1
=
GET_VALUE
(
9
);
t2
=
GET_VALUE
(
10
);
t3
=
GET_VALUE
(
11
);
u
=
0
,
v
=
2
;
...
...
@@ -227,7 +227,7 @@ static void computeOrbDescriptor(const KeyPoint& kpt,
if
(
t3
>
t2
)
t2
=
t3
,
v
=
3
;
k
=
t0
>
t2
?
u
:
v
;
val
|=
k
<<
4
;
t0
=
GET_VALUE
(
12
);
t1
=
GET_VALUE
(
13
);
t2
=
GET_VALUE
(
14
);
t3
=
GET_VALUE
(
15
);
u
=
0
,
v
=
2
;
...
...
@@ -235,23 +235,23 @@ static void computeOrbDescriptor(const KeyPoint& kpt,
if
(
t3
>
t2
)
t2
=
t3
,
v
=
3
;
k
=
t0
>
t2
?
u
:
v
;
val
|=
k
<<
6
;
desc
[
i
]
=
(
uchar
)
val
;
}
}
else
CV_Error
(
CV_StsBadSize
,
"Wrong WTA_K. It can be only 2, 3 or 4."
);
#undef GET_VALUE
}
static
void
initializeOrbPattern
(
const
Point
*
pattern0
,
vector
<
Point
>&
pattern
,
int
ntuples
,
int
tupleSize
,
int
poolSize
)
{
RNG
rng
(
0x12345678
);
int
i
,
k
,
k1
;
pattern
.
resize
(
ntuples
*
tupleSize
);
for
(
i
=
0
;
i
<
ntuples
;
i
++
)
{
for
(
k
=
0
;
k
<
tupleSize
;
k
++
)
...
...
@@ -545,7 +545,7 @@ static void makeRandomPattern(int patchSize, Point* pattern, int npoints)
}
}
static
inline
float
getScale
(
int
level
,
int
firstLevel
,
double
scaleFactor
)
{
return
(
float
)
std
::
pow
(
scaleFactor
,
(
double
)(
level
-
firstLevel
));
...
...
@@ -570,8 +570,8 @@ int ORB::descriptorSize() const
int
ORB
::
descriptorType
()
const
{
return
CV_8U
;
}
}
/** Compute the ORB features and descriptors on an image
* @param img the image to compute the features and descriptors on
* @param mask the mask to apply
...
...
@@ -599,7 +599,7 @@ static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints,
keypoint
->
angle
=
IC_Angle
(
image
,
halfPatchSize
,
keypoint
->
pt
,
umax
);
}
}
/** Compute the ORB keypoints on an image
* @param image_pyramid the image pyramid to compute the features and descriptors on
...
...
@@ -614,11 +614,11 @@ static void computeKeyPoints(const vector<Mat>& imagePyramid,
{
int
nlevels
=
(
int
)
imagePyramid
.
size
();
vector
<
int
>
nfeaturesPerLevel
(
nlevels
);
// fill the extractors and descriptors for the corresponding scales
float
factor
=
(
float
)(
1.0
/
scaleFactor
);
float
ndesiredFeaturesPerScale
=
nfeatures
*
(
1
-
factor
)
/
(
1
-
(
float
)
pow
((
double
)
factor
,
(
double
)
nlevels
));
int
sumFeatures
=
0
;
for
(
int
level
=
0
;
level
<
nlevels
-
1
;
level
++
)
{
...
...
@@ -627,19 +627,19 @@ static void computeKeyPoints(const vector<Mat>& imagePyramid,
ndesiredFeaturesPerScale
*=
factor
;
}
nfeaturesPerLevel
[
nlevels
-
1
]
=
std
::
max
(
nfeatures
-
sumFeatures
,
0
);
// Make sure we forget about what is too close to the boundary
//edge_threshold_ = std::max(edge_threshold_, patch_size_/2 + kKernelWidth / 2 + 2);
// pre-compute the end of a row in a circular patch
int
halfPatchSize
=
patchSize
/
2
;
vector
<
int
>
umax
(
halfPatchSize
+
1
);
int
v
,
v0
,
vmax
=
cvFloor
(
halfPatchSize
*
sqrt
(
2.
f
)
/
2
+
1
);
int
vmin
=
cvCeil
(
halfPatchSize
*
sqrt
(
2.
f
)
/
2
);
for
(
v
=
0
;
v
<=
vmax
;
++
v
)
umax
[
v
]
=
cvRound
(
sqrt
((
double
)
halfPatchSize
*
halfPatchSize
-
v
*
v
));
// Make sure we are symmetric
for
(
v
=
halfPatchSize
,
v0
=
0
;
v
>=
vmin
;
--
v
)
{
...
...
@@ -648,37 +648,37 @@ static void computeKeyPoints(const vector<Mat>& imagePyramid,
umax
[
v
]
=
v0
;
++
v0
;
}
allKeypoints
.
resize
(
nlevels
);
for
(
int
level
=
0
;
level
<
nlevels
;
++
level
)
{
int
nfeatures
=
nfeaturesPerLevel
[
level
];
allKeypoints
[
level
].
reserve
(
nfeatures
*
2
);
vector
<
KeyPoint
>
&
keypoints
=
allKeypoints
[
level
];
// Detect FAST features, 20 is a good threshold
FastFeatureDetector
fd
(
20
,
true
);
fd
.
detect
(
imagePyramid
[
level
],
keypoints
,
maskPyramid
[
level
]);
// Remove keypoints very close to the border
KeyPointsFilter
::
runByImageBorder
(
keypoints
,
imagePyramid
[
level
].
size
(),
edgeThreshold
);
if
(
scoreType
==
ORB
::
HARRIS_SCORE
)
{
// Keep more points than necessary as FAST does not give amazing corners
KeyPointsFilter
::
retainBest
(
keypoints
,
2
*
nfeatures
);
// Compute the Harris cornerness (better scoring than FAST)
HarrisResponses
(
imagePyramid
[
level
],
keypoints
,
7
,
HARRIS_K
);
}
//cull to the final desired level, using the new Harris scores or the original FAST scores.
KeyPointsFilter
::
retainBest
(
keypoints
,
nfeatures
);
KeyPointsFilter
::
retainBest
(
keypoints
,
nfeatures
);
float
sf
=
getScale
(
level
,
firstLevel
,
scaleFactor
);
// Set the level of the coordinates
for
(
vector
<
KeyPoint
>::
iterator
keypoint
=
keypoints
.
begin
(),
keypointEnd
=
keypoints
.
end
();
keypoint
!=
keypointEnd
;
++
keypoint
)
...
...
@@ -686,12 +686,12 @@ static void computeKeyPoints(const vector<Mat>& imagePyramid,
keypoint
->
octave
=
level
;
keypoint
->
size
=
patchSize
*
sf
;
}
computeOrientation
(
imagePyramid
[
level
],
keypoints
,
halfPatchSize
,
umax
);
}
}
}
/** Compute the ORB decriptors
* @param image the image to compute the features and descriptors on
* @param integral_image the integral image of the image (can be empty, but the computation will be slower)
...
...
@@ -706,12 +706,12 @@ static void computeDescriptors(const Mat& image, vector<KeyPoint>& keypoints, Ma
CV_Assert
(
image
.
type
()
==
CV_8UC1
);
//create the descriptor mat, keypoints.size() rows, BYTES cols
descriptors
=
Mat
::
zeros
((
int
)
keypoints
.
size
(),
dsize
,
CV_8UC1
);
for
(
size_t
i
=
0
;
i
<
keypoints
.
size
();
i
++
)
computeOrbDescriptor
(
keypoints
[
i
],
image
,
&
pattern
[
0
],
descriptors
.
ptr
((
int
)
i
),
dsize
,
WTA_K
);
}
/** Compute the ORB features and descriptors on an image
* @param img the image to compute the features and descriptors on
* @param mask the mask to apply
...
...
@@ -725,21 +725,21 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
{
bool
do_keypoints
=
!
useProvidedKeypoints
;
bool
do_descriptors
=
_descriptors
.
needed
();
if
(
(
!
do_keypoints
&&
!
do_descriptors
)
||
_image
.
empty
()
)
return
;
//ROI handling
const
int
HARRIS_BLOCK_SIZE
=
9
;
int
halfPatchSize
=
patchSize
/
2
;
int
border
=
std
::
max
(
edgeThreshold
,
std
::
max
(
halfPatchSize
,
HARRIS_BLOCK_SIZE
/
2
))
+
1
;
Mat
image
=
_image
.
getMat
(),
mask
=
_mask
.
getMat
();
if
(
image
.
type
()
!=
CV_8UC1
)
cvtColor
(
_image
,
image
,
CV_BGR2GRAY
);
int
nlevels
=
this
->
nlevels
;
if
(
!
do_keypoints
)
{
// if we have pre-computed keypoints, they may use more levels than it is set in parameters
...
...
@@ -756,7 +756,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
nlevels
=
std
::
max
(
nlevels
,
std
::
max
(
_keypoints
[
i
].
octave
,
0
));
nlevels
++
;
}
// Pre-compute the scale pyramids
vector
<
Mat
>
imagePyramid
(
nlevels
),
maskPyramid
(
nlevels
);
for
(
int
level
=
0
;
level
<
nlevels
;
++
level
)
...
...
@@ -766,49 +766,48 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
Size
wholeSize
(
sz
.
width
+
border
*
2
,
sz
.
height
+
border
*
2
);
Mat
temp
(
wholeSize
,
image
.
type
()),
masktemp
;
imagePyramid
[
level
]
=
temp
(
Rect
(
border
,
border
,
sz
.
width
,
sz
.
height
));
if
(
!
mask
.
empty
()
)
{
masktemp
=
Mat
(
wholeSize
,
mask
.
type
());
maskPyramid
[
level
]
=
masktemp
(
Rect
(
border
,
border
,
sz
.
width
,
sz
.
height
));
}
// Compute the resized image
if
(
level
!=
firstLevel
)
{
if
(
level
<
firstLevel
)
{
resize
(
image
,
imagePyramid
[
level
],
sz
,
scale
,
scale
,
INTER_LINEAR
);
resize
(
image
,
imagePyramid
[
level
],
sz
,
0
,
0
,
INTER_LINEAR
);
if
(
!
mask
.
empty
())
resize
(
mask
,
maskPyramid
[
level
],
sz
,
scale
,
scale
,
INTER_LINEAR
);
copyMakeBorder
(
imagePyramid
[
level
],
temp
,
border
,
border
,
border
,
border
,
BORDER_REFLECT_101
+
BORDER_ISOLATED
);
resize
(
mask
,
maskPyramid
[
level
],
sz
,
0
,
0
,
INTER_LINEAR
);
}
else
{
resize
(
imagePyramid
[
level
-
1
],
imagePyramid
[
level
],
sz
,
1.
/
scaleFactor
,
1.
/
scaleFactor
,
INTER_LINEAR
);
resize
(
imagePyramid
[
level
-
1
],
imagePyramid
[
level
],
sz
,
0
,
0
,
INTER_LINEAR
);
if
(
!
mask
.
empty
())
resize
(
maskPyramid
[
level
-
1
],
maskPyramid
[
level
],
sz
,
1.
/
scaleFactor
,
1.
/
scaleFactor
,
INTER_LINEAR
);
copyMakeBorder
(
imagePyramid
[
level
],
temp
,
border
,
border
,
border
,
border
,
BORDER_REFLECT_101
+
BORDER_ISOLATED
);
{
resize
(
maskPyramid
[
level
-
1
],
maskPyramid
[
level
],
sz
,
0
,
0
,
INTER_LINEAR
);
threshold
(
maskPyramid
[
level
],
maskPyramid
[
level
],
254
,
0
,
THRESH_TOZERO
);
}
}
copyMakeBorder
(
imagePyramid
[
level
],
temp
,
border
,
border
,
border
,
border
,
BORDER_REFLECT_101
+
BORDER_ISOLATED
);
if
(
!
mask
.
empty
())
copyMakeBorder
(
maskPyramid
[
level
],
masktemp
,
border
,
border
,
border
,
border
,
BORDER_CONSTANT
+
BORDER_ISOLATED
);
}
else
{
copyMakeBorder
(
image
,
temp
,
border
,
border
,
border
,
border
,
BORDER_REFLECT_101
);
image
.
copyTo
(
imagePyramid
[
level
]);
if
(
!
mask
.
empty
()
)
mask
.
copyTo
(
maskPyramid
[
level
]);
copyMakeBorder
(
mask
,
masktemp
,
border
,
border
,
border
,
border
,
BORDER_CONSTANT
+
BORDER_ISOLATED
);
}
if
(
!
mask
.
empty
()
)
copyMakeBorder
(
maskPyramid
[
level
],
masktemp
,
border
,
border
,
border
,
border
,
BORDER_CONSTANT
+
BORDER_ISOLATED
);
}
// Pre-compute the keypoints (we keep the best over all scales, so this has to be done beforehand
vector
<
vector
<
KeyPoint
>
>
allKeypoints
;
if
(
do_keypoints
)
...
...
@@ -817,19 +816,19 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
computeKeyPoints
(
imagePyramid
,
maskPyramid
,
allKeypoints
,
nfeatures
,
firstLevel
,
scaleFactor
,
edgeThreshold
,
patchSize
,
scoreType
);
// make sure we have the right number of keypoints keypoints
/*vector<KeyPoint> temp;
for (int level = 0; level < n_levels; ++level)
{
vector<KeyPoint>& keypoints = all_keypoints[level];
temp.insert(temp.end(), keypoints.begin(), keypoints.end());
keypoints.clear();
}
KeyPoint::retainBest(temp, n_features_);
for (vector<KeyPoint>::iterator keypoint = temp.begin(),
keypoint_end = temp.end(); keypoint != keypoint_end; ++keypoint)
all_keypoints[keypoint->octave].push_back(*keypoint);*/
...
...
@@ -838,19 +837,19 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
{
// Remove keypoints very close to the border
KeyPointsFilter
::
runByImageBorder
(
_keypoints
,
image
.
size
(),
edgeThreshold
);
// Cluster the input keypoints depending on the level they were computed at
allKeypoints
.
resize
(
nlevels
);
for
(
vector
<
KeyPoint
>::
iterator
keypoint
=
_keypoints
.
begin
(),
keypointEnd
=
_keypoints
.
end
();
keypoint
!=
keypointEnd
;
++
keypoint
)
allKeypoints
[
keypoint
->
octave
].
push_back
(
*
keypoint
);
// Make sure we rescale the coordinates
for
(
int
level
=
0
;
level
<
nlevels
;
++
level
)
{
if
(
level
==
firstLevel
)
continue
;
vector
<
KeyPoint
>
&
keypoints
=
allKeypoints
[
level
];
float
scale
=
1
/
getScale
(
level
,
firstLevel
,
scaleFactor
);
for
(
vector
<
KeyPoint
>::
iterator
keypoint
=
keypoints
.
begin
(),
...
...
@@ -858,10 +857,10 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
keypoint
->
pt
*=
scale
;
}
}
Mat
descriptors
;
vector
<
Point
>
pattern
;
if
(
do_descriptors
)
{
int
nkeypoints
=
0
;
...
...
@@ -874,19 +873,19 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
_descriptors
.
create
(
nkeypoints
,
descriptorSize
(),
CV_8U
);
descriptors
=
_descriptors
.
getMat
();
}
const
int
npoints
=
512
;
Point
patternbuf
[
npoints
];
const
Point
*
pattern0
=
(
const
Point
*
)
bit_pattern_31_
;
if
(
patchSize
!=
31
)
{
pattern0
=
patternbuf
;
makeRandomPattern
(
patchSize
,
patternbuf
,
npoints
);
}
CV_Assert
(
WTA_K
==
2
||
WTA_K
==
3
||
WTA_K
==
4
);
if
(
WTA_K
==
2
)
std
::
copy
(
pattern0
,
pattern0
+
npoints
,
std
::
back_inserter
(
pattern
));
else
...
...
@@ -895,7 +894,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
initializeOrbPattern
(
pattern0
,
pattern
,
ntuples
,
WTA_K
,
npoints
);
}
}
_keypoints
.
clear
();
int
offset
=
0
;
for
(
int
level
=
0
;
level
<
nlevels
;
++
level
)
...
...
@@ -903,15 +902,15 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
// Get the features and compute their orientation
vector
<
KeyPoint
>&
keypoints
=
allKeypoints
[
level
];
int
nkeypoints
=
(
int
)
keypoints
.
size
();
// Compute the descriptors
if
(
do_descriptors
)
{
Mat
desc
;
if
(
!
descriptors
.
empty
())
if
(
!
descriptors
.
empty
())
{
desc
=
descriptors
.
rowRange
(
offset
,
offset
+
nkeypoints
);
}
}
offset
+=
nkeypoints
;
// preprocess the resized image
...
...
@@ -920,7 +919,7 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
GaussianBlur
(
workingMat
,
workingMat
,
Size
(
7
,
7
),
2
,
2
,
BORDER_REFLECT_101
);
computeDescriptors
(
workingMat
,
keypoints
,
desc
,
pattern
,
descriptorSize
(),
WTA_K
);
}
// Copy to the output data
if
(
level
!=
firstLevel
)
{
...
...
@@ -933,11 +932,11 @@ void ORB::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _ke
_keypoints
.
insert
(
_keypoints
.
end
(),
keypoints
.
begin
(),
keypoints
.
end
());
}
}
void
ORB
::
detectImpl
(
const
Mat
&
image
,
vector
<
KeyPoint
>&
keypoints
,
const
Mat
&
mask
)
const
{
(
*
this
)(
image
,
mask
,
keypoints
,
noArray
(),
false
);
}
}
void
ORB
::
computeImpl
(
const
Mat
&
image
,
vector
<
KeyPoint
>&
keypoints
,
Mat
&
descriptors
)
const
{
...
...
modules/features2d/test/test_features2d.cpp
View file @
9399394e
...
...
@@ -1091,3 +1091,51 @@ TEST( Features2d_DescriptorMatcher_FlannBased, regression )
CV_DescriptorMatcherTest
test
(
"descriptor-matcher-flann-based"
,
new
FlannBasedMatcher
,
0.04
f
);
test
.
safe_run
();
}
TEST
(
Features2D_ORB
,
_1996
)
{
cv
::
Ptr
<
cv
::
FeatureDetector
>
fd
=
cv
::
FeatureDetector
::
create
(
"ORB"
);
cv
::
Ptr
<
cv
::
DescriptorExtractor
>
de
=
cv
::
DescriptorExtractor
::
create
(
"ORB"
);
Mat
image
=
cv
::
imread
(
string
(
cvtest
::
TS
::
ptr
()
->
get_data_path
())
+
"shared/lena.jpg"
);
ASSERT_FALSE
(
image
.
empty
());
Mat
roi
(
image
.
size
(),
CV_8UC1
,
Scalar
(
0
));
Point
poly
[]
=
{
Point
(
100
,
20
),
Point
(
300
,
50
),
Point
(
400
,
200
),
Point
(
10
,
500
)};
fillConvexPoly
(
roi
,
poly
,
int
(
sizeof
(
poly
)
/
sizeof
(
poly
[
0
])),
Scalar
(
255
));
std
::
vector
<
cv
::
KeyPoint
>
keypoints
;
fd
->
detect
(
image
,
keypoints
,
roi
);
cv
::
Mat
descriptors
;
de
->
compute
(
image
,
keypoints
,
descriptors
);
//image.setTo(Scalar(255,255,255), roi);
int
roiViolations
=
0
;
for
(
std
::
vector
<
cv
::
KeyPoint
>::
const_iterator
kp
=
keypoints
.
begin
();
kp
!=
keypoints
.
end
();
++
kp
)
{
int
x
=
cvRound
(
kp
->
pt
.
x
);
int
y
=
cvRound
(
kp
->
pt
.
y
);
ASSERT_LE
(
0
,
x
);
ASSERT_LE
(
0
,
y
);
ASSERT_GT
(
image
.
cols
,
x
);
ASSERT_GT
(
image
.
rows
,
y
);
// if (!roi.at<uchar>(y,x))
// {
// roiViolations++;
// circle(image, kp->pt, 3, Scalar(0,0,255));
// }
}
// if(roiViolations)
// {
// imshow("img", image);
// waitKey();
// }
ASSERT_EQ
(
0
,
roiViolations
);
}
\ No newline at end of file
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