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
7a594354
Commit
7a594354
authored
Apr 04, 2014
by
Ievgen Khvedchenia
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
KAZE and AKAZE integration initial commit
parent
d1710a85
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
7164 additions
and
0 deletions
+7164
-0
AKAZE.cpp
modules/features2d/src/akaze/AKAZE.cpp
+2068
-0
AKAZE.h
modules/features2d/src/akaze/AKAZE.h
+175
-0
config.h
modules/features2d/src/akaze/config.h
+156
-0
fed.h
modules/features2d/src/akaze/fed.h
+26
-0
nldiffusion_functions.cpp
modules/features2d/src/akaze/nldiffusion_functions.cpp
+431
-0
nldiffusion_functions.h
modules/features2d/src/akaze/nldiffusion_functions.h
+41
-0
utils.cpp
modules/features2d/src/akaze/utils.cpp
+196
-0
utils.h
modules/features2d/src/akaze/utils.h
+54
-0
kaze.cpp
modules/features2d/src/kaze.cpp
+0
-0
KAZE.cpp
modules/features2d/src/kaze/KAZE.cpp
+2801
-0
KAZE.h
modules/features2d/src/kaze/KAZE.h
+294
-0
config.h
modules/features2d/src/kaze/config.h
+129
-0
fed.cpp
modules/features2d/src/kaze/fed.cpp
+192
-0
fed.h
modules/features2d/src/kaze/fed.h
+30
-0
nldiffusion_functions.cpp
modules/features2d/src/kaze/nldiffusion_functions.cpp
+386
-0
nldiffusion_functions.h
modules/features2d/src/kaze/nldiffusion_functions.h
+51
-0
utils.cpp
modules/features2d/src/kaze/utils.cpp
+93
-0
utils.h
modules/features2d/src/kaze/utils.h
+41
-0
No files found.
modules/features2d/src/akaze/AKAZE.cpp
0 → 100644
View file @
7a594354
//=============================================================================
//
// AKAZE.cpp
// Authors: Pablo F. Alcantarilla (1), Jesus Nuevo (2)
// Institutions: Georgia Institute of Technology (1)
// TrueVision Solutions (2)
// Date: 15/09/2013
// Email: pablofdezalc@gmail.com
//
// AKAZE Features Copyright 2013, Pablo F. Alcantarilla, Jesus Nuevo
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================
/**
* @file AKAZE.cpp
* @brief Main class for detecting and describing binary features in an
* accelerated nonlinear scale space
* @date Sep 15, 2013
* @author Pablo F. Alcantarilla, Jesus Nuevo
*/
#include "AKAZE.h"
using
namespace
std
;
using
namespace
cv
;
//*******************************************************************************
//*******************************************************************************
/**
* @brief AKAZE constructor with input options
* @param options AKAZE configuration options
* @note This constructor allocates memory for the nonlinear scale space
*/
AKAZE
::
AKAZE
(
const
AKAZEOptions
&
options
)
{
soffset_
=
options
.
soffset
;
factor_size_
=
DEFAULT_FACTOR_SIZE
;
sderivatives_
=
DEFAULT_SIGMA_SMOOTHING_DERIVATIVES
;
omax_
=
options
.
omax
;
nsublevels_
=
options
.
nsublevels
;
dthreshold_
=
options
.
dthreshold
;
descriptor_
=
options
.
descriptor
;
diffusivity_
=
options
.
diffusivity
;
save_scale_space_
=
options
.
save_scale_space
;
verbosity_
=
options
.
verbosity
;
img_width_
=
options
.
img_width
;
img_height_
=
options
.
img_height
;
noctaves_
=
omax_
;
ncycles_
=
0
;
reordering_
=
true
;
descriptor_size_
=
options
.
descriptor_size
;
descriptor_channels_
=
options
.
descriptor_channels
;
descriptor_pattern_size_
=
options
.
descriptor_pattern_size
;
tkcontrast_
=
0.0
;
tscale_
=
0.0
;
tderivatives_
=
0.0
;
tdetector_
=
0.0
;
textrema_
=
0.0
;
tsubpixel_
=
0.0
;
tdescriptor_
=
0.0
;
if
(
descriptor_size_
>
0
&&
descriptor_
>=
MLDB_UPRIGHT
)
{
generateDescriptorSubsample
(
descriptorSamples_
,
descriptorBits_
,
descriptor_size_
,
descriptor_pattern_size_
,
descriptor_channels_
);
}
Allocate_Memory_Evolution
();
}
//*******************************************************************************
//*******************************************************************************
/**
* @brief AKAZE destructor
*/
AKAZE
::~
AKAZE
(
void
)
{
evolution_
.
clear
();
}
//*******************************************************************************
//*******************************************************************************
/**
* @brief This method allocates the memory for the nonlinear diffusion evolution
*/
void
AKAZE
::
Allocate_Memory_Evolution
(
void
)
{
float
rfactor
=
0.0
;
int
level_height
=
0
,
level_width
=
0
;
// Allocate the dimension of the matrices for the evolution
for
(
int
i
=
0
;
i
<=
omax_
-
1
&&
i
<=
DEFAULT_OCTAVE_MAX
;
i
++
)
{
rfactor
=
1.0
/
pow
(
2.
f
,
i
);
level_height
=
(
int
)(
img_height_
*
rfactor
);
level_width
=
(
int
)(
img_width_
*
rfactor
);
// Smallest possible octave
if
(
level_width
<
80
||
level_height
<
40
)
{
noctaves_
=
i
;
i
=
omax_
;
break
;
}
for
(
int
j
=
0
;
j
<
nsublevels_
;
j
++
)
{
tevolution
aux
;
aux
.
Lx
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
Ly
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
Lxx
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
Lxy
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
Lyy
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
Lt
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
Ldet
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
Lflow
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
Lstep
=
cv
::
Mat
::
zeros
(
level_height
,
level_width
,
CV_32F
);
aux
.
esigma
=
soffset_
*
pow
(
2.
f
,(
float
)(
j
)
/
(
float
)(
nsublevels_
)
+
i
);
aux
.
sigma_size
=
fRound
(
aux
.
esigma
);
aux
.
etime
=
0.5
*
(
aux
.
esigma
*
aux
.
esigma
);
aux
.
octave
=
i
;
aux
.
sublevel
=
j
;
evolution_
.
push_back
(
aux
);
}
}
// Allocate memory for the number of cycles and time steps
for
(
size_t
i
=
1
;
i
<
evolution_
.
size
();
i
++
)
{
int
naux
=
0
;
std
::
vector
<
float
>
tau
;
float
ttime
=
0.0
;
ttime
=
evolution_
[
i
].
etime
-
evolution_
[
i
-
1
].
etime
;
naux
=
fed_tau_by_process_time
(
ttime
,
1
,
0.25
,
reordering_
,
tau
);
nsteps_
.
push_back
(
naux
);
tsteps_
.
push_back
(
tau
);
ncycles_
++
;
}
}
//*******************************************************************************
//*******************************************************************************
/**
* @brief This method creates the nonlinear scale space for a given image
* @param img Input image for which the nonlinear scale space needs to be created
* @return 0 if the nonlinear scale space was created successfully, -1 otherwise
*/
int
AKAZE
::
Create_Nonlinear_Scale_Space
(
const
cv
::
Mat
&
img
)
{
double
t1
=
0.0
,
t2
=
0.0
;
if
(
evolution_
.
size
()
==
0
)
{
cout
<<
"Error generating the nonlinear scale space!!"
<<
endl
;
cout
<<
"Firstly you need to call AKAZE::Allocate_Memory_Evolution()"
<<
endl
;
return
-
1
;
}
t1
=
getTickCount
();
// Copy the original image to the first level of the evolution
img
.
copyTo
(
evolution_
[
0
].
Lt
);
gaussian_2D_convolution
(
evolution_
[
0
].
Lt
,
evolution_
[
0
].
Lt
,
0
,
0
,
soffset_
);
evolution_
[
0
].
Lt
.
copyTo
(
evolution_
[
0
].
Lsmooth
);
// Firstly compute the kcontrast factor
kcontrast_
=
compute_k_percentile
(
img
,
KCONTRAST_PERCENTILE
,
1.0
,
KCONTRAST_NBINS
,
0
,
0
);
t2
=
getTickCount
();
tkcontrast_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
// Now generate the rest of evolution levels
for
(
size_t
i
=
1
;
i
<
evolution_
.
size
();
i
++
)
{
if
(
evolution_
[
i
].
octave
>
evolution_
[
i
-
1
].
octave
)
{
halfsample_image
(
evolution_
[
i
-
1
].
Lt
,
evolution_
[
i
].
Lt
);
kcontrast_
=
kcontrast_
*
0.75
;
}
else
{
evolution_
[
i
-
1
].
Lt
.
copyTo
(
evolution_
[
i
].
Lt
);
}
gaussian_2D_convolution
(
evolution_
[
i
].
Lt
,
evolution_
[
i
].
Lsmooth
,
0
,
0
,
1.0
);
// Compute the Gaussian derivatives Lx and Ly
image_derivatives_scharr
(
evolution_
[
i
].
Lsmooth
,
evolution_
[
i
].
Lx
,
1
,
0
);
image_derivatives_scharr
(
evolution_
[
i
].
Lsmooth
,
evolution_
[
i
].
Ly
,
0
,
1
);
// Compute the conductivity equation
switch
(
diffusivity_
)
{
case
0
:
pm_g1
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lflow
,
kcontrast_
);
break
;
case
1
:
pm_g2
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lflow
,
kcontrast_
);
break
;
case
2
:
weickert_diffusivity
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lflow
,
kcontrast_
);
break
;
case
3
:
charbonnier_diffusivity
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lflow
,
kcontrast_
);
break
;
default
:
std
::
cerr
<<
"Diffusivity: "
<<
diffusivity_
<<
" is not supported"
<<
std
::
endl
;
}
// Perform FED n inner steps
for
(
int
j
=
0
;
j
<
nsteps_
[
i
-
1
];
j
++
)
{
nld_step_scalar
(
evolution_
[
i
].
Lt
,
evolution_
[
i
].
Lflow
,
evolution_
[
i
].
Lstep
,
tsteps_
[
i
-
1
][
j
]);
}
}
t2
=
getTickCount
();
tscale_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
return
0
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method selects interesting keypoints through the nonlinear scale space
* @param kpts Vector of detected keypoints
*/
void
AKAZE
::
Feature_Detection
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
)
{
double
t1
=
0.0
,
t2
=
0.0
;
t1
=
getTickCount
();
Compute_Determinant_Hessian_Response
();
Find_Scale_Space_Extrema
(
kpts
);
Do_Subpixel_Refinement
(
kpts
);
t2
=
getTickCount
();
tdetector_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the multiscale derivatives for the nonlinear scale space
*/
void
AKAZE
::
Compute_Multiscale_Derivatives
(
void
)
{
double
t1
=
0.0
,
t2
=
0.0
;
t1
=
getTickCount
();
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
evolution_
.
size
();
i
++
)
{
float
ratio
=
pow
(
2.
f
,
evolution_
[
i
].
octave
);
int
sigma_size_
=
fRound
(
evolution_
[
i
].
esigma
*
factor_size_
/
ratio
);
compute_scharr_derivatives
(
evolution_
[
i
].
Lsmooth
,
evolution_
[
i
].
Lx
,
1
,
0
,
sigma_size_
);
compute_scharr_derivatives
(
evolution_
[
i
].
Lsmooth
,
evolution_
[
i
].
Ly
,
0
,
1
,
sigma_size_
);
compute_scharr_derivatives
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Lxx
,
1
,
0
,
sigma_size_
);
compute_scharr_derivatives
(
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lyy
,
0
,
1
,
sigma_size_
);
compute_scharr_derivatives
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Lxy
,
0
,
1
,
sigma_size_
);
evolution_
[
i
].
Lx
=
evolution_
[
i
].
Lx
*
((
sigma_size_
));
evolution_
[
i
].
Ly
=
evolution_
[
i
].
Ly
*
((
sigma_size_
));
evolution_
[
i
].
Lxx
=
evolution_
[
i
].
Lxx
*
((
sigma_size_
)
*
(
sigma_size_
));
evolution_
[
i
].
Lxy
=
evolution_
[
i
].
Lxy
*
((
sigma_size_
)
*
(
sigma_size_
));
evolution_
[
i
].
Lyy
=
evolution_
[
i
].
Lyy
*
((
sigma_size_
)
*
(
sigma_size_
));
}
t2
=
getTickCount
();
tderivatives_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the feature detector response for the nonlinear scale space
* @note We use the Hessian determinant as the feature detector response
*/
void
AKAZE
::
Compute_Determinant_Hessian_Response
(
void
)
{
// Firstly compute the multiscale derivatives
Compute_Multiscale_Derivatives
();
for
(
size_t
i
=
0
;
i
<
evolution_
.
size
();
i
++
)
{
if
(
verbosity_
==
true
)
{
cout
<<
"Computing detector response. Determinant of Hessian. Evolution time: "
<<
evolution_
[
i
].
etime
<<
endl
;
}
for
(
int
ix
=
0
;
ix
<
evolution_
[
i
].
Ldet
.
rows
;
ix
++
)
{
for
(
int
jx
=
0
;
jx
<
evolution_
[
i
].
Ldet
.
cols
;
jx
++
)
{
float
lxx
=
*
(
evolution_
[
i
].
Lxx
.
ptr
<
float
>
(
ix
)
+
jx
);
float
lxy
=
*
(
evolution_
[
i
].
Lxy
.
ptr
<
float
>
(
ix
)
+
jx
);
float
lyy
=
*
(
evolution_
[
i
].
Lyy
.
ptr
<
float
>
(
ix
)
+
jx
);
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
)
+
jx
)
=
(
lxx
*
lyy
-
lxy
*
lxy
);
}
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method finds extrema in the nonlinear scale space
* @param kpts Vector of detected keypoints
*/
void
AKAZE
::
Find_Scale_Space_Extrema
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
)
{
double
t1
=
0.0
,
t2
=
0.0
;
float
value
=
0.0
;
float
dist
=
0.0
,
ratio
=
0.0
,
smax
=
0.0
;
int
npoints
=
0
,
id_repeated
=
0
;
int
sigma_size_
=
0
,
left_x
=
0
,
right_x
=
0
,
up_y
=
0
,
down_y
=
0
;
bool
is_extremum
=
false
,
is_repeated
=
false
,
is_out
=
false
;
cv
::
KeyPoint
point
;
// Set maximum size
if
(
descriptor_
==
SURF_UPRIGHT
||
descriptor_
==
SURF
||
descriptor_
==
MLDB_UPRIGHT
||
descriptor_
==
MLDB
)
{
smax
=
10.0
*
sqrtf
(
2.0
);
}
else
if
(
descriptor_
==
MSURF_UPRIGHT
||
descriptor_
==
MSURF
)
{
smax
=
12.0
*
sqrtf
(
2.0
);
}
t1
=
getTickCount
();
for
(
size_t
i
=
0
;
i
<
evolution_
.
size
();
i
++
)
{
for
(
int
ix
=
1
;
ix
<
evolution_
[
i
].
Ldet
.
rows
-
1
;
ix
++
)
{
for
(
int
jx
=
1
;
jx
<
evolution_
[
i
].
Ldet
.
cols
-
1
;
jx
++
)
{
is_extremum
=
false
;
is_repeated
=
false
;
is_out
=
false
;
value
=
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
)
+
jx
);
// Filter the points with the detector threshold
if
(
value
>
dthreshold_
&&
value
>=
DEFAULT_MIN_DETECTOR_THRESHOLD
&&
value
>
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
)
+
jx
-
1
)
&&
value
>
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
)
+
jx
+
1
)
&&
value
>
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
-
1
)
+
jx
-
1
)
&&
value
>
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
-
1
)
+
jx
)
&&
value
>
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
-
1
)
+
jx
+
1
)
&&
value
>
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
+
1
)
+
jx
-
1
)
&&
value
>
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
+
1
)
+
jx
)
&&
value
>
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
+
1
)
+
jx
+
1
))
{
is_extremum
=
true
;
point
.
response
=
fabs
(
value
);
point
.
size
=
evolution_
[
i
].
esigma
*
factor_size_
;
point
.
octave
=
evolution_
[
i
].
octave
;
point
.
class_id
=
i
;
ratio
=
pow
(
2.
f
,
point
.
octave
);
sigma_size_
=
fRound
(
point
.
size
/
ratio
);
point
.
pt
.
x
=
jx
;
point
.
pt
.
y
=
ix
;
for
(
size_t
ik
=
0
;
ik
<
kpts
.
size
();
ik
++
)
{
if
(
point
.
class_id
==
kpts
[
ik
].
class_id
-
1
||
point
.
class_id
==
kpts
[
ik
].
class_id
||
point
.
class_id
==
kpts
[
ik
].
class_id
+
1
)
{
dist
=
sqrt
(
pow
(
point
.
pt
.
x
*
ratio
-
kpts
[
ik
].
pt
.
x
,
2
)
+
pow
(
point
.
pt
.
y
*
ratio
-
kpts
[
ik
].
pt
.
y
,
2
));
if
(
dist
<=
point
.
size
)
{
if
(
point
.
response
>
kpts
[
ik
].
response
)
{
id_repeated
=
ik
;
is_repeated
=
true
;
}
else
{
is_extremum
=
false
;
}
break
;
}
}
}
// Check out of bounds
if
(
is_extremum
==
true
)
{
// Check that the point is under the image limits for the descriptor computation
left_x
=
fRound
(
point
.
pt
.
x
-
smax
*
sigma_size_
)
-
1
;
right_x
=
fRound
(
point
.
pt
.
x
+
smax
*
sigma_size_
)
+
1
;
up_y
=
fRound
(
point
.
pt
.
y
-
smax
*
sigma_size_
)
-
1
;
down_y
=
fRound
(
point
.
pt
.
y
+
smax
*
sigma_size_
)
+
1
;
if
(
left_x
<
0
||
right_x
>=
evolution_
[
i
].
Ldet
.
cols
||
up_y
<
0
||
down_y
>=
evolution_
[
i
].
Ldet
.
rows
)
{
is_out
=
true
;
}
if
(
is_out
==
false
)
{
if
(
is_repeated
==
false
)
{
point
.
pt
.
x
*=
ratio
;
point
.
pt
.
y
*=
ratio
;
kpts
.
push_back
(
point
);
npoints
++
;
}
else
{
point
.
pt
.
x
*=
ratio
;
point
.
pt
.
y
*=
ratio
;
kpts
[
id_repeated
]
=
point
;
}
}
// if is_out
}
//if is_extremum
}
}
// for jx
}
// for ix
}
// for i
t2
=
getTickCount
();
textrema_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method performs subpixel refinement of the detected keypoints
* @param kpts Vector of detected keypoints
*/
void
AKAZE
::
Do_Subpixel_Refinement
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
)
{
double
t1
=
0.0
,
t2
=
0.0
;
float
Dx
=
0.0
,
Dy
=
0.0
,
ratio
=
0.0
;
float
Dxx
=
0.0
,
Dyy
=
0.0
,
Dxy
=
0.0
;
int
x
=
0
,
y
=
0
;
Mat
A
=
Mat
::
zeros
(
2
,
2
,
CV_32F
);
Mat
b
=
Mat
::
zeros
(
2
,
1
,
CV_32F
);
Mat
dst
=
Mat
::
zeros
(
2
,
1
,
CV_32F
);
t1
=
getTickCount
();
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
ratio
=
pow
(
2.
f
,
kpts
[
i
].
octave
);
x
=
fRound
(
kpts
[
i
].
pt
.
x
/
ratio
);
y
=
fRound
(
kpts
[
i
].
pt
.
y
/
ratio
);
// Compute the gradient
Dx
=
(
0.5
)
*
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
+
1
)
-*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
-
1
));
Dy
=
(
0.5
)
*
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
+
1
)
+
x
)
-*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
-
1
)
+
x
));
// Compute the Hessian
Dxx
=
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
+
1
)
+
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
-
1
)
-
2.0
*
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
)));
Dyy
=
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
+
1
)
+
x
)
+
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
-
1
)
+
x
)
-
2.0
*
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
)));
Dxy
=
(
0.25
)
*
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
+
1
)
+
x
+
1
)
+
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
-
1
)
+
x
-
1
)))
-
(
0.25
)
*
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
-
1
)
+
x
+
1
)
+
(
*
(
evolution_
[
kpts
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
+
1
)
+
x
-
1
)));
// Solve the linear system
*
(
A
.
ptr
<
float
>
(
0
))
=
Dxx
;
*
(
A
.
ptr
<
float
>
(
1
)
+
1
)
=
Dyy
;
*
(
A
.
ptr
<
float
>
(
0
)
+
1
)
=
*
(
A
.
ptr
<
float
>
(
1
))
=
Dxy
;
*
(
b
.
ptr
<
float
>
(
0
))
=
-
Dx
;
*
(
b
.
ptr
<
float
>
(
1
))
=
-
Dy
;
solve
(
A
,
b
,
dst
,
DECOMP_LU
);
if
(
fabs
(
*
(
dst
.
ptr
<
float
>
(
0
)))
<=
1.0
&&
fabs
(
*
(
dst
.
ptr
<
float
>
(
1
)))
<=
1.0
)
{
kpts
[
i
].
pt
.
x
=
x
+
(
*
(
dst
.
ptr
<
float
>
(
0
)));
kpts
[
i
].
pt
.
y
=
y
+
(
*
(
dst
.
ptr
<
float
>
(
1
)));
kpts
[
i
].
pt
.
x
*=
powf
(
2.
f
,
evolution_
[
kpts
[
i
].
class_id
].
octave
);
kpts
[
i
].
pt
.
y
*=
powf
(
2.
f
,
evolution_
[
kpts
[
i
].
class_id
].
octave
);
kpts
[
i
].
angle
=
0.0
;
// In OpenCV the size of a keypoint its the diameter
kpts
[
i
].
size
*=
2.0
;
}
// Delete the point since its not stable
else
{
kpts
.
erase
(
kpts
.
begin
()
+
i
);
i
--
;
}
}
t2
=
getTickCount
();
tsubpixel_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method performs feature suppression based on 2D distance
* @param kpts Vector of keypoints
* @param mdist Maximum distance in pixels
*/
void
AKAZE
::
Feature_Suppression_Distance
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
,
float
mdist
)
{
vector
<
KeyPoint
>
aux
;
vector
<
int
>
to_delete
;
float
dist
=
0.0
,
x1
=
0.0
,
y1
=
0.0
,
x2
=
0.0
,
y2
=
0.0
;
bool
found
=
false
;
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
x1
=
kpts
[
i
].
pt
.
x
;
y1
=
kpts
[
i
].
pt
.
y
;
for
(
size_t
j
=
i
+
1
;
j
<
kpts
.
size
();
j
++
)
{
x2
=
kpts
[
j
].
pt
.
x
;
y2
=
kpts
[
j
].
pt
.
y
;
dist
=
sqrt
(
pow
(
x1
-
x2
,
2
)
+
pow
(
y1
-
y2
,
2
));
if
(
dist
<
mdist
)
{
if
(
fabs
(
kpts
[
i
].
response
)
>=
fabs
(
kpts
[
j
].
response
))
{
to_delete
.
push_back
(
j
);
}
else
{
to_delete
.
push_back
(
i
);
break
;
}
}
}
}
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
found
=
false
;
for
(
size_t
j
=
0
;
j
<
to_delete
.
size
();
j
++
)
{
if
(
i
==
(
size_t
)(
to_delete
[
j
]))
{
found
=
true
;
break
;
}
}
if
(
found
==
false
)
{
aux
.
push_back
(
kpts
[
i
]);
}
}
kpts
.
clear
();
kpts
=
aux
;
aux
.
clear
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the set of descriptors through the nonlinear scale space
* @param kpts Vector of detected keypoints
* @param desc Matrix to store the descriptors
*/
void
AKAZE
::
Compute_Descriptors
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
,
cv
::
Mat
&
desc
)
{
double
t1
=
0.0
,
t2
=
0.0
;
t1
=
getTickCount
();
// Allocate memory for the matrix with the descriptors
if
(
descriptor_
<
MLDB_UPRIGHT
)
{
desc
=
cv
::
Mat
::
zeros
(
kpts
.
size
(),
64
,
CV_32FC1
);
}
else
{
// We use the full length binary descriptor -> 486 bits
if
(
descriptor_size_
==
0
)
{
int
t
=
(
6
+
36
+
120
)
*
descriptor_channels_
;
desc
=
cv
::
Mat
::
zeros
(
kpts
.
size
(),
ceil
(
t
/
8.
),
CV_8UC1
);
}
else
{
// We use the random bit selection length binary descriptor
desc
=
cv
::
Mat
::
zeros
(
kpts
.
size
(),
ceil
(
descriptor_size_
/
8.
),
CV_8UC1
);
}
}
switch
(
descriptor_
)
{
case
SURF_UPRIGHT
:
// Upright descriptors, not invariant to rotation
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Get_SURF_Descriptor_Upright_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
break
;
case
SURF
:
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
Get_SURF_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
break
;
case
MSURF_UPRIGHT
:
// Upright descriptors, not invariant to rotation
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Get_MSURF_Upright_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
break
;
case
MSURF
:
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
Get_MSURF_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
break
;
case
MLDB_UPRIGHT
:
// Upright descriptors, not invariant to rotation
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
if
(
descriptor_size_
==
0
)
Get_Upright_MLDB_Full_Descriptor
(
kpts
[
i
],
desc
.
ptr
<
unsigned
char
>
(
i
));
else
Get_Upright_MLDB_Descriptor_Subset
(
kpts
[
i
],
desc
.
ptr
<
unsigned
char
>
(
i
));
}
}
break
;
case
MLDB
:
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
if
(
descriptor_size_
==
0
)
Get_MLDB_Full_Descriptor
(
kpts
[
i
],
desc
.
ptr
<
unsigned
char
>
(
i
));
else
Get_MLDB_Descriptor_Subset
(
kpts
[
i
],
desc
.
ptr
<
unsigned
char
>
(
i
));
}
}
break
;
}
t2
=
getTickCount
();
tdescriptor_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the main orientation for a given keypoint
* @param kpt Input keypoint
* @note The orientation is computed using a similar approach as described in the
* original SURF method. See Bay et al., Speeded Up Robust Features, ECCV 2006
*/
void
AKAZE
::
Compute_Main_Orientation_SURF
(
cv
::
KeyPoint
&
kpt
)
{
int
ix
=
0
,
iy
=
0
,
idx
=
0
,
s
=
0
,
level
=
0
;
float
xf
=
0.0
,
yf
=
0.0
,
gweight
=
0.0
,
ratio
=
0.0
;
std
::
vector
<
float
>
resX
(
109
),
resY
(
109
),
Ang
(
109
);
const
int
id
[]
=
{
6
,
5
,
4
,
3
,
2
,
1
,
0
,
1
,
2
,
3
,
4
,
5
,
6
};
// Variables for computing the dominant direction
float
sumX
=
0.0
,
sumY
=
0.0
,
max
=
0.0
,
ang1
=
0.0
,
ang2
=
0.0
;
// Get the information from the keypoint
level
=
kpt
.
class_id
;
ratio
=
(
float
)(
1
<<
evolution_
[
level
].
octave
);
s
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
xf
=
kpt
.
pt
.
x
/
ratio
;
yf
=
kpt
.
pt
.
y
/
ratio
;
// Calculate derivatives responses for points within radius of 6*scale
for
(
int
i
=
-
6
;
i
<=
6
;
++
i
)
{
for
(
int
j
=
-
6
;
j
<=
6
;
++
j
)
{
if
(
i
*
i
+
j
*
j
<
36
)
{
iy
=
fRound
(
yf
+
j
*
s
);
ix
=
fRound
(
xf
+
i
*
s
);
gweight
=
gauss25
[
id
[
i
+
6
]][
id
[
j
+
6
]];
resX
[
idx
]
=
gweight
*
(
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
iy
)
+
ix
));
resY
[
idx
]
=
gweight
*
(
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
iy
)
+
ix
));
Ang
[
idx
]
=
get_angle
(
resX
[
idx
],
resY
[
idx
]);
++
idx
;
}
}
}
// Loop slides pi/3 window around feature point
for
(
ang1
=
0
;
ang1
<
2.0
*
CV_PI
;
ang1
+=
0.15
f
)
{
ang2
=
(
ang1
+
CV_PI
/
3.0
f
>
2.0
*
CV_PI
?
ang1
-
5.0
f
*
CV_PI
/
3.0
f
:
ang1
+
CV_PI
/
3.0
f
);
sumX
=
sumY
=
0.
f
;
for
(
size_t
k
=
0
;
k
<
Ang
.
size
();
++
k
)
{
// Get angle from the x-axis of the sample point
const
float
&
ang
=
Ang
[
k
];
// Determine whether the point is within the window
if
(
ang1
<
ang2
&&
ang1
<
ang
&&
ang
<
ang2
)
{
sumX
+=
resX
[
k
];
sumY
+=
resY
[
k
];
}
else
if
(
ang2
<
ang1
&&
((
ang
>
0
&&
ang
<
ang2
)
||
(
ang
>
ang1
&&
ang
<
2.0
*
CV_PI
)
))
{
sumX
+=
resX
[
k
];
sumY
+=
resY
[
k
];
}
}
// if the vector produced from this window is longer than all
// previous vectors then this forms the new dominant direction
if
(
sumX
*
sumX
+
sumY
*
sumY
>
max
)
{
// store largest orientation
max
=
sumX
*
sumX
+
sumY
*
sumY
;
kpt
.
angle
=
get_angle
(
sumX
,
sumY
);
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the upright descriptor of the provided keypoint
* @param kpt Input keypoint
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional
* Gaussian weighting is performed. The descriptor is inspired from Bay et al.,
* Speeded Up Robust Features, ECCV, 2006
*/
void
AKAZE
::
Get_SURF_Descriptor_Upright_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
ratio
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
scale
=
0
,
dsize
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
ratio
=
(
float
)(
1
<<
kpt
.
octave
);
scale
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
level
=
kpt
.
class_id
;
yf
=
kpt
.
pt
.
y
/
ratio
;
xf
=
kpt
.
pt
.
x
/
ratio
;
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point on the rotated axis
sample_y
=
yf
+
l
*
scale
;
sample_x
=
xf
+
k
*
scale
;
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Sum the derivatives to the cumulative descriptor
dx
+=
rx
;
dy
+=
ry
;
mdx
+=
fabs
(
rx
);
mdy
+=
fabs
(
ry
);
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dx
;
desc
[
dcount
++
]
=
dy
;
desc
[
dcount
++
]
=
mdx
;
desc
[
dcount
++
]
=
mdy
;
// Store the current length^2 of the vector
len
+=
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the descriptor of the provided keypoint given the
* main orientation
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional
* Gaussian weighting is performed. The descriptor is inspired from Bay et al.,
* Speeded Up Robust Features, ECCV, 2006
*/
void
AKAZE
::
Get_SURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rrx
=
0.0
,
rry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
ratio
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
scale
=
0
,
dsize
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
ratio
=
(
float
)(
1
<<
kpt
.
octave
);
scale
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
yf
=
kpt
.
pt
.
y
/
ratio
;
xf
=
kpt
.
pt
.
x
/
ratio
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point on the rotated axis
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Get the x and y derivatives on the rotated axis
rry
=
rx
*
co
+
ry
*
si
;
rrx
=
-
rx
*
si
+
ry
*
co
;
// Sum the derivatives to the cumulative descriptor
dx
+=
rrx
;
dy
+=
rry
;
mdx
+=
fabs
(
rrx
);
mdy
+=
fabs
(
rry
);
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dx
;
desc
[
dcount
++
]
=
dy
;
desc
[
dcount
++
]
=
mdx
;
desc
[
dcount
++
]
=
mdy
;
// Store the current length^2 of the vector
len
+=
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the upright descriptor (not rotation invariant) of
* the provided keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 24 s x 24 s. Descriptor Length 64. The descriptor is inspired
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
* ECCV 2008
*/
void
AKAZE
::
Get_MSURF_Upright_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
,
gauss_s1
=
0.0
,
gauss_s2
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
ys
=
0.0
,
xs
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
;
int
x1
=
0
,
y1
=
0
,
sample_step
=
0
,
pattern_size
=
0
;
int
x2
=
0
,
y2
=
0
,
kx
=
0
,
ky
=
0
,
i
=
0
,
j
=
0
,
dcount
=
0
;
float
fx
=
0.0
,
fy
=
0.0
,
ratio
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
int
scale
=
0
,
dsize
=
0
,
level
=
0
;
// Subregion centers for the 4x4 gaussian weighting
float
cx
=
-
0.5
,
cy
=
0.5
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
12
;
// Get the information from the keypoint
ratio
=
(
float
)(
1
<<
kpt
.
octave
);
scale
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
level
=
kpt
.
class_id
;
yf
=
kpt
.
pt
.
y
/
ratio
;
xf
=
kpt
.
pt
.
x
/
ratio
;
i
=
-
8
;
// Calculate descriptor for this interest point
// Area of size 24 s x 24 s
while
(
i
<
pattern_size
)
{
j
=
-
8
;
i
=
i
-
4
;
cx
+=
1.0
;
cy
=
-
0.5
;
while
(
j
<
pattern_size
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
cy
+=
1.0
;
j
=
j
-
4
;
ky
=
i
+
sample_step
;
kx
=
j
+
sample_step
;
ys
=
yf
+
(
ky
*
scale
);
xs
=
xf
+
(
kx
*
scale
);
for
(
int
k
=
i
;
k
<
i
+
9
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
9
;
l
++
)
{
sample_y
=
k
*
scale
+
yf
;
sample_x
=
l
*
scale
+
xf
;
//Get the gaussian weighted x and y responses
gauss_s1
=
gaussian
(
xs
-
sample_x
,
ys
-
sample_y
,
2.50
*
scale
);
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
rx
=
gauss_s1
*
rx
;
ry
=
gauss_s1
*
ry
;
// Sum the derivatives to the cumulative descriptor
dx
+=
rx
;
dy
+=
ry
;
mdx
+=
fabs
(
rx
);
mdy
+=
fabs
(
ry
);
}
}
// Add the values to the descriptor vector
gauss_s2
=
gaussian
(
cx
-
2.0
f
,
cy
-
2.0
f
,
1.5
f
);
desc
[
dcount
++
]
=
dx
*
gauss_s2
;
desc
[
dcount
++
]
=
dy
*
gauss_s2
;
desc
[
dcount
++
]
=
mdx
*
gauss_s2
;
desc
[
dcount
++
]
=
mdy
*
gauss_s2
;
len
+=
(
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
)
*
gauss_s2
*
gauss_s2
;
j
+=
9
;
}
i
+=
9
;
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the descriptor of the provided keypoint given the
* main orientation of the keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 24 s x 24 s. Descriptor Length 64. The descriptor is inspired
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
* ECCV 2008
*/
void
AKAZE
::
Get_MSURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
,
gauss_s1
=
0.0
,
gauss_s2
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rrx
=
0.0
,
rry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
ys
=
0.0
,
xs
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
ratio
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
;
int
kx
=
0
,
ky
=
0
,
i
=
0
,
j
=
0
,
dcount
=
0
;
int
scale
=
0
,
dsize
=
0
,
level
=
0
;
// Subregion centers for the 4x4 gaussian weighting
float
cx
=
-
0.5
,
cy
=
0.5
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
12
;
// Get the information from the keypoint
ratio
=
(
float
)(
1
<<
kpt
.
octave
);
scale
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
yf
=
kpt
.
pt
.
y
/
ratio
;
xf
=
kpt
.
pt
.
x
/
ratio
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
i
=
-
8
;
// Calculate descriptor for this interest point
// Area of size 24 s x 24 s
while
(
i
<
pattern_size
)
{
j
=
-
8
;
i
=
i
-
4
;
cx
+=
1.0
;
cy
=
-
0.5
;
while
(
j
<
pattern_size
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
cy
+=
1.0
;
j
=
j
-
4
;
ky
=
i
+
sample_step
;
kx
=
j
+
sample_step
;
xs
=
xf
+
(
-
kx
*
scale
*
si
+
ky
*
scale
*
co
);
ys
=
yf
+
(
kx
*
scale
*
co
+
ky
*
scale
*
si
);
for
(
int
k
=
i
;
k
<
i
+
9
;
++
k
)
{
for
(
int
l
=
j
;
l
<
j
+
9
;
++
l
)
{
// Get coords of sample point on the rotated axis
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
// Get the gaussian weighted x and y responses
gauss_s1
=
gaussian
(
xs
-
sample_x
,
ys
-
sample_y
,
2.5
*
scale
);
y1
=
fRound
(
sample_y
-
.5
);
x1
=
fRound
(
sample_x
-
.5
);
y2
=
fRound
(
sample_y
+
.5
);
x2
=
fRound
(
sample_x
+
.5
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Get the x and y derivatives on the rotated axis
rry
=
gauss_s1
*
(
rx
*
co
+
ry
*
si
);
rrx
=
gauss_s1
*
(
-
rx
*
si
+
ry
*
co
);
// Sum the derivatives to the cumulative descriptor
dx
+=
rrx
;
dy
+=
rry
;
mdx
+=
fabs
(
rrx
);
mdy
+=
fabs
(
rry
);
}
}
// Add the values to the descriptor vector
gauss_s2
=
gaussian
(
cx
-
2.0
f
,
cy
-
2.0
f
,
1.5
f
);
desc
[
dcount
++
]
=
dx
*
gauss_s2
;
desc
[
dcount
++
]
=
dy
*
gauss_s2
;
desc
[
dcount
++
]
=
mdx
*
gauss_s2
;
desc
[
dcount
++
]
=
mdy
*
gauss_s2
;
len
+=
(
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
)
*
gauss_s2
*
gauss_s2
;
j
+=
9
;
}
i
+=
9
;
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the rupright descriptor (not rotation invariant) of
* the provided keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
*/
void
AKAZE
::
Get_Upright_MLDB_Full_Descriptor
(
const
cv
::
KeyPoint
&
kpt
,
unsigned
char
*
desc
)
{
float
di
=
0.0
,
dx
=
0.0
,
dy
=
0.0
;
float
ri
=
0.0
,
rx
=
0.0
,
ry
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
ratio
=
0.0
;
int
x1
=
0
,
y1
=
0
,
sample_step
=
0
,
pattern_size
=
0
;
int
level
=
0
,
nsamples
=
0
,
scale
=
0
;
int
dcount1
=
0
,
dcount2
=
0
;
// Matrices for the M-LDB descriptor
Mat
values_1
=
Mat
::
zeros
(
4
,
descriptor_channels_
,
CV_32FC1
);
Mat
values_2
=
Mat
::
zeros
(
9
,
descriptor_channels_
,
CV_32FC1
);
Mat
values_3
=
Mat
::
zeros
(
16
,
descriptor_channels_
,
CV_32FC1
);
// Get the information from the keypoint
ratio
=
(
float
)(
1
<<
kpt
.
octave
);
scale
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
level
=
kpt
.
class_id
;
yf
=
kpt
.
pt
.
y
/
ratio
;
xf
=
kpt
.
pt
.
x
/
ratio
;
// First 2x2 grid
pattern_size
=
descriptor_pattern_size_
;
sample_step
=
pattern_size
;
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
di
=
dx
=
dy
=
0.0
;
nsamples
=
0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point
sample_y
=
yf
+
l
*
scale
;
sample_x
=
xf
+
k
*
scale
;
y1
=
fRound
(
sample_y
);
x1
=
fRound
(
sample_x
);
ri
=
*
(
evolution_
[
level
].
Lt
.
ptr
<
float
>
(
y1
)
+
x1
);
rx
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
ry
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
di
+=
ri
;
dx
+=
rx
;
dy
+=
ry
;
nsamples
++
;
}
}
di
/=
nsamples
;
dx
/=
nsamples
;
dy
/=
nsamples
;
*
(
values_1
.
ptr
<
float
>
(
dcount2
))
=
di
;
*
(
values_1
.
ptr
<
float
>
(
dcount2
)
+
1
)
=
dx
;
*
(
values_1
.
ptr
<
float
>
(
dcount2
)
+
2
)
=
dy
;
dcount2
++
;
}
}
// Do binary comparison first level
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
4
;
j
++
)
{
if
(
*
(
values_1
.
ptr
<
float
>
(
i
))
>
*
(
values_1
.
ptr
<
float
>
(
j
)))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
if
(
*
(
values_1
.
ptr
<
float
>
(
i
)
+
1
)
>
*
(
values_1
.
ptr
<
float
>
(
j
)
+
1
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
if
(
*
(
values_1
.
ptr
<
float
>
(
i
)
+
2
)
>
*
(
values_1
.
ptr
<
float
>
(
j
)
+
2
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
// Second 3x3 grid
sample_step
=
ceil
(
pattern_size
*
2.
/
3.
);
dcount2
=
0
;
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
di
=
dx
=
dy
=
0.0
;
nsamples
=
0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point
sample_y
=
yf
+
l
*
scale
;
sample_x
=
xf
+
k
*
scale
;
y1
=
fRound
(
sample_y
);
x1
=
fRound
(
sample_x
);
ri
=
*
(
evolution_
[
level
].
Lt
.
ptr
<
float
>
(
y1
)
+
x1
);
rx
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
ry
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
di
+=
ri
;
dx
+=
rx
;
dy
+=
ry
;
nsamples
++
;
}
}
di
/=
nsamples
;
dx
/=
nsamples
;
dy
/=
nsamples
;
*
(
values_2
.
ptr
<
float
>
(
dcount2
))
=
di
;
*
(
values_2
.
ptr
<
float
>
(
dcount2
)
+
1
)
=
dx
;
*
(
values_2
.
ptr
<
float
>
(
dcount2
)
+
2
)
=
dy
;
dcount2
++
;
}
}
dcount2
=
0
;
//Do binary comparison second level
for
(
int
i
=
0
;
i
<
9
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
9
;
j
++
)
{
if
(
*
(
values_2
.
ptr
<
float
>
(
i
))
>
*
(
values_2
.
ptr
<
float
>
(
j
)))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
if
(
*
(
values_2
.
ptr
<
float
>
(
i
)
+
1
)
>
*
(
values_2
.
ptr
<
float
>
(
j
)
+
1
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
if
(
*
(
values_2
.
ptr
<
float
>
(
i
)
+
2
)
>
*
(
values_2
.
ptr
<
float
>
(
j
)
+
2
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
// Third 4x4 grid
sample_step
=
pattern_size
/
2
;
dcount2
=
0
;
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
di
=
dx
=
dy
=
0.0
;
nsamples
=
0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point
sample_y
=
yf
+
l
*
scale
;
sample_x
=
xf
+
k
*
scale
;
y1
=
fRound
(
sample_y
);
x1
=
fRound
(
sample_x
);
ri
=
*
(
evolution_
[
level
].
Lt
.
ptr
<
float
>
(
y1
)
+
x1
);
rx
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
ry
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
di
+=
ri
;
dx
+=
rx
;
dy
+=
ry
;
nsamples
++
;
}
}
di
/=
nsamples
;
dx
/=
nsamples
;
dy
/=
nsamples
;
*
(
values_3
.
ptr
<
float
>
(
dcount2
))
=
di
;
*
(
values_3
.
ptr
<
float
>
(
dcount2
)
+
1
)
=
dx
;
*
(
values_3
.
ptr
<
float
>
(
dcount2
)
+
2
)
=
dy
;
dcount2
++
;
}
}
dcount2
=
0
;
//Do binary comparison third level
for
(
int
i
=
0
;
i
<
16
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
16
;
j
++
)
{
if
(
*
(
values_3
.
ptr
<
float
>
(
i
))
>
*
(
values_3
.
ptr
<
float
>
(
j
)))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
if
(
*
(
values_3
.
ptr
<
float
>
(
i
)
+
1
)
>
*
(
values_3
.
ptr
<
float
>
(
j
)
+
1
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
if
(
*
(
values_3
.
ptr
<
float
>
(
i
)
+
2
)
>
*
(
values_3
.
ptr
<
float
>
(
j
)
+
2
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the descriptor of the provided keypoint given the
* main orientation of the keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
*/
void
AKAZE
::
Get_MLDB_Full_Descriptor
(
const
cv
::
KeyPoint
&
kpt
,
unsigned
char
*
desc
)
{
float
di
=
0.0
,
dx
=
0.0
,
dy
=
0.0
,
ratio
=
0.0
;
float
ri
=
0.0
,
rx
=
0.0
,
ry
=
0.0
,
rrx
=
0.0
,
rry
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
int
x1
=
0
,
y1
=
0
,
sample_step
=
0
,
pattern_size
=
0
;
int
level
=
0
,
nsamples
=
0
,
scale
=
0
;
int
dcount1
=
0
,
dcount2
=
0
;
// Matrices for the M-LDB descriptor
Mat
values_1
=
Mat
::
zeros
(
4
,
descriptor_channels_
,
CV_32FC1
);
Mat
values_2
=
Mat
::
zeros
(
9
,
descriptor_channels_
,
CV_32FC1
);
Mat
values_3
=
Mat
::
zeros
(
16
,
descriptor_channels_
,
CV_32FC1
);
// Get the information from the keypoint
ratio
=
(
float
)(
1
<<
kpt
.
octave
);
scale
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
yf
=
kpt
.
pt
.
y
/
ratio
;
xf
=
kpt
.
pt
.
x
/
ratio
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
// First 2x2 grid
pattern_size
=
descriptor_pattern_size_
;
sample_step
=
pattern_size
;
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
di
=
dx
=
dy
=
0.0
;
nsamples
=
0
;
for
(
float
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
float
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
fRound
(
sample_y
);
x1
=
fRound
(
sample_x
);
ri
=
*
(
evolution_
[
level
].
Lt
.
ptr
<
float
>
(
y1
)
+
x1
);
rx
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
ry
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
di
+=
ri
;
if
(
descriptor_channels_
==
2
)
{
dx
+=
sqrtf
(
rx
*
rx
+
ry
*
ry
);
}
else
if
(
descriptor_channels_
==
3
)
{
// Get the x and y derivatives on the rotated axis
rry
=
rx
*
co
+
ry
*
si
;
rrx
=
-
rx
*
si
+
ry
*
co
;
dx
+=
rrx
;
dy
+=
rry
;
}
nsamples
++
;
}
}
di
/=
nsamples
;
dx
/=
nsamples
;
dy
/=
nsamples
;
*
(
values_1
.
ptr
<
float
>
(
dcount2
))
=
di
;
if
(
descriptor_channels_
>
1
)
{
*
(
values_1
.
ptr
<
float
>
(
dcount2
)
+
1
)
=
dx
;
}
if
(
descriptor_channels_
>
2
)
{
*
(
values_1
.
ptr
<
float
>
(
dcount2
)
+
2
)
=
dy
;
}
dcount2
++
;
}
}
// Do binary comparison first level
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
4
;
j
++
)
{
if
(
*
(
values_1
.
ptr
<
float
>
(
i
))
>
*
(
values_1
.
ptr
<
float
>
(
j
)))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
if
(
descriptor_channels_
>
1
)
{
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
4
;
j
++
)
{
if
(
*
(
values_1
.
ptr
<
float
>
(
i
)
+
1
)
>
*
(
values_1
.
ptr
<
float
>
(
j
)
+
1
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
}
if
(
descriptor_channels_
>
2
)
{
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
4
;
j
++
)
{
if
(
*
(
values_1
.
ptr
<
float
>
(
i
)
+
2
)
>
*
(
values_1
.
ptr
<
float
>
(
j
)
+
2
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
}
// Second 3x3 grid
sample_step
=
ceil
(
pattern_size
*
2.
/
3.
);
dcount2
=
0
;
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
di
=
dx
=
dy
=
0.0
;
nsamples
=
0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
fRound
(
sample_y
);
x1
=
fRound
(
sample_x
);
ri
=
*
(
evolution_
[
level
].
Lt
.
ptr
<
float
>
(
y1
)
+
x1
);
rx
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
ry
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
di
+=
ri
;
if
(
descriptor_channels_
==
2
)
{
dx
+=
sqrtf
(
rx
*
rx
+
ry
*
ry
);
}
else
if
(
descriptor_channels_
==
3
)
{
// Get the x and y derivatives on the rotated axis
rry
=
rx
*
co
+
ry
*
si
;
rrx
=
-
rx
*
si
+
ry
*
co
;
dx
+=
rrx
;
dy
+=
rry
;
}
nsamples
++
;
}
}
di
/=
nsamples
;
dx
/=
nsamples
;
dy
/=
nsamples
;
*
(
values_2
.
ptr
<
float
>
(
dcount2
))
=
di
;
if
(
descriptor_channels_
>
1
)
{
*
(
values_2
.
ptr
<
float
>
(
dcount2
)
+
1
)
=
dx
;
}
if
(
descriptor_channels_
>
2
)
{
*
(
values_2
.
ptr
<
float
>
(
dcount2
)
+
2
)
=
dy
;
}
dcount2
++
;
}
}
// Do binary comparison second level
for
(
int
i
=
0
;
i
<
9
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
9
;
j
++
)
{
if
(
*
(
values_2
.
ptr
<
float
>
(
i
))
>
*
(
values_2
.
ptr
<
float
>
(
j
)))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
if
(
descriptor_channels_
>
1
)
{
for
(
int
i
=
0
;
i
<
9
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
9
;
j
++
)
{
if
(
*
(
values_2
.
ptr
<
float
>
(
i
)
+
1
)
>
*
(
values_2
.
ptr
<
float
>
(
j
)
+
1
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
}
if
(
descriptor_channels_
>
2
)
{
for
(
int
i
=
0
;
i
<
9
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
9
;
j
++
)
{
if
(
*
(
values_2
.
ptr
<
float
>
(
i
)
+
2
)
>
*
(
values_2
.
ptr
<
float
>
(
j
)
+
2
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
}
// Third 4x4 grid
sample_step
=
pattern_size
/
2
;
dcount2
=
0
;
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
di
=
dx
=
dy
=
0.0
;
nsamples
=
0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
fRound
(
sample_y
);
x1
=
fRound
(
sample_x
);
ri
=
*
(
evolution_
[
level
].
Lt
.
ptr
<
float
>
(
y1
)
+
x1
);
rx
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
ry
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
di
+=
ri
;
if
(
descriptor_channels_
==
2
)
{
dx
+=
sqrtf
(
rx
*
rx
+
ry
*
ry
);
}
else
if
(
descriptor_channels_
==
3
)
{
// Get the x and y derivatives on the rotated axis
rry
=
rx
*
co
+
ry
*
si
;
rrx
=
-
rx
*
si
+
ry
*
co
;
dx
+=
rrx
;
dy
+=
rry
;
}
nsamples
++
;
}
}
di
/=
nsamples
;
dx
/=
nsamples
;
dy
/=
nsamples
;
*
(
values_3
.
ptr
<
float
>
(
dcount2
))
=
di
;
if
(
descriptor_channels_
>
1
)
{
*
(
values_3
.
ptr
<
float
>
(
dcount2
)
+
1
)
=
dx
;
}
if
(
descriptor_channels_
>
2
)
{
*
(
values_3
.
ptr
<
float
>
(
dcount2
)
+
2
)
=
dy
;
}
dcount2
++
;
}
}
// Do binary comparison third level
for
(
int
i
=
0
;
i
<
16
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
16
;
j
++
)
{
if
(
*
(
values_3
.
ptr
<
float
>
(
i
))
>
*
(
values_3
.
ptr
<
float
>
(
j
)))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
if
(
descriptor_channels_
>
1
)
{
for
(
int
i
=
0
;
i
<
16
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
16
;
j
++
)
{
if
(
*
(
values_3
.
ptr
<
float
>
(
i
)
+
1
)
>
*
(
values_3
.
ptr
<
float
>
(
j
)
+
1
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
}
if
(
descriptor_channels_
>
2
)
{
for
(
int
i
=
0
;
i
<
16
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
16
;
j
++
)
{
if
(
*
(
values_3
.
ptr
<
float
>
(
i
)
+
2
)
>
*
(
values_3
.
ptr
<
float
>
(
j
)
+
2
))
{
desc
[
dcount1
/
8
]
|=
(
1
<<
(
dcount1
%
8
));
}
dcount1
++
;
}
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the M-LDB descriptor of the provided keypoint given the
* main orientation of the keypoint. The descriptor is computed based on a subset of
* the bits of the whole descriptor
* @param kpt Input keypoint
* @param desc Descriptor vector
*/
void
AKAZE
::
Get_MLDB_Descriptor_Subset
(
const
cv
::
KeyPoint
&
kpt
,
unsigned
char
*
desc
)
{
float
di
,
dx
,
dy
;
float
rx
,
ry
;
float
sample_x
=
0.
f
,
sample_y
=
0.
f
;
int
x1
=
0
,
y1
=
0
;
// Get the information from the keypoint
float
ratio
=
(
float
)(
1
<<
kpt
.
octave
);
int
scale
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
float
angle
=
kpt
.
angle
;
float
level
=
kpt
.
class_id
;
float
yf
=
kpt
.
pt
.
y
/
ratio
;
float
xf
=
kpt
.
pt
.
x
/
ratio
;
float
co
=
cos
(
angle
);
float
si
=
sin
(
angle
);
// Allocate memory for the matrix of values
Mat
values
=
cv
::
Mat_
<
float
>::
zeros
((
4
+
9
+
16
)
*
descriptor_channels_
,
1
);
// Sample everything, but only do the comparisons
vector
<
int
>
steps
(
3
);
steps
.
at
(
0
)
=
descriptor_pattern_size_
;
steps
.
at
(
1
)
=
ceil
(
2.
f
*
descriptor_pattern_size_
/
3.
f
);
steps
.
at
(
2
)
=
descriptor_pattern_size_
/
2
;
for
(
int
i
=
0
;
i
<
descriptorSamples_
.
rows
;
i
++
)
{
int
*
coords
=
descriptorSamples_
.
ptr
<
int
>
(
i
);
int
sample_step
=
steps
.
at
(
coords
[
0
]);
di
=
0.0
f
;
dx
=
0.0
f
;
dy
=
0.0
f
;
for
(
int
k
=
coords
[
1
];
k
<
coords
[
1
]
+
sample_step
;
k
++
)
{
for
(
int
l
=
coords
[
2
];
l
<
coords
[
2
]
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
fRound
(
sample_y
);
x1
=
fRound
(
sample_x
);
di
+=
*
(
evolution_
[
level
].
Lt
.
ptr
<
float
>
(
y1
)
+
x1
);
if
(
descriptor_channels_
>
1
)
{
rx
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
ry
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
if
(
descriptor_channels_
==
2
)
{
dx
+=
sqrtf
(
rx
*
rx
+
ry
*
ry
);
}
else
if
(
descriptor_channels_
==
3
)
{
// Get the x and y derivatives on the rotated axis
dx
+=
rx
*
co
+
ry
*
si
;
dy
+=
-
rx
*
si
+
ry
*
co
;
}
}
}
}
*
(
values
.
ptr
<
float
>
(
descriptor_channels_
*
i
))
=
di
;
if
(
descriptor_channels_
==
2
)
{
*
(
values
.
ptr
<
float
>
(
descriptor_channels_
*
i
+
1
))
=
dx
;
}
else
if
(
descriptor_channels_
==
3
)
{
*
(
values
.
ptr
<
float
>
(
descriptor_channels_
*
i
+
1
))
=
dx
;
*
(
values
.
ptr
<
float
>
(
descriptor_channels_
*
i
+
2
))
=
dy
;
}
}
// Do the comparisons
const
float
*
vals
=
values
.
ptr
<
float
>
(
0
);
const
int
*
comps
=
descriptorBits_
.
ptr
<
int
>
(
0
);
for
(
int
i
=
0
;
i
<
descriptorBits_
.
rows
;
i
++
)
{
if
(
vals
[
comps
[
2
*
i
]]
>
vals
[
comps
[
2
*
i
+
1
]])
{
desc
[
i
/
8
]
|=
(
1
<<
(
i
%
8
));
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the upright (not rotation invariant) M-LDB descriptor
* of the provided keypoint given the main orientation of the keypoint.
* The descriptor is computed based on a subset of the bits of the whole descriptor
* @param kpt Input keypoint
* @param desc Descriptor vector
*/
void
AKAZE
::
Get_Upright_MLDB_Descriptor_Subset
(
const
cv
::
KeyPoint
&
kpt
,
unsigned
char
*
desc
)
{
float
di
=
0.0
f
,
dx
=
0.0
f
,
dy
=
0.0
f
;
float
rx
=
0.0
f
,
ry
=
0.0
f
;
float
sample_x
=
0.0
f
,
sample_y
=
0.0
f
;
int
x1
=
0
,
y1
=
0
;
// Get the information from the keypoint
float
ratio
=
(
float
)(
1
<<
kpt
.
octave
);
int
scale
=
fRound
(
0.5
*
kpt
.
size
/
ratio
);
float
level
=
kpt
.
class_id
;
float
yf
=
kpt
.
pt
.
y
/
ratio
;
float
xf
=
kpt
.
pt
.
x
/
ratio
;
// Allocate memory for the matrix of values
Mat
values
=
cv
::
Mat_
<
float
>::
zeros
((
4
+
9
+
16
)
*
descriptor_channels_
,
1
);
vector
<
int
>
steps
(
3
);
steps
.
at
(
0
)
=
descriptor_pattern_size_
;
steps
.
at
(
1
)
=
ceil
(
2.
f
*
descriptor_pattern_size_
/
3.
f
);
steps
.
at
(
2
)
=
descriptor_pattern_size_
/
2
;
for
(
int
i
=
0
;
i
<
descriptorSamples_
.
rows
;
i
++
)
{
int
*
coords
=
descriptorSamples_
.
ptr
<
int
>
(
i
);
int
sample_step
=
steps
.
at
(
coords
[
0
]);
di
=
0.0
f
;
dx
=
0.0
f
;
dy
=
0.0
f
;
for
(
int
k
=
coords
[
1
];
k
<
coords
[
1
]
+
sample_step
;
k
++
)
{
for
(
int
l
=
coords
[
2
];
l
<
coords
[
2
]
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point
sample_y
=
yf
+
l
*
scale
;
sample_x
=
xf
+
k
*
scale
;
y1
=
fRound
(
sample_y
);
x1
=
fRound
(
sample_x
);
di
+=
*
(
evolution_
[
level
].
Lt
.
ptr
<
float
>
(
y1
)
+
x1
);
if
(
descriptor_channels_
>
1
)
{
rx
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
ry
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
if
(
descriptor_channels_
==
2
)
{
dx
+=
sqrtf
(
rx
*
rx
+
ry
*
ry
);
}
else
if
(
descriptor_channels_
==
3
)
{
dx
+=
rx
;
dy
+=
ry
;
}
}
}
}
*
(
values
.
ptr
<
float
>
(
descriptor_channels_
*
i
))
=
di
;
if
(
descriptor_channels_
==
2
)
{
*
(
values
.
ptr
<
float
>
(
descriptor_channels_
*
i
+
1
))
=
dx
;
}
else
if
(
descriptor_channels_
==
3
)
{
*
(
values
.
ptr
<
float
>
(
descriptor_channels_
*
i
+
1
))
=
dx
;
*
(
values
.
ptr
<
float
>
(
descriptor_channels_
*
i
+
2
))
=
dy
;
}
}
// Do the comparisons
const
float
*
vals
=
values
.
ptr
<
float
>
(
0
);
const
int
*
comps
=
descriptorBits_
.
ptr
<
int
>
(
0
);
for
(
int
i
=
0
;
i
<
descriptorBits_
.
rows
;
i
++
)
{
if
(
vals
[
comps
[
2
*
i
]]
>
vals
[
comps
[
2
*
i
+
1
]])
{
desc
[
i
/
8
]
|=
(
1
<<
(
i
%
8
));
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method displays the computation times
*/
void
AKAZE
::
Show_Computation_Times
(
void
)
{
cout
<<
"(*) Time Scale Space: "
<<
tscale_
<<
endl
;
cout
<<
"(*) Time Detector: "
<<
tdetector_
<<
endl
;
cout
<<
" - Time Derivatives: "
<<
tderivatives_
<<
endl
;
cout
<<
" - Time Extrema: "
<<
textrema_
<<
endl
;
cout
<<
" - Time Subpixel: "
<<
tsubpixel_
<<
endl
;
cout
<<
"(*) Time Descriptor: "
<<
tdescriptor_
<<
endl
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes a (quasi-random) list of bits to be taken
* from the full descriptor. To speed the extraction, the function creates
* a list of the samples that are involved in generating at least a bit (sampleList)
* and a list of the comparisons between those samples (comparisons)
* @param sampleList
* @param comparisons The matrix with the binary comparisons
* @param nbits The number of bits of the descriptor
* @param pattern_size The pattern size for the binary descriptor
* @param nchannels Number of channels to consider in the descriptor (1-3)
* @note The function keeps the 18 bits (3-channels by 6 comparisons) of the
* coarser grid, since it provides the most robust estimations
*/
void
generateDescriptorSubsample
(
cv
::
Mat
&
sampleList
,
cv
::
Mat
&
comparisons
,
int
nbits
,
int
pattern_size
,
int
nchannels
)
{
int
ssz
=
0
;
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
int
gz
=
(
i
+
2
)
*
(
i
+
2
);
ssz
+=
gz
*
(
gz
-
1
)
/
2
;
}
ssz
*=
nchannels
;
CV_Assert
(
nbits
<=
ssz
&&
"descriptor size can't be bigger than full descriptor"
);
// Since the full descriptor is usually under 10k elements, we pick
// the selection from the full matrix. We take as many samples per
// pick as the number of channels. For every pick, we
// take the two samples involved and put them in the sampling list
Mat_
<
int
>
fullM
(
ssz
/
nchannels
,
5
);
for
(
size_t
i
=
0
,
c
=
0
;
i
<
3
;
i
++
)
{
int
gdiv
=
i
+
2
;
//grid divisions, per row
int
gsz
=
gdiv
*
gdiv
;
int
psz
=
ceil
(
2.
*
pattern_size
/
(
float
)
gdiv
);
for
(
int
j
=
0
;
j
<
gsz
;
j
++
)
{
for
(
int
k
=
j
+
1
;
k
<
gsz
;
k
++
,
c
++
)
{
fullM
(
c
,
0
)
=
i
;
fullM
(
c
,
1
)
=
psz
*
(
j
%
gdiv
)
-
pattern_size
;
fullM
(
c
,
2
)
=
psz
*
(
j
/
gdiv
)
-
pattern_size
;
fullM
(
c
,
3
)
=
psz
*
(
k
%
gdiv
)
-
pattern_size
;
fullM
(
c
,
4
)
=
psz
*
(
k
/
gdiv
)
-
pattern_size
;
}
}
}
srand
(
1024
);
Mat_
<
int
>
comps
=
Mat_
<
int
>
(
nchannels
*
ceil
(
nbits
/
(
float
)
nchannels
),
2
);
comps
=
1000
;
// Select some samples. A sample includes all channels
int
count
=
0
;
size_t
npicks
=
ceil
(
nbits
/
(
float
)
nchannels
);
Mat_
<
int
>
samples
(
29
,
3
);
Mat_
<
int
>
fullcopy
=
fullM
.
clone
();
samples
=
-
1
;
for
(
size_t
i
=
0
;
i
<
npicks
;
i
++
)
{
size_t
k
=
rand
()
%
(
fullM
.
rows
-
i
);
if
(
i
<
6
)
{
// Force use of the coarser grid values and comparisons
k
=
i
;
}
bool
n
=
true
;
for
(
int
j
=
0
;
j
<
count
;
j
++
)
{
if
(
samples
(
j
,
0
)
==
fullcopy
(
k
,
0
)
&&
samples
(
j
,
1
)
==
fullcopy
(
k
,
1
)
&&
samples
(
j
,
2
)
==
fullcopy
(
k
,
2
))
{
n
=
false
;
comps
(
i
*
nchannels
,
0
)
=
nchannels
*
j
;
comps
(
i
*
nchannels
+
1
,
0
)
=
nchannels
*
j
+
1
;
comps
(
i
*
nchannels
+
2
,
0
)
=
nchannels
*
j
+
2
;
break
;
}
}
if
(
n
)
{
samples
(
count
,
0
)
=
fullcopy
(
k
,
0
);
samples
(
count
,
1
)
=
fullcopy
(
k
,
1
);
samples
(
count
,
2
)
=
fullcopy
(
k
,
2
);
comps
(
i
*
nchannels
,
0
)
=
nchannels
*
count
;
comps
(
i
*
nchannels
+
1
,
0
)
=
nchannels
*
count
+
1
;
comps
(
i
*
nchannels
+
2
,
0
)
=
nchannels
*
count
+
2
;
count
++
;
}
n
=
true
;
for
(
int
j
=
0
;
j
<
count
;
j
++
)
{
if
(
samples
(
j
,
0
)
==
fullcopy
(
k
,
0
)
&&
samples
(
j
,
1
)
==
fullcopy
(
k
,
3
)
&&
samples
(
j
,
2
)
==
fullcopy
(
k
,
4
))
{
n
=
false
;
comps
(
i
*
nchannels
,
1
)
=
nchannels
*
j
;
comps
(
i
*
nchannels
+
1
,
1
)
=
nchannels
*
j
+
1
;
comps
(
i
*
nchannels
+
2
,
1
)
=
nchannels
*
j
+
2
;
break
;
}
}
if
(
n
)
{
samples
(
count
,
0
)
=
fullcopy
(
k
,
0
);
samples
(
count
,
1
)
=
fullcopy
(
k
,
3
);
samples
(
count
,
2
)
=
fullcopy
(
k
,
4
);
comps
(
i
*
nchannels
,
1
)
=
nchannels
*
count
;
comps
(
i
*
nchannels
+
1
,
1
)
=
nchannels
*
count
+
1
;
comps
(
i
*
nchannels
+
2
,
1
)
=
nchannels
*
count
+
2
;
count
++
;
}
Mat
tmp
=
fullcopy
.
row
(
k
);
fullcopy
.
row
(
fullcopy
.
rows
-
i
-
1
).
copyTo
(
tmp
);
}
sampleList
=
samples
.
rowRange
(
0
,
count
).
clone
();
comparisons
=
comps
.
rowRange
(
0
,
nbits
).
clone
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes the angle from the vector given by (X Y). From 0 to 2*Pi
*/
inline
float
get_angle
(
float
x
,
float
y
)
{
if
(
x
>=
0
&&
y
>=
0
)
{
return
atanf
(
y
/
x
);
}
if
(
x
<
0
&&
y
>=
0
)
{
return
CV_PI
-
atanf
(
-
y
/
x
);
}
if
(
x
<
0
&&
y
<
0
)
{
return
CV_PI
+
atanf
(
y
/
x
);
}
if
(
x
>=
0
&&
y
<
0
)
{
return
2.0
*
CV_PI
-
atanf
(
-
y
/
x
);
}
return
0
;
}
//**************************************************************************************
//**************************************************************************************
/**
* @brief This function computes the value of a 2D Gaussian function
* @param x X Position
* @param y Y Position
* @param sig Standard Deviation
*/
inline
float
gaussian
(
float
x
,
float
y
,
float
sigma
)
{
return
expf
(
-
(
x
*
x
+
y
*
y
)
/
(
2.0
f
*
sigma
*
sigma
));
}
//**************************************************************************************
//**************************************************************************************
/**
* @brief This function checks descriptor limits
* @param x X Position
* @param y Y Position
* @param width Image width
* @param height Image height
*/
inline
void
check_descriptor_limits
(
int
&
x
,
int
&
y
,
const
int
width
,
const
int
height
)
{
if
(
x
<
0
)
{
x
=
0
;
}
if
(
y
<
0
)
{
y
=
0
;
}
if
(
x
>
width
-
1
)
{
x
=
width
-
1
;
}
if
(
y
>
height
-
1
)
{
y
=
height
-
1
;
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This funtion rounds float to nearest integer
* @param flt Input float
* @return dst Nearest integer
*/
inline
int
fRound
(
float
flt
)
{
return
(
int
)(
flt
+
0.5
f
);
}
modules/features2d/src/akaze/AKAZE.h
0 → 100644
View file @
7a594354
/**
* @file AKAZE.h
* @brief Main class for detecting and computing binary descriptors in an
* accelerated nonlinear scale space
* @date Mar 27, 2013
* @author Pablo F. Alcantarilla, Jesus Nuevo
*/
#ifndef _AKAZE_H_
#define _AKAZE_H_
//*************************************************************************************
//*************************************************************************************
// Includes
#include "config.h"
#include "fed.h"
#include "utils.h"
#include "nldiffusion_functions.h"
//*************************************************************************************
//*************************************************************************************
// AKAZE Class Declaration
class
AKAZE
{
private
:
// Parameters of the AKAZE class
int
omax_
;
// Maximum octave level
int
noctaves_
;
// Number of octaves
int
nsublevels_
;
// Number of sublevels per octave level
int
img_width_
;
// Width of the original image
int
img_height_
;
// Height of the original image
float
soffset_
;
// Base scale offset
float
factor_size_
;
// Factor for the multiscale derivatives
float
sderivatives_
;
// Standard deviation of the Gaussian for the nonlinear diff. derivatives
float
kcontrast_
;
// The contrast parameter for the scalar nonlinear diffusion
float
dthreshold_
;
// Feature detector threshold response
int
diffusivity_
;
// Diffusivity type, 0->PM G1, 1->PM G2, 2-> Weickert, 3->Charbonnier
int
descriptor_
;
// Descriptor mode:
// 0-> SURF_UPRIGHT, 1->SURF
// 2-> M-SURF_UPRIGHT, 3->M-SURF
// 4-> M-LDB_UPRIGHT, 5->M-LDB
int
descriptor_size_
;
// Size of the descriptor in bits. Use 0 for the full descriptor
int
descriptor_pattern_size_
;
// Size of the pattern. Actual size sampled is 2*pattern_size
int
descriptor_channels_
;
// Number of channels to consider in the M-LDB descriptor
bool
save_scale_space_
;
// For saving scale space images
bool
verbosity_
;
// Verbosity level
std
::
vector
<
tevolution
>
evolution_
;
// Vector of nonlinear diffusion evolution
// FED parameters
int
ncycles_
;
// Number of cycles
bool
reordering_
;
// Flag for reordering time steps
std
::
vector
<
std
::
vector
<
float
>
>
tsteps_
;
// Vector of FED dynamic time steps
std
::
vector
<
int
>
nsteps_
;
// Vector of number of steps per cycle
// Some matrices for the M-LDB descriptor computation
cv
::
Mat
descriptorSamples_
;
// List of positions in the grids to sample LDB bits from.
cv
::
Mat
descriptorBits_
;
cv
::
Mat
bitMask_
;
// Computation times variables in ms
double
tkcontrast_
;
// Kcontrast factor computation
double
tscale_
;
// Nonlinear Scale space generation
double
tderivatives_
;
// Multiscale derivatives
double
tdetector_
;
// Feature detector
double
textrema_
;
// Scale Space extrema
double
tsubpixel_
;
// Subpixel refinement
double
tdescriptor_
;
// Feature descriptors
public
:
// Constructor
AKAZE
(
const
AKAZEOptions
&
options
);
// Destructor
~
AKAZE
(
void
);
// Setters
void
Set_Octave_Max
(
const
int
&
omax
)
{
omax_
=
omax
;
}
void
Set_NSublevels
(
const
int
&
nsublevels
)
{
nsublevels_
=
nsublevels
;
}
void
Set_Save_Scale_Space_Flag
(
const
bool
&
save_scale_space
)
{
save_scale_space_
=
save_scale_space
;
}
void
Set_Image_Width
(
const
int
&
img_width
)
{
img_width_
=
img_width
;
}
void
Set_Image_Height
(
const
int
&
img_height
)
{
img_height_
=
img_height
;
}
// Getters
int
Get_Image_Width
(
void
)
{
return
img_width_
;
}
int
Get_Image_Height
(
void
)
{
return
img_height_
;
}
double
Get_Time_KContrast
(
void
)
{
return
tkcontrast_
;
}
double
Get_Time_Scale_Space
(
void
)
{
return
tscale_
;
}
double
Get_Time_Derivatives
(
void
)
{
return
tderivatives_
;
}
double
Get_Time_Detector
(
void
)
{
return
tdetector_
;
}
double
Get_Time_Descriptor
(
void
)
{
return
tdescriptor_
;
}
// Scale Space methods
void
Allocate_Memory_Evolution
(
void
);
int
Create_Nonlinear_Scale_Space
(
const
cv
::
Mat
&
img
);
void
Feature_Detection
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
);
void
Compute_Determinant_Hessian_Response
(
void
);
void
Compute_Multiscale_Derivatives
(
void
);
void
Find_Scale_Space_Extrema
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
);
void
Do_Subpixel_Refinement
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
);
void
Feature_Suppression_Distance
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
,
float
mdist
);
// Feature description methods
void
Compute_Descriptors
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
,
cv
::
Mat
&
desc
);
void
Compute_Main_Orientation_SURF
(
cv
::
KeyPoint
&
kpt
);
// SURF Pattern Descriptor
void
Get_SURF_Descriptor_Upright_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
void
Get_SURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
// M-SURF Pattern Descriptor
void
Get_MSURF_Upright_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
void
Get_MSURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
// M-LDB Pattern Descriptor
void
Get_Upright_MLDB_Full_Descriptor
(
const
cv
::
KeyPoint
&
kpt
,
unsigned
char
*
desc
);
void
Get_MLDB_Full_Descriptor
(
const
cv
::
KeyPoint
&
kpt
,
unsigned
char
*
desc
);
void
Get_Upright_MLDB_Descriptor_Subset
(
const
cv
::
KeyPoint
&
kpt
,
unsigned
char
*
desc
);
void
Get_MLDB_Descriptor_Subset
(
const
cv
::
KeyPoint
&
kpt
,
unsigned
char
*
desc
);
// Methods for saving some results and showing computation times
void
Save_Scale_Space
(
void
);
void
Save_Detector_Responses
(
void
);
void
Show_Computation_Times
(
void
);
};
//*************************************************************************************
//*************************************************************************************
// Inline functions
/**
* @brief This function sets default parameters for the A-KAZE detector.
* @param options AKAZE options
*/
void
setDefaultAKAZEOptions
(
AKAZEOptions
&
options
);
// Inline functions
void
generateDescriptorSubsample
(
cv
::
Mat
&
sampleList
,
cv
::
Mat
&
comparisons
,
int
nbits
,
int
pattern_size
,
int
nchannels
);
float
get_angle
(
float
x
,
float
y
);
float
gaussian
(
float
x
,
float
y
,
float
sigma
);
void
check_descriptor_limits
(
int
&
x
,
int
&
y
,
const
int
width
,
const
int
height
);
int
fRound
(
float
flt
);
//*************************************************************************************
//*************************************************************************************
#endif
modules/features2d/src/akaze/config.h
0 → 100644
View file @
7a594354
#ifndef _CONFIG_H_
#define _CONFIG_H_
// STL
#include <string>
#include <vector>
#include <cmath>
#include <bitset>
#include <iomanip>
// OpenCV
#include "precomp.hpp"
// OpenMP
#ifdef _OPENMP
# include <omp.h>
#endif
// Lookup table for 2d gaussian (sigma = 2.5) where (0,0) is top left and (6,6) is bottom right
const
float
gauss25
[
7
][
7
]
=
{
{
0
.
025464
81
f
,
0
.
023506
98
f
,
0
.
01
849125
f
,
0
.
0123
9505
f
,
0
.
0070
8017
f
,
0
.
0034462
9
f
,
0
.
00142
946
f
},
{
0
.
023506
98
f
,
0
.
0216
9968
f
,
0
.
01706
957
f
,
0
.
0114420
8
f
,
0
.
006535
82
f
,
0
.
0031
8132
f
,
0
.
00131
956
f
},
{
0
.
01
849125
f
,
0
.
01706
957
f
,
0
.
01342740
f
,
0
.
00
900066
f
,
0
.
00514126
f
,
0
.
00250252
f
,
0
.
00103
800
f
},
{
0
.
0123
9505
f
,
0
.
0114420
8
f
,
0
.
00
900066
f
,
0
.
00603332
f
,
0
.
0034462
9
f
,
0
.
0016774
9
f
,
0
.
0006
9579
f
},
{
0
.
0070
8017
f
,
0
.
006535
82
f
,
0
.
00514126
f
,
0
.
0034462
9
f
,
0
.
001
96855
f
,
0
.
000
95820
f
,
0
.
0003
9744
f
},
{
0
.
0034462
9
f
,
0
.
0031
8132
f
,
0
.
00250252
f
,
0
.
0016774
9
f
,
0
.
000
95820
f
,
0
.
00046640
f
,
0
.
0001
9346
f
},
{
0
.
00142
946
f
,
0
.
00131
956
f
,
0
.
00103
800
f
,
0
.
0006
9579
f
,
0
.
0003
9744
f
,
0
.
0001
9346
f
,
0
.
0000
8024
f
}
};
// Scale Space parameters
const
float
DEFAULT_SCALE_OFFSET
=
1
.
60
f
;
// Base scale offset (sigma units)
const
float
DEFAULT_FACTOR_SIZE
=
1
.
5
f
;
// Factor for the multiscale derivatives
const
int
DEFAULT_OCTAVE_MIN
=
0
;
// Initial octave level (-1 means that the size of the input image is duplicated)
const
int
DEFAULT_OCTAVE_MAX
=
4
;
// Maximum octave evolution of the image 2^sigma (coarsest scale sigma units)
const
int
DEFAULT_NSUBLEVELS
=
4
;
// Default number of sublevels per scale level
const
int
DEFAULT_DIFFUSIVITY_TYPE
=
1
;
const
float
KCONTRAST_PERCENTILE
=
0
.
7
f
;
const
int
KCONTRAST_NBINS
=
300
;
const
float
DEFAULT_SIGMA_SMOOTHING_DERIVATIVES
=
1
.
0
f
;
const
float
DEFAULT_KCONTRAST
=
.
01
f
;
// Detector Parameters
const
float
DEFAULT_DETECTOR_THRESHOLD
=
0
.
001
f
;
// Detector response threshold to accept point
const
float
DEFAULT_MIN_DETECTOR_THRESHOLD
=
0
.
00001
f
;
// Minimum Detector response threshold to accept point
const
int
DEFAULT_LDB_DESCRIPTOR_SIZE
=
0
;
// Use 0 for the full descriptor, or the number of bits
const
int
DEFAULT_LDB_PATTERN_SIZE
=
10
;
// Actual patch size is 2*pattern_size*point.scale;
const
int
DEFAULT_LDB_CHANNELS
=
3
;
// Descriptor Parameters
enum
DESCRIPTOR_TYPE
{
SURF_UPRIGHT
=
0
,
// Upright descriptors, not invariant to rotation
SURF
=
1
,
MSURF_UPRIGHT
=
2
,
// Upright descriptors, not invariant to rotation
MSURF
=
3
,
MLDB_UPRIGHT
=
4
,
// Upright descriptors, not invariant to rotation
MLDB
=
5
};
const
int
DEFAULT_DESCRIPTOR
=
MLDB
;
// Some debugging options
const
bool
DEFAULT_SAVE_SCALE_SPACE
=
false
;
// For saving the scale space images
const
bool
DEFAULT_VERBOSITY
=
false
;
// Verbosity level (0->no verbosity)
const
bool
DEFAULT_SHOW_RESULTS
=
true
;
// For showing the output image with the detected features plus some ratios
const
bool
DEFAULT_SAVE_KEYPOINTS
=
false
;
// For saving the list of keypoints
// Options structure
struct
AKAZEOptions
{
int
omin
;
int
omax
;
int
nsublevels
;
int
img_width
;
int
img_height
;
int
diffusivity
;
float
soffset
;
float
sderivatives
;
float
dthreshold
;
float
dthreshold2
;
int
descriptor
;
int
descriptor_size
;
int
descriptor_channels
;
int
descriptor_pattern_size
;
bool
save_scale_space
;
bool
save_keypoints
;
bool
verbosity
;
AKAZEOptions
()
{
// Load the default options
soffset
=
DEFAULT_SCALE_OFFSET
;
omax
=
DEFAULT_OCTAVE_MAX
;
nsublevels
=
DEFAULT_NSUBLEVELS
;
dthreshold
=
DEFAULT_DETECTOR_THRESHOLD
;
diffusivity
=
DEFAULT_DIFFUSIVITY_TYPE
;
descriptor
=
DEFAULT_DESCRIPTOR
;
descriptor_size
=
DEFAULT_LDB_DESCRIPTOR_SIZE
;
descriptor_channels
=
DEFAULT_LDB_CHANNELS
;
descriptor_pattern_size
=
DEFAULT_LDB_PATTERN_SIZE
;
sderivatives
=
DEFAULT_SIGMA_SMOOTHING_DERIVATIVES
;
save_scale_space
=
DEFAULT_SAVE_SCALE_SPACE
;
save_keypoints
=
DEFAULT_SAVE_KEYPOINTS
;
verbosity
=
DEFAULT_VERBOSITY
;
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
AKAZEOptions
&
akaze_options
)
{
os
<<
std
::
left
;
#define CHECK_AKAZE_OPTION(option) \
os << std::setw(33) << #option << " = " << option << std::endl
// Scale-space parameters.
CHECK_AKAZE_OPTION
(
akaze_options
.
omax
);
CHECK_AKAZE_OPTION
(
akaze_options
.
nsublevels
);
CHECK_AKAZE_OPTION
(
akaze_options
.
soffset
);
CHECK_AKAZE_OPTION
(
akaze_options
.
sderivatives
);
CHECK_AKAZE_OPTION
(
akaze_options
.
diffusivity
);
// Detection parameters.
CHECK_AKAZE_OPTION
(
akaze_options
.
dthreshold
);
// Descriptor parameters.
CHECK_AKAZE_OPTION
(
akaze_options
.
descriptor
);
CHECK_AKAZE_OPTION
(
akaze_options
.
descriptor_channels
);
CHECK_AKAZE_OPTION
(
akaze_options
.
descriptor_size
);
// Save scale-space
CHECK_AKAZE_OPTION
(
akaze_options
.
save_scale_space
);
// Verbose option for debug.
CHECK_AKAZE_OPTION
(
akaze_options
.
verbosity
);
#undef CHECK_AKAZE_OPTIONS
return
os
;
}
};
struct
tevolution
{
cv
::
Mat
Lx
,
Ly
;
// First order spatial derivatives
cv
::
Mat
Lxx
,
Lxy
,
Lyy
;
// Second order spatial derivatives
cv
::
Mat
Lflow
;
// Diffusivity image
cv
::
Mat
Lt
;
// Evolution image
cv
::
Mat
Lsmooth
;
// Smoothed image
cv
::
Mat
Lstep
;
// Evolution step update
cv
::
Mat
Ldet
;
// Detector response
float
etime
;
// Evolution time
float
esigma
;
// Evolution sigma. For linear diffusion t = sigma^2 / 2
int
octave
;
// Image octave
int
sublevel
;
// Image sublevel in each octave
int
sigma_size
;
// Integer sigma. For computing the feature detector responses
};
#endif
\ No newline at end of file
modules/features2d/src/akaze/fed.h
0 → 100644
View file @
7a594354
#ifndef FED_H
#define FED_H
//******************************************************************************
//******************************************************************************
// Includes
#include <iostream>
#include <vector>
//*************************************************************************************
//*************************************************************************************
// Declaration of functions
int
fed_tau_by_process_time
(
const
float
&
T
,
const
int
&
M
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>&
tau
);
int
fed_tau_by_cycle_time
(
const
float
&
t
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>
&
tau
)
;
int
fed_tau_internal
(
const
int
&
n
,
const
float
&
scale
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>
&
tau
);
bool
fed_is_prime_internal
(
const
int
&
number
);
//*************************************************************************************
//*************************************************************************************
#endif // FED_H
modules/features2d/src/akaze/nldiffusion_functions.cpp
0 → 100644
View file @
7a594354
//=============================================================================
//
// nldiffusion_functions.cpp
// Authors: Pablo F. Alcantarilla (1), Jesus Nuevo (2)
// Institutions: Georgia Institute of Technology (1)
// TrueVision Solutions (2)
// Date: 15/09/2013
// Email: pablofdezalc@gmail.com
//
// AKAZE Features Copyright 2013, Pablo F. Alcantarilla, Jesus Nuevo
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================
/**
* @file nldiffusion_functions.cpp
* @brief Functions for nonlinear diffusion filtering applications
* @date Sep 15, 2013
* @author Pablo F. Alcantarilla, Jesus Nuevo
*/
#include "nldiffusion_functions.h"
using
namespace
std
;
using
namespace
cv
;
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function smoothes an image with a Gaussian kernel
* @param src Input image
* @param dst Output image
* @param ksize_x Kernel size in X-direction (horizontal)
* @param ksize_y Kernel size in Y-direction (vertical)
* @param sigma Kernel standard deviation
*/
void
gaussian_2D_convolution
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
const
size_t
&
ksize_x
,
const
size_t
&
ksize_y
,
const
float
&
sigma
)
{
size_t
ksize_x_
=
0
,
ksize_y_
=
0
;
// Compute an appropriate kernel size according to the specified sigma
if
(
sigma
>
ksize_x
||
sigma
>
ksize_y
||
ksize_x
==
0
||
ksize_y
==
0
)
{
ksize_x_
=
ceil
(
2.0
*
(
1.0
+
(
sigma
-
0.8
)
/
(
0.3
)));
ksize_y_
=
ksize_x_
;
}
// The kernel size must be and odd number
if
((
ksize_x_
%
2
)
==
0
)
{
ksize_x_
+=
1
;
}
if
((
ksize_y_
%
2
)
==
0
)
{
ksize_y_
+=
1
;
}
// Perform the Gaussian Smoothing with border replication
GaussianBlur
(
src
,
dst
,
Size
(
ksize_x_
,
ksize_y_
),
sigma
,
sigma
,
BORDER_REPLICATE
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes image derivatives with Scharr kernel
* @param src Input image
* @param dst Output image
* @param xorder Derivative order in X-direction (horizontal)
* @param yorder Derivative order in Y-direction (vertical)
* @note Scharr operator approximates better rotation invariance than
* other stencils such as Sobel. See Weickert and Scharr,
* A Scheme for Coherence-Enhancing Diffusion Filtering with Optimized Rotation Invariance,
* Journal of Visual Communication and Image Representation 2002
*/
void
image_derivatives_scharr
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
const
size_t
&
xorder
,
const
size_t
&
yorder
)
{
Scharr
(
src
,
dst
,
CV_32F
,
xorder
,
yorder
,
1.0
,
0
,
BORDER_DEFAULT
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes the Perona and Malik conductivity coefficient g1
* g1 = exp(-|dL|^2/k^2)
* @param Lx First order image derivative in X-direction (horizontal)
* @param Ly First order image derivative in Y-direction (vertical)
* @param dst Output image
* @param k Contrast factor parameter
*/
void
pm_g1
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
const
float
&
k
)
{
exp
(
-
(
Lx
.
mul
(
Lx
)
+
Ly
.
mul
(
Ly
))
/
(
k
*
k
),
dst
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes the Perona and Malik conductivity coefficient g2
* g2 = 1 / (1 + dL^2 / k^2)
* @param Lx First order image derivative in X-direction (horizontal)
* @param Ly First order image derivative in Y-direction (vertical)
* @param dst Output image
* @param k Contrast factor parameter
*/
void
pm_g2
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
const
float
&
k
)
{
dst
=
1.0
/
(
1.0
+
(
Lx
.
mul
(
Lx
)
+
Ly
.
mul
(
Ly
))
/
(
k
*
k
));
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes Weickert conductivity coefficient gw
* @param Lx First order image derivative in X-direction (horizontal)
* @param Ly First order image derivative in Y-direction (vertical)
* @param dst Output image
* @param k Contrast factor parameter
* @note For more information check the following paper: J. Weickert
* Applications of nonlinear diffusion in image processing and computer vision,
* Proceedings of Algorithmy 2000
*/
void
weickert_diffusivity
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
const
float
&
k
)
{
Mat
modg
;
pow
((
Lx
.
mul
(
Lx
)
+
Ly
.
mul
(
Ly
))
/
(
k
*
k
),
4
,
modg
);
cv
::
exp
(
-
3.315
/
modg
,
dst
);
dst
=
1.0
-
dst
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes Charbonnier conductivity coefficient gc
* gc = 1 / sqrt(1 + dL^2 / k^2)
* @param Lx First order image derivative in X-direction (horizontal)
* @param Ly First order image derivative in Y-direction (vertical)
* @param dst Output image
* @param k Contrast factor parameter
* @note For more information check the following paper: J. Weickert
* Applications of nonlinear diffusion in image processing and computer vision,
* Proceedings of Algorithmy 2000
*/
void
charbonnier_diffusivity
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
const
float
&
k
)
{
Mat
den
;
cv
::
sqrt
(
1.0
+
(
Lx
.
mul
(
Lx
)
+
Ly
.
mul
(
Ly
))
/
(
k
*
k
),
den
);
dst
=
1.0
/
den
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes a good empirical value for the k contrast factor
* given an input image, the percentile (0-1), the gradient scale and the number of
* bins in the histogram
* @param img Input image
* @param perc Percentile of the image gradient histogram (0-1)
* @param gscale Scale for computing the image gradient histogram
* @param nbins Number of histogram bins
* @param ksize_x Kernel size in X-direction (horizontal) for the Gaussian smoothing kernel
* @param ksize_y Kernel size in Y-direction (vertical) for the Gaussian smoothing kernel
* @return k contrast factor
*/
float
compute_k_percentile
(
const
cv
::
Mat
&
img
,
const
float
&
perc
,
const
float
&
gscale
,
const
size_t
&
nbins
,
const
size_t
&
ksize_x
,
const
size_t
&
ksize_y
)
{
size_t
nbin
=
0
,
nelements
=
0
,
nthreshold
=
0
,
k
=
0
;
float
kperc
=
0.0
,
modg
=
0.0
,
lx
=
0.0
,
ly
=
0.0
;
float
npoints
=
0.0
;
float
hmax
=
0.0
;
// Create the array for the histogram
float
*
hist
=
new
float
[
nbins
];
// Create the matrices
Mat
gaussian
=
Mat
::
zeros
(
img
.
rows
,
img
.
cols
,
CV_32F
);
Mat
Lx
=
Mat
::
zeros
(
img
.
rows
,
img
.
cols
,
CV_32F
);
Mat
Ly
=
Mat
::
zeros
(
img
.
rows
,
img
.
cols
,
CV_32F
);
// Set the histogram to zero, just in case
for
(
size_t
i
=
0
;
i
<
nbins
;
i
++
)
{
hist
[
i
]
=
0.0
;
}
// Perform the Gaussian convolution
gaussian_2D_convolution
(
img
,
gaussian
,
ksize_x
,
ksize_y
,
gscale
);
// Compute the Gaussian derivatives Lx and Ly
image_derivatives_scharr
(
gaussian
,
Lx
,
1
,
0
);
image_derivatives_scharr
(
gaussian
,
Ly
,
0
,
1
);
// Skip the borders for computing the histogram
for
(
int
i
=
1
;
i
<
gaussian
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
1
;
j
<
gaussian
.
cols
-
1
;
j
++
)
{
lx
=
*
(
Lx
.
ptr
<
float
>
(
i
)
+
j
);
ly
=
*
(
Ly
.
ptr
<
float
>
(
i
)
+
j
);
modg
=
sqrt
(
lx
*
lx
+
ly
*
ly
);
// Get the maximum
if
(
modg
>
hmax
)
{
hmax
=
modg
;
}
}
}
// Skip the borders for computing the histogram
for
(
int
i
=
1
;
i
<
gaussian
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
1
;
j
<
gaussian
.
cols
-
1
;
j
++
)
{
lx
=
*
(
Lx
.
ptr
<
float
>
(
i
)
+
j
);
ly
=
*
(
Ly
.
ptr
<
float
>
(
i
)
+
j
);
modg
=
sqrt
(
lx
*
lx
+
ly
*
ly
);
// Find the correspondent bin
if
(
modg
!=
0.0
)
{
nbin
=
floor
(
nbins
*
(
modg
/
hmax
));
if
(
nbin
==
nbins
)
{
nbin
--
;
}
hist
[
nbin
]
++
;
npoints
++
;
}
}
}
// Now find the perc of the histogram percentile
nthreshold
=
(
size_t
)(
npoints
*
perc
);
for
(
k
=
0
;
nelements
<
nthreshold
&&
k
<
nbins
;
k
++
)
{
nelements
=
nelements
+
hist
[
k
];
}
if
(
nelements
<
nthreshold
)
{
kperc
=
0.03
;
}
else
{
kperc
=
hmax
*
((
float
)(
k
)
/
(
float
)
nbins
);
}
delete
[]
hist
;
return
kperc
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes Scharr image derivatives
* @param src Input image
* @param dst Output image
* @param xorder Derivative order in X-direction (horizontal)
* @param yorder Derivative order in Y-direction (vertical)
* @param scale Scale factor for the derivative size
*/
void
compute_scharr_derivatives
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
const
size_t
&
xorder
,
const
size_t
&
yorder
,
const
size_t
&
scale
)
{
Mat
kx
,
ky
;
compute_derivative_kernels
(
kx
,
ky
,
xorder
,
yorder
,
scale
);
sepFilter2D
(
src
,
dst
,
CV_32F
,
kx
,
ky
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function performs a scalar non-linear diffusion step
* @param Ld2 Output image in the evolution
* @param c Conductivity image
* @param Lstep Previous image in the evolution
* @param stepsize The step size in time units
* @note Forward Euler Scheme 3x3 stencil
* The function c is a scalar value that depends on the gradient norm
* dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy
*/
void
nld_step_scalar
(
cv
::
Mat
&
Ld
,
const
cv
::
Mat
&
c
,
cv
::
Mat
&
Lstep
,
const
float
&
stepsize
)
{
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for
(
int
i
=
1
;
i
<
Lstep
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
1
;
j
<
Lstep
.
cols
-
1
;
j
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
j
+
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
+
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
)));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
j
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
-
1
)));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
i
+
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
+
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
)));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
i
-
1
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
-
1
)
+
j
)));
*
(
Lstep
.
ptr
<
float
>
(
i
)
+
j
)
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
}
for
(
int
j
=
1
;
j
<
Lstep
.
cols
-
1
;
j
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
0
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
0
)
+
j
+
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
+
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
)));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
0
)
+
j
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
0
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
-
1
)));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
0
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
)));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
0
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
0
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
)));
*
(
Lstep
.
ptr
<
float
>
(
0
)
+
j
)
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
for
(
int
j
=
1
;
j
<
Lstep
.
cols
-
1
;
j
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
+
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
+
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
-
1
)));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
2
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
2
)
+
j
)));
*
(
Lstep
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
for
(
int
i
=
1
;
i
<
Lstep
.
rows
-
1
;
i
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
i
)))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
))));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
i
)))
+
(
*
(
c
.
ptr
<
float
>
(
i
))))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
))));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
i
)))
+
(
*
(
c
.
ptr
<
float
>
(
i
+
1
))))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
+
1
)))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
))));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
i
-
1
)))
+
(
*
(
c
.
ptr
<
float
>
(
i
))))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
-
1
))));
*
(
Lstep
.
ptr
<
float
>
(
i
))
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
for
(
int
i
=
1
;
i
<
Lstep
.
rows
-
1
;
i
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
2
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
2
)));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
i
+
1
)
+
Lstep
.
cols
-
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
+
1
)
+
Lstep
.
cols
-
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
i
-
1
)
+
Lstep
.
cols
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
-
1
)
+
Lstep
.
cols
-
1
)));
*
(
Lstep
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
Ld
=
Ld
+
Lstep
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function downsamples the input image with the kernel [1/4,1/2,1/4]
* @param img Input image to be downsampled
* @param dst Output image with half of the resolution of the input image
*/
void
downsample_image
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
)
{
int
i1
=
0
,
j1
=
0
,
i2
=
0
,
j2
=
0
;
for
(
i1
=
1
;
i1
<
src
.
rows
;
i1
+=
2
)
{
j2
=
0
;
for
(
j1
=
1
;
j1
<
src
.
cols
;
j1
+=
2
)
{
*
(
dst
.
ptr
<
float
>
(
i2
)
+
j2
)
=
0.5
*
(
*
(
src
.
ptr
<
float
>
(
i1
)
+
j1
))
+
0.25
*
(
*
(
src
.
ptr
<
float
>
(
i1
)
+
j1
-
1
)
+
*
(
src
.
ptr
<
float
>
(
i1
)
+
j1
+
1
));
j2
++
;
}
i2
++
;
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function downsamples the input image using OpenCV resize
* @param img Input image to be downsampled
* @param dst Output image with half of the resolution of the input image
*/
void
halfsample_image
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
)
{
// Make sure the destination image is of the right size
CV_Assert
(
src
.
cols
/
2
==
dst
.
cols
);
CV_Assert
(
src
.
rows
/
2
==
dst
.
rows
);
resize
(
src
,
dst
,
dst
.
size
(),
0
,
0
,
cv
::
INTER_AREA
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief Compute Scharr derivative kernels for sizes different than 3
* @param kx_ The derivative kernel in x-direction
* @param ky_ The derivative kernel in y-direction
* @param dx The derivative order in x-direction
* @param dy The derivative order in y-direction
* @param scale The kernel size
*/
void
compute_derivative_kernels
(
cv
::
OutputArray
kx_
,
cv
::
OutputArray
ky_
,
const
size_t
&
dx
,
const
size_t
&
dy
,
const
size_t
&
scale
)
{
const
int
ksize
=
3
+
2
*
(
scale
-
1
);
// The usual Scharr kernel
if
(
scale
==
1
)
{
getDerivKernels
(
kx_
,
ky_
,
dx
,
dy
,
0
,
true
,
CV_32F
);
return
;
}
kx_
.
create
(
ksize
,
1
,
CV_32F
,
-
1
,
true
);
ky_
.
create
(
ksize
,
1
,
CV_32F
,
-
1
,
true
);
Mat
kx
=
kx_
.
getMat
();
Mat
ky
=
ky_
.
getMat
();
float
w
=
10.0
/
3.0
;
float
norm
=
1.0
/
(
2.0
*
scale
*
(
w
+
2.0
));
for
(
int
k
=
0
;
k
<
2
;
k
++
)
{
Mat
*
kernel
=
k
==
0
?
&
kx
:
&
ky
;
int
order
=
k
==
0
?
dx
:
dy
;
float
kerI
[
1000
];
for
(
int
t
=
0
;
t
<
ksize
;
t
++
)
{
kerI
[
t
]
=
0
;
}
if
(
order
==
0
)
{
kerI
[
0
]
=
norm
;
kerI
[
ksize
/
2
]
=
w
*
norm
;
kerI
[
ksize
-
1
]
=
norm
;
}
else
if
(
order
==
1
)
{
kerI
[
0
]
=
-
1
;
kerI
[
ksize
/
2
]
=
0
;
kerI
[
ksize
-
1
]
=
1
;
}
Mat
temp
(
kernel
->
rows
,
kernel
->
cols
,
CV_32F
,
&
kerI
[
0
]);
temp
.
copyTo
(
*
kernel
);
}
}
modules/features2d/src/akaze/nldiffusion_functions.h
0 → 100644
View file @
7a594354
#ifndef _NLDIFFUSION_FUNCTIONS_H_
#define _NLDIFFUSION_FUNCTIONS_H_
//******************************************************************************
//******************************************************************************
// Includes
#include "precomp.hpp"
// OpenMP Includes
#ifdef _OPENMP
# include <omp.h>
#endif
//*************************************************************************************
//*************************************************************************************
// Declaration of functions
void
gaussian_2D_convolution
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
const
size_t
&
ksize_x
,
const
size_t
&
ksize_y
,
const
float
&
sigma
);
void
image_derivatives_scharr
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
const
size_t
&
xorder
,
const
size_t
&
yorder
);
void
pm_g1
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
const
float
&
k
);
void
pm_g2
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
const
float
&
k
);
void
weickert_diffusivity
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
const
float
&
k
);
void
charbonnier_diffusivity
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
const
float
&
k
);
float
compute_k_percentile
(
const
cv
::
Mat
&
img
,
const
float
&
perc
,
const
float
&
gscale
,
const
size_t
&
nbins
,
const
size_t
&
ksize_x
,
const
size_t
&
ksize_y
);
void
compute_scharr_derivatives
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
const
size_t
&
xorder
,
const
size_t
&
yorder
,
const
size_t
&
scale
);
void
nld_step_scalar
(
cv
::
Mat
&
Ld
,
const
cv
::
Mat
&
c
,
cv
::
Mat
&
Lstep
,
const
float
&
stepsize
);
void
downsample_image
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
);
void
halfsample_image
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
);
void
compute_derivative_kernels
(
cv
::
OutputArray
kx_
,
cv
::
OutputArray
ky_
,
const
size_t
&
dx
,
const
size_t
&
dy
,
const
size_t
&
scale
);
//*************************************************************************************
//*************************************************************************************
#endif
modules/features2d/src/akaze/utils.cpp
0 → 100644
View file @
7a594354
//=============================================================================
//
// utils.cpp
// Authors: Pablo F. Alcantarilla (1), Jesus Nuevo (2)
// Institutions: Georgia Institute of Technology (1)
// TrueVision Solutions (2)
//
// Date: 15/09/2013
// Email: pablofdezalc@gmail.com
//
// AKAZE Features Copyright 2013, Pablo F. Alcantarilla, Jesus Nuevo
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================
/**
* @file utils.cpp
* @brief Some utilities functions
* @date Sep 15, 2013
* @author Pablo F. Alcantarilla, Jesus Nuevo
*/
#include "precomp.hpp"
#include "utils.h"
// Namespaces
using
namespace
std
;
using
namespace
cv
;
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes the minimum value of a float image
* @param src Input image
* @param value Minimum value
*/
void
compute_min_32F
(
const
cv
::
Mat
&
src
,
float
&
value
)
{
float
aux
=
1000.0
;
for
(
int
i
=
0
;
i
<
src
.
rows
;
i
++
)
{
for
(
int
j
=
0
;
j
<
src
.
cols
;
j
++
)
{
if
(
src
.
at
<
float
>
(
i
,
j
)
<
aux
)
{
aux
=
src
.
at
<
float
>
(
i
,
j
);
}
}
}
value
=
aux
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes the maximum value of a float image
* @param src Input image
* @param value Maximum value
*/
void
compute_max_32F
(
const
cv
::
Mat
&
src
,
float
&
value
)
{
float
aux
=
0.0
;
for
(
int
i
=
0
;
i
<
src
.
rows
;
i
++
)
{
for
(
int
j
=
0
;
j
<
src
.
cols
;
j
++
)
{
if
(
src
.
at
<
float
>
(
i
,
j
)
>
aux
)
{
aux
=
src
.
at
<
float
>
(
i
,
j
);
}
}
}
value
=
aux
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function converts the scale of the input image prior to visualization
* @param src Input/Output image
* @param value Maximum value
*/
void
convert_scale
(
cv
::
Mat
&
src
)
{
float
min_val
=
0
,
max_val
=
0
;
compute_min_32F
(
src
,
min_val
);
src
=
src
-
min_val
;
compute_max_32F
(
src
,
max_val
);
src
=
src
/
max_val
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function copies the input image and converts the scale of the copied
* image prior visualization
* @param src Input image
* @param dst Output image
*/
void
copy_and_convert_scale
(
const
cv
::
Mat
&
src
,
cv
::
Mat
dst
)
{
float
min_val
=
0
,
max_val
=
0
;
src
.
copyTo
(
dst
);
compute_min_32F
(
dst
,
min_val
);
dst
=
dst
-
min_val
;
compute_max_32F
(
dst
,
max_val
);
dst
=
dst
/
max_val
;
}
//*************************************************************************************
//*************************************************************************************
const
size_t
length
=
string
(
"--descriptor_channels"
).
size
()
+
2
;
static
inline
std
::
ostream
&
cout_help
()
{
cout
<<
setw
(
length
);
return
cout
;
}
static
inline
std
::
string
toUpper
(
std
::
string
s
)
{
std
::
transform
(
s
.
begin
(),
s
.
end
(),
s
.
begin
(),
::
toupper
);
return
s
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function shows the possible command line configuration options
*/
void
show_input_options_help
(
int
example
)
{
fflush
(
stdout
);
cout
<<
"A-KAZE Features"
<<
endl
;
cout
<<
"Usage: "
;
if
(
example
==
0
)
{
cout
<<
"./akaze_features -i img.jpg [options]"
<<
endl
;
}
else
if
(
example
==
1
)
{
cout
<<
"./akaze_match img1.jpg img2.pgm homography.txt [options]"
<<
endl
;
}
else
if
(
example
==
2
)
{
cout
<<
"./akaze_compare img1.jpg img2.pgm homography.txt [options]"
<<
endl
;
}
cout
<<
endl
;
cout_help
()
<<
"Options below are not mandatory. Unless specified, default arguments are used."
<<
endl
<<
endl
;
// Justify on the left
cout
<<
left
;
// Generalities
cout_help
()
<<
"--help"
<<
"Show the command line options"
<<
endl
;
cout_help
()
<<
"--verbose "
<<
"Verbosity is required"
<<
endl
;
cout_help
()
<<
endl
;
// Scale-space parameters
cout_help
()
<<
"--soffset"
<<
"Base scale offset (sigma units)"
<<
endl
;
cout_help
()
<<
"--omax"
<<
"Maximum octave of image evolution"
<<
endl
;
cout_help
()
<<
"--nsublevels"
<<
"Number of sublevels per octave"
<<
endl
;
cout_help
()
<<
"--diffusivity"
<<
"Diffusivity function. Possible values:"
<<
endl
;
cout_help
()
<<
" "
<<
"0 -> Perona-Malik, g1 = exp(-|dL|^2/k^2)"
<<
endl
;
cout_help
()
<<
" "
<<
"1 -> Perona-Malik, g2 = 1 / (1 + dL^2 / k^2)"
<<
endl
;
cout_help
()
<<
" "
<<
"2 -> Weickert diffusivity"
<<
endl
;
cout_help
()
<<
" "
<<
"3 -> Charbonnier diffusivity"
<<
endl
;
cout_help
()
<<
endl
;
// Feature detection parameters.
cout_help
()
<<
"--dthreshold"
<<
"Feature detector threshold response for keypoints"
<<
endl
;
cout_help
()
<<
" "
<<
"(0.001 can be a good value)"
<<
endl
;
cout_help
()
<<
endl
;
// Descriptor parameters.
cout_help
()
<<
"--descriptor"
<<
"Descriptor Type. Possible values:"
<<
endl
;
cout_help
()
<<
" "
<<
"0 -> SURF_UPRIGHT"
<<
endl
;
cout_help
()
<<
" "
<<
"1 -> SURF"
<<
endl
;
cout_help
()
<<
" "
<<
"2 -> M-SURF_UPRIGHT,"
<<
endl
;
cout_help
()
<<
" "
<<
"3 -> M-SURF"
<<
endl
;
cout_help
()
<<
" "
<<
"4 -> M-LDB_UPRIGHT"
<<
endl
;
cout_help
()
<<
" "
<<
"5 -> M-LDB"
<<
endl
;
cout_help
()
<<
"--descriptor_channels "
<<
"Descriptor Channels for M-LDB. Valid values: "
<<
endl
;
cout_help
()
<<
" "
<<
"1 -> intensity"
<<
endl
;
cout_help
()
<<
" "
<<
"2 -> intensity + gradient magnitude"
<<
endl
;
cout_help
()
<<
" "
<<
"3 -> intensity + X and Y gradients"
<<
endl
;
cout_help
()
<<
"--descriptor_size"
<<
"Descriptor size for M-LDB in bits."
<<
endl
;
cout_help
()
<<
" "
<<
"0: means the full length descriptor (486)!!"
<<
endl
;
cout_help
()
<<
endl
;
// Save results?
cout_help
()
<<
"--show_results"
<<
"Possible values below:"
<<
endl
;
cout_help
()
<<
" "
<<
"1 -> show detection results."
<<
endl
;
cout_help
()
<<
" "
<<
"0 -> don't show detection results"
<<
endl
;
cout_help
()
<<
endl
;
}
modules/features2d/src/akaze/utils.h
0 → 100644
View file @
7a594354
#ifndef _UTILS_H_
#define _UTILS_H_
//******************************************************************************
//******************************************************************************
// OpenCV Includes
#include "precomp.hpp"
// System Includes
#include <stdlib.h>
#include <stdio.h>
#include <cstdlib>
#include <vector>
#include <fstream>
#include <iostream>
#include <iomanip>
//******************************************************************************
//******************************************************************************
// Stringify common types such as int, double and others.
template
<
typename
T
>
inline
std
::
string
to_string
(
const
T
&
x
)
{
std
::
stringstream
oss
;
oss
<<
x
;
return
oss
.
str
();
}
//******************************************************************************
//******************************************************************************
// Stringify and format integral types as follows:
// to_formatted_string( 1, 2) produces string: '01'
// to_formatted_string( 5, 2) produces string: '05'
// to_formatted_string( 19, 2) produces string: '19'
// to_formatted_string( 19, 3) produces string: '019'
template
<
typename
Integer
>
inline
std
::
string
to_formatted_string
(
Integer
x
,
int
num_digits
)
{
std
::
stringstream
oss
;
oss
<<
std
::
setfill
(
'0'
)
<<
std
::
setw
(
num_digits
)
<<
x
;
return
oss
.
str
();
}
//******************************************************************************
//******************************************************************************
void
compute_min_32F
(
const
cv
::
Mat
&
src
,
float
&
value
);
void
compute_max_32F
(
const
cv
::
Mat
&
src
,
float
&
value
);
void
convert_scale
(
cv
::
Mat
&
src
);
void
copy_and_convert_scale
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
);
#endif
modules/features2d/src/kaze.cpp
0 → 100644
View file @
7a594354
modules/features2d/src/kaze/KAZE.cpp
0 → 100644
View file @
7a594354
//=============================================================================
//
// KAZE.cpp
// Author: Pablo F. Alcantarilla
// Institution: University d'Auvergne
// Address: Clermont Ferrand, France
// Date: 21/01/2012
// Email: pablofdezalc@gmail.com
//
// KAZE Features Copyright 2012, Pablo F. Alcantarilla
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================
/**
* @file KAZE.cpp
* @brief Main class for detecting and describing features in a nonlinear
* scale space
* @date Jan 21, 2012
* @author Pablo F. Alcantarilla
*/
#include "KAZE.h"
// Namespaces
using
namespace
std
;
using
namespace
cv
;
//*******************************************************************************
//*******************************************************************************
/**
* @brief KAZE constructor with input options
* @param options KAZE configuration options
* @note The constructor allocates memory for the nonlinear scale space
*/
KAZE
::
KAZE
(
KAZEOptions
&
options
)
{
soffset_
=
options
.
soffset
;
sderivatives_
=
options
.
sderivatives
;
omax_
=
options
.
omax
;
nsublevels_
=
options
.
nsublevels
;
save_scale_space_
=
options
.
save_scale_space
;
verbosity_
=
options
.
verbosity
;
img_width_
=
options
.
img_width
;
img_height_
=
options
.
img_height
;
dthreshold_
=
options
.
dthreshold
;
diffusivity_
=
options
.
diffusivity
;
descriptor_mode_
=
options
.
descriptor
;
use_fed_
=
options
.
use_fed
;
use_upright_
=
options
.
upright
;
use_extended_
=
options
.
extended
;
kcontrast_
=
DEFAULT_KCONTRAST
;
ncycles_
=
0
;
reordering_
=
true
;
tkcontrast_
=
0.0
;
tnlscale_
=
0.0
;
tdetector_
=
0.0
;
tmderivatives_
=
0.0
;
tdresponse_
=
0.0
;
tdescriptor_
=
0.0
;
// Now allocate memory for the evolution
Allocate_Memory_Evolution
();
}
//*******************************************************************************
//*******************************************************************************
/**
* @brief KAZE destructor
*/
KAZE
::~
KAZE
(
void
)
{
evolution_
.
clear
();
}
//*******************************************************************************
//*******************************************************************************
/**
* @brief This method allocates the memory for the nonlinear diffusion evolution
*/
void
KAZE
::
Allocate_Memory_Evolution
(
void
)
{
// Allocate the dimension of the matrices for the evolution
for
(
int
i
=
0
;
i
<=
omax_
-
1
;
i
++
)
{
for
(
int
j
=
0
;
j
<=
nsublevels_
-
1
;
j
++
)
{
TEvolution
aux
;
aux
.
Lx
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Ly
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Lxx
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Lxy
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Lyy
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Lflow
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Lt
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Lsmooth
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Lstep
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
Ldet
=
cv
::
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
aux
.
esigma
=
soffset_
*
pow
((
float
)
2.0
,(
float
)(
j
)
/
(
float
)(
nsublevels_
)
+
i
);
aux
.
etime
=
0.5
*
(
aux
.
esigma
*
aux
.
esigma
);
aux
.
sigma_size
=
fRound
(
aux
.
esigma
);
aux
.
octave
=
i
;
aux
.
sublevel
=
j
;
evolution_
.
push_back
(
aux
);
}
}
// Allocate memory for the FED number of cycles and time steps
if
(
use_fed_
)
{
for
(
size_t
i
=
1
;
i
<
evolution_
.
size
();
i
++
)
{
int
naux
=
0
;
vector
<
float
>
tau
;
float
ttime
=
0.0
;
ttime
=
evolution_
[
i
].
etime
-
evolution_
[
i
-
1
].
etime
;
naux
=
fed_tau_by_process_time
(
ttime
,
1
,
0.25
,
reordering_
,
tau
);
nsteps_
.
push_back
(
naux
);
tsteps_
.
push_back
(
tau
);
ncycles_
++
;
}
}
else
{
// Allocate memory for the auxiliary variables that are used in the AOS scheme
Ltx_
=
Mat
::
zeros
(
img_width_
,
img_height_
,
CV_32F
);
Lty_
=
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
px_
=
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
py_
=
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
ax_
=
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
ay_
=
Mat
::
zeros
(
img_height_
,
img_width_
,
CV_32F
);
bx_
=
Mat
::
zeros
(
img_height_
-
1
,
img_width_
,
CV_32F
);
by_
=
Mat
::
zeros
(
img_height_
-
1
,
img_width_
,
CV_32F
);
qr_
=
Mat
::
zeros
(
img_height_
-
1
,
img_width_
,
CV_32F
);
qc_
=
Mat
::
zeros
(
img_height_
,
img_width_
-
1
,
CV_32F
);
}
}
//*******************************************************************************
//*******************************************************************************
/**
* @brief This method creates the nonlinear scale space for a given image
* @param img Input image for which the nonlinear scale space needs to be created
* @return 0 if the nonlinear scale space was created successfully. -1 otherwise
*/
int
KAZE
::
Create_Nonlinear_Scale_Space
(
const
cv
::
Mat
&
img
)
{
double
t2
=
0.0
,
t1
=
0.0
;
if
(
evolution_
.
size
()
==
0
)
{
cout
<<
"Error generating the nonlinear scale space!!"
<<
endl
;
cout
<<
"Firstly you need to call KAZE::Allocate_Memory_Evolution()"
<<
endl
;
return
-
1
;
}
t1
=
getTickCount
();
// Copy the original image to the first level of the evolution
img
.
copyTo
(
evolution_
[
0
].
Lt
);
gaussian_2D_convolution
(
evolution_
[
0
].
Lt
,
evolution_
[
0
].
Lt
,
0
,
0
,
soffset_
);
gaussian_2D_convolution
(
evolution_
[
0
].
Lt
,
evolution_
[
0
].
Lsmooth
,
0
,
0
,
sderivatives_
);
// Firstly compute the kcontrast factor
Compute_KContrast
(
evolution_
[
0
].
Lt
,
KCONTRAST_PERCENTILE
);
t2
=
getTickCount
();
tkcontrast_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
if
(
verbosity_
==
true
)
{
cout
<<
"Computed image evolution step. Evolution time: "
<<
evolution_
[
0
].
etime
<<
" Sigma: "
<<
evolution_
[
0
].
esigma
<<
endl
;
}
// Now generate the rest of evolution levels
for
(
size_t
i
=
1
;
i
<
evolution_
.
size
();
i
++
)
{
evolution_
[
i
-
1
].
Lt
.
copyTo
(
evolution_
[
i
].
Lt
);
gaussian_2D_convolution
(
evolution_
[
i
-
1
].
Lt
,
evolution_
[
i
].
Lsmooth
,
0
,
0
,
sderivatives_
);
// Compute the Gaussian derivatives Lx and Ly
Scharr
(
evolution_
[
i
].
Lsmooth
,
evolution_
[
i
].
Lx
,
CV_32F
,
1
,
0
,
1
,
0
,
BORDER_DEFAULT
);
Scharr
(
evolution_
[
i
].
Lsmooth
,
evolution_
[
i
].
Ly
,
CV_32F
,
0
,
1
,
1
,
0
,
BORDER_DEFAULT
);
// Compute the conductivity equation
if
(
diffusivity_
==
0
)
{
pm_g1
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lflow
,
kcontrast_
);
}
else
if
(
diffusivity_
==
1
)
{
pm_g2
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lflow
,
kcontrast_
);
}
else
if
(
diffusivity_
==
2
)
{
weickert_diffusivity
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lflow
,
kcontrast_
);
}
// Perform FED n inner steps
if
(
use_fed_
)
{
for
(
int
j
=
0
;
j
<
nsteps_
[
i
-
1
];
j
++
)
{
nld_step_scalar
(
evolution_
[
i
].
Lt
,
evolution_
[
i
].
Lflow
,
evolution_
[
i
].
Lstep
,
tsteps_
[
i
-
1
][
j
]);
}
}
else
{
// Perform the evolution step with AOS
AOS_Step_Scalar
(
evolution_
[
i
].
Lt
,
evolution_
[
i
-
1
].
Lt
,
evolution_
[
i
].
Lflow
,
evolution_
[
i
].
etime
-
evolution_
[
i
-
1
].
etime
);
}
if
(
verbosity_
==
true
)
{
cout
<<
"Computed image evolution step "
<<
i
<<
" Evolution time: "
<<
evolution_
[
i
].
etime
<<
" Sigma: "
<<
evolution_
[
i
].
esigma
<<
endl
;
}
}
t2
=
getTickCount
();
tnlscale_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
return
0
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the k contrast factor
* @param img Input image
* @param kpercentile Percentile of the gradient histogram
*/
void
KAZE
::
Compute_KContrast
(
const
cv
::
Mat
&
img
,
const
float
&
kpercentile
)
{
if
(
verbosity_
==
true
)
{
cout
<<
"Computing Kcontrast factor."
<<
endl
;
}
if
(
COMPUTE_KCONTRAST
==
true
)
{
kcontrast_
=
compute_k_percentile
(
img
,
kpercentile
,
sderivatives_
,
KCONTRAST_NBINS
,
0
,
0
);
}
if
(
verbosity_
==
true
)
{
cout
<<
"kcontrast = "
<<
kcontrast_
<<
endl
;
cout
<<
endl
<<
"Now computing the nonlinear scale space!!"
<<
endl
;
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the multiscale derivatives for the nonlinear scale space
*/
void
KAZE
::
Compute_Multiscale_Derivatives
(
void
)
{
double
t2
=
0.0
,
t1
=
0.0
;
t1
=
getTickCount
();
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
evolution_
.
size
();
i
++
)
{
if
(
verbosity_
==
true
)
{
cout
<<
"Computing multiscale derivatives. Evolution time: "
<<
evolution_
[
i
].
etime
<<
" Step (pixels): "
<<
evolution_
[
i
].
sigma_size
<<
endl
;
}
// Compute multiscale derivatives for the detector
compute_scharr_derivatives
(
evolution_
[
i
].
Lsmooth
,
evolution_
[
i
].
Lx
,
1
,
0
,
evolution_
[
i
].
sigma_size
);
compute_scharr_derivatives
(
evolution_
[
i
].
Lsmooth
,
evolution_
[
i
].
Ly
,
0
,
1
,
evolution_
[
i
].
sigma_size
);
compute_scharr_derivatives
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Lxx
,
1
,
0
,
evolution_
[
i
].
sigma_size
);
compute_scharr_derivatives
(
evolution_
[
i
].
Ly
,
evolution_
[
i
].
Lyy
,
0
,
1
,
evolution_
[
i
].
sigma_size
);
compute_scharr_derivatives
(
evolution_
[
i
].
Lx
,
evolution_
[
i
].
Lxy
,
0
,
1
,
evolution_
[
i
].
sigma_size
);
evolution_
[
i
].
Lx
=
evolution_
[
i
].
Lx
*
((
evolution_
[
i
].
sigma_size
));
evolution_
[
i
].
Ly
=
evolution_
[
i
].
Ly
*
((
evolution_
[
i
].
sigma_size
));
evolution_
[
i
].
Lxx
=
evolution_
[
i
].
Lxx
*
((
evolution_
[
i
].
sigma_size
)
*
(
evolution_
[
i
].
sigma_size
));
evolution_
[
i
].
Lxy
=
evolution_
[
i
].
Lxy
*
((
evolution_
[
i
].
sigma_size
)
*
(
evolution_
[
i
].
sigma_size
));
evolution_
[
i
].
Lyy
=
evolution_
[
i
].
Lyy
*
((
evolution_
[
i
].
sigma_size
)
*
(
evolution_
[
i
].
sigma_size
));
}
t2
=
getTickCount
();
tmderivatives_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the feature detector response for the nonlinear scale space
* @note We use the Hessian determinant as feature detector
*/
void
KAZE
::
Compute_Detector_Response
(
void
)
{
double
t2
=
0.0
,
t1
=
0.0
;
float
lxx
=
0.0
,
lxy
=
0.0
,
lyy
=
0.0
;
t1
=
getTickCount
();
// Firstly compute the multiscale derivatives
Compute_Multiscale_Derivatives
();
for
(
size_t
i
=
0
;
i
<
evolution_
.
size
();
i
++
)
{
// Determinant of the Hessian
if
(
verbosity_
==
true
)
{
cout
<<
"Computing detector response. Determinant of Hessian. Evolution time: "
<<
evolution_
[
i
].
etime
<<
endl
;
}
for
(
int
ix
=
0
;
ix
<
img_height_
;
ix
++
)
{
for
(
int
jx
=
0
;
jx
<
img_width_
;
jx
++
)
{
lxx
=
*
(
evolution_
[
i
].
Lxx
.
ptr
<
float
>
(
ix
)
+
jx
);
lxy
=
*
(
evolution_
[
i
].
Lxy
.
ptr
<
float
>
(
ix
)
+
jx
);
lyy
=
*
(
evolution_
[
i
].
Lyy
.
ptr
<
float
>
(
ix
)
+
jx
);
*
(
evolution_
[
i
].
Ldet
.
ptr
<
float
>
(
ix
)
+
jx
)
=
(
lxx
*
lyy
-
lxy
*
lxy
);
}
}
}
t2
=
getTickCount
();
tdresponse_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method selects interesting keypoints through the nonlinear scale space
* @param kpts Vector of keypoints
*/
void
KAZE
::
Feature_Detection
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
)
{
double
t2
=
0.0
,
t1
=
0.0
;
t1
=
getTickCount
();
// Firstly compute the detector response for each pixel and scale level
Compute_Detector_Response
();
// Find scale space extrema
Determinant_Hessian_Parallel
(
kpts
);
// Perform some subpixel refinement
Do_Subpixel_Refinement
(
kpts
);
t2
=
getTickCount
();
tdetector_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method performs the detection of keypoints by using the normalized
* score of the Hessian determinant through the nonlinear scale space
* @param kpts Vector of keypoints
* @note We compute features for each of the nonlinear scale space level in a different processing thread
*/
void
KAZE
::
Determinant_Hessian_Parallel
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
)
{
int
level
=
0
;
float
dist
=
0.0
,
smax
=
3.0
;
int
npoints
=
0
,
id_repeated
=
0
;
int
left_x
=
0
,
right_x
=
0
,
up_y
=
0
,
down_y
=
0
;
bool
is_extremum
=
false
,
is_repeated
=
false
,
is_out
=
false
;
// Delete the memory of the vector of keypoints vectors
// In case we use the same kaze object for multiple images
for
(
size_t
i
=
0
;
i
<
kpts_par_
.
size
();
i
++
)
{
vector
<
KeyPoint
>
().
swap
(
kpts_par_
[
i
]);
}
kpts_par_
.
clear
();
vector
<
KeyPoint
>
aux
;
// Allocate memory for the vector of vectors
for
(
size_t
i
=
1
;
i
<
evolution_
.
size
()
-
1
;
i
++
)
{
kpts_par_
.
push_back
(
aux
);
}
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
1
;
i
<
evolution_
.
size
()
-
1
;
i
++
)
{
Find_Extremum_Threading
(
i
);
}
// Now fill the vector of keypoints!!!
for
(
size_t
i
=
0
;
i
<
kpts_par_
.
size
();
i
++
)
{
for
(
size_t
j
=
0
;
j
<
kpts_par_
[
i
].
size
();
j
++
)
{
level
=
i
+
1
;
is_extremum
=
true
;
is_repeated
=
false
;
is_out
=
false
;
// Check in case we have the same point as maxima in previous evolution levels
for
(
size_t
ik
=
0
;
ik
<
kpts
.
size
();
ik
++
)
{
if
(
kpts
[
ik
].
class_id
==
level
||
kpts
[
ik
].
class_id
==
level
+
1
||
kpts
[
ik
].
class_id
==
level
-
1
)
{
dist
=
pow
(
kpts_par_
[
i
][
j
].
pt
.
x
-
kpts
[
ik
].
pt
.
x
,
2
)
+
pow
(
kpts_par_
[
i
][
j
].
pt
.
y
-
kpts
[
ik
].
pt
.
y
,
2
);
if
(
dist
<
evolution_
[
level
].
sigma_size
*
evolution_
[
level
].
sigma_size
)
{
if
(
kpts_par_
[
i
][
j
].
response
>
kpts
[
ik
].
response
)
{
id_repeated
=
ik
;
is_repeated
=
true
;
}
else
{
is_extremum
=
false
;
}
break
;
}
}
}
if
(
is_extremum
==
true
)
{
// Check that the point is under the image limits for the descriptor computation
left_x
=
fRound
(
kpts_par_
[
i
][
j
].
pt
.
x
-
smax
*
kpts_par_
[
i
][
j
].
size
);
right_x
=
fRound
(
kpts_par_
[
i
][
j
].
pt
.
x
+
smax
*
kpts_par_
[
i
][
j
].
size
);
up_y
=
fRound
(
kpts_par_
[
i
][
j
].
pt
.
y
-
smax
*
kpts_par_
[
i
][
j
].
size
);
down_y
=
fRound
(
kpts_par_
[
i
][
j
].
pt
.
y
+
smax
*
kpts_par_
[
i
][
j
].
size
);
if
(
left_x
<
0
||
right_x
>=
evolution_
[
level
].
Ldet
.
cols
||
up_y
<
0
||
down_y
>=
evolution_
[
level
].
Ldet
.
rows
)
{
is_out
=
true
;
}
is_out
=
false
;
if
(
is_out
==
false
)
{
if
(
is_repeated
==
false
)
{
kpts
.
push_back
(
kpts_par_
[
i
][
j
]);
npoints
++
;
}
else
{
kpts
[
id_repeated
]
=
kpts_par_
[
i
][
j
];
}
}
}
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method is called by the thread which is responsible of finding extrema
* at a given nonlinear scale level
* @param level Index in the nonlinear scale space evolution
*/
void
KAZE
::
Find_Extremum_Threading
(
const
int
&
level
)
{
float
value
=
0.0
;
bool
is_extremum
=
false
;
for
(
int
ix
=
1
;
ix
<
img_height_
-
1
;
ix
++
)
{
for
(
int
jx
=
1
;
jx
<
img_width_
-
1
;
jx
++
)
{
is_extremum
=
false
;
value
=
*
(
evolution_
[
level
].
Ldet
.
ptr
<
float
>
(
ix
)
+
jx
);
// Filter the points with the detector threshold
if
(
value
>
dthreshold_
&&
value
>=
DEFAULT_MIN_DETECTOR_THRESHOLD
)
{
if
(
value
>=
*
(
evolution_
[
level
].
Ldet
.
ptr
<
float
>
(
ix
)
+
jx
-
1
))
{
// First check on the same scale
if
(
check_maximum_neighbourhood
(
evolution_
[
level
].
Ldet
,
1
,
value
,
ix
,
jx
,
1
))
{
// Now check on the lower scale
if
(
check_maximum_neighbourhood
(
evolution_
[
level
-
1
].
Ldet
,
1
,
value
,
ix
,
jx
,
0
))
{
// Now check on the upper scale
if
(
check_maximum_neighbourhood
(
evolution_
[
level
+
1
].
Ldet
,
1
,
value
,
ix
,
jx
,
0
))
{
is_extremum
=
true
;
}
}
}
}
}
// Add the point of interest!!
if
(
is_extremum
==
true
)
{
KeyPoint
point
;
point
.
pt
.
x
=
jx
;
point
.
pt
.
y
=
ix
;
point
.
response
=
fabs
(
value
);
point
.
size
=
evolution_
[
level
].
esigma
;
point
.
octave
=
evolution_
[
level
].
octave
;
point
.
class_id
=
level
;
// We use the angle field for the sublevel value
// Then, we will replace this angle field with the main orientation
point
.
angle
=
evolution_
[
level
].
sublevel
;
kpts_par_
[
level
-
1
].
push_back
(
point
);
}
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method performs subpixel refinement of the detected keypoints
* @param kpts Vector of detected keypoints
*/
void
KAZE
::
Do_Subpixel_Refinement
(
std
::
vector
<
cv
::
KeyPoint
>
&
kpts
)
{
int
step
=
1
;
int
x
=
0
,
y
=
0
;
float
Dx
=
0.0
,
Dy
=
0.0
,
Ds
=
0.0
,
dsc
=
0.0
;
float
Dxx
=
0.0
,
Dyy
=
0.0
,
Dss
=
0.0
,
Dxy
=
0.0
,
Dxs
=
0.0
,
Dys
=
0.0
;
Mat
A
=
Mat
::
zeros
(
3
,
3
,
CV_32F
);
Mat
b
=
Mat
::
zeros
(
3
,
1
,
CV_32F
);
Mat
dst
=
Mat
::
zeros
(
3
,
1
,
CV_32F
);
double
t2
=
0.0
,
t1
=
0.0
;
t1
=
cv
::
getTickCount
();
vector
<
KeyPoint
>
kpts_
(
kpts
);
for
(
size_t
i
=
0
;
i
<
kpts_
.
size
();
i
++
)
{
x
=
kpts_
[
i
].
pt
.
x
;
y
=
kpts_
[
i
].
pt
.
y
;
// Compute the gradient
Dx
=
(
1.0
/
(
2.0
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
+
step
)
-*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
-
step
));
Dy
=
(
1.0
/
(
2.0
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
+
step
)
+
x
)
-*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
-
step
)
+
x
));
Ds
=
0.5
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
+
1
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
)
-*
(
evolution_
[
kpts_
[
i
].
class_id
-
1
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
));
// Compute the Hessian
Dxx
=
(
1.0
/
(
step
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
+
step
)
+
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
-
step
)
-
2.0
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
)));
Dyy
=
(
1.0
/
(
step
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
+
step
)
+
x
)
+
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
-
step
)
+
x
)
-
2.0
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
)));
Dss
=
*
(
evolution_
[
kpts_
[
i
].
class_id
+
1
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
)
+
*
(
evolution_
[
kpts_
[
i
].
class_id
-
1
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
)
-
2.0
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
));
Dxy
=
(
1.0
/
(
4.0
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
+
step
)
+
x
+
step
)
+
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
-
step
)
+
x
-
step
)))
-
(
1.0
/
(
4.0
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
-
step
)
+
x
+
step
)
+
(
*
(
evolution_
[
kpts_
[
i
].
class_id
].
Ldet
.
ptr
<
float
>
(
y
+
step
)
+
x
-
step
)));
Dxs
=
(
1.0
/
(
4.0
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
+
1
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
+
step
)
+
(
*
(
evolution_
[
kpts_
[
i
].
class_id
-
1
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
-
step
)))
-
(
1.0
/
(
4.0
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
+
1
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
-
step
)
+
(
*
(
evolution_
[
kpts_
[
i
].
class_id
-
1
].
Ldet
.
ptr
<
float
>
(
y
)
+
x
+
step
)));
Dys
=
(
1.0
/
(
4.0
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
+
1
].
Ldet
.
ptr
<
float
>
(
y
+
step
)
+
x
)
+
(
*
(
evolution_
[
kpts_
[
i
].
class_id
-
1
].
Ldet
.
ptr
<
float
>
(
y
-
step
)
+
x
)))
-
(
1.0
/
(
4.0
*
step
))
*
(
*
(
evolution_
[
kpts_
[
i
].
class_id
+
1
].
Ldet
.
ptr
<
float
>
(
y
-
step
)
+
x
)
+
(
*
(
evolution_
[
kpts_
[
i
].
class_id
-
1
].
Ldet
.
ptr
<
float
>
(
y
+
step
)
+
x
)));
// Solve the linear system
*
(
A
.
ptr
<
float
>
(
0
))
=
Dxx
;
*
(
A
.
ptr
<
float
>
(
1
)
+
1
)
=
Dyy
;
*
(
A
.
ptr
<
float
>
(
2
)
+
2
)
=
Dss
;
*
(
A
.
ptr
<
float
>
(
0
)
+
1
)
=
*
(
A
.
ptr
<
float
>
(
1
))
=
Dxy
;
*
(
A
.
ptr
<
float
>
(
0
)
+
2
)
=
*
(
A
.
ptr
<
float
>
(
2
))
=
Dxs
;
*
(
A
.
ptr
<
float
>
(
1
)
+
2
)
=
*
(
A
.
ptr
<
float
>
(
2
)
+
1
)
=
Dys
;
*
(
b
.
ptr
<
float
>
(
0
))
=
-
Dx
;
*
(
b
.
ptr
<
float
>
(
1
))
=
-
Dy
;
*
(
b
.
ptr
<
float
>
(
2
))
=
-
Ds
;
solve
(
A
,
b
,
dst
,
DECOMP_LU
);
if
(
fabs
(
*
(
dst
.
ptr
<
float
>
(
0
)))
<=
1.0
&&
fabs
(
*
(
dst
.
ptr
<
float
>
(
1
)))
<=
1.0
&&
fabs
(
*
(
dst
.
ptr
<
float
>
(
2
)))
<=
1.0
)
{
kpts_
[
i
].
pt
.
x
+=
*
(
dst
.
ptr
<
float
>
(
0
));
kpts_
[
i
].
pt
.
y
+=
*
(
dst
.
ptr
<
float
>
(
1
));
dsc
=
kpts_
[
i
].
octave
+
(
kpts_
[
i
].
angle
+*
(
dst
.
ptr
<
float
>
(
2
)))
/
((
float
)(
nsublevels_
));
// In OpenCV the size of a keypoint is the diameter!!
kpts_
[
i
].
size
=
2.0
*
soffset_
*
pow
((
float
)
2.0
,
dsc
);
kpts_
[
i
].
angle
=
0.0
;
}
// Set the points to be deleted after the for loop
else
{
kpts_
[
i
].
response
=
-
1
;
}
}
// Clear the vector of keypoints
kpts
.
clear
();
for
(
size_t
i
=
0
;
i
<
kpts_
.
size
();
i
++
)
{
if
(
kpts_
[
i
].
response
!=
-
1
)
{
kpts
.
push_back
(
kpts_
[
i
]);
}
}
t2
=
getTickCount
();
tsubpixel_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method performs feature suppression based on 2D distance
* @param kpts Vector of keypoints
* @param mdist Maximum distance in pixels
*/
void
KAZE
::
Feature_Suppression_Distance
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
,
const
float
&
mdist
)
{
vector
<
KeyPoint
>
aux
;
vector
<
int
>
to_delete
;
float
dist
=
0.0
,
x1
=
0.0
,
y1
=
0.0
,
x2
=
0.0
,
y2
=
0.0
;
bool
found
=
false
;
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
x1
=
kpts
[
i
].
pt
.
x
;
y1
=
kpts
[
i
].
pt
.
y
;
for
(
size_t
j
=
i
+
1
;
j
<
kpts
.
size
();
j
++
)
{
x2
=
kpts
[
j
].
pt
.
x
;
y2
=
kpts
[
j
].
pt
.
y
;
dist
=
sqrt
(
pow
(
x1
-
x2
,
2
)
+
pow
(
y1
-
y2
,
2
));
if
(
dist
<
mdist
)
{
if
(
fabs
(
kpts
[
i
].
response
)
>=
fabs
(
kpts
[
j
].
response
))
{
to_delete
.
push_back
(
j
);
}
else
{
to_delete
.
push_back
(
i
);
break
;
}
}
}
}
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
found
=
false
;
for
(
size_t
j
=
0
;
j
<
to_delete
.
size
();
j
++
)
{
if
(
i
==
(
size_t
)(
to_delete
[
j
]))
{
found
=
true
;
break
;
}
}
if
(
found
==
false
)
{
aux
.
push_back
(
kpts
[
i
]);
}
}
kpts
.
clear
();
kpts
=
aux
;
aux
.
clear
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the set of descriptors through the nonlinear scale space
* @param kpts Vector of keypoints
* @param desc Matrix with the feature descriptors
*/
void
KAZE
::
Feature_Description
(
std
::
vector
<
cv
::
KeyPoint
>
&
kpts
,
cv
::
Mat
&
desc
)
{
double
t2
=
0.0
,
t1
=
0.0
;
t1
=
getTickCount
();
// Allocate memory for the matrix of descriptors
if
(
use_extended_
==
true
)
{
desc
=
Mat
::
zeros
(
kpts
.
size
(),
128
,
CV_32FC1
);
}
else
{
desc
=
Mat
::
zeros
(
kpts
.
size
(),
64
,
CV_32FC1
);
}
if
(
use_upright_
==
true
)
{
if
(
use_extended_
==
false
)
{
if
(
descriptor_mode_
==
0
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
kpts
[
i
].
angle
=
0.0
;
Get_SURF_Upright_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
else
if
(
descriptor_mode_
==
1
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
kpts
[
i
].
angle
=
0.0
;
Get_MSURF_Upright_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
else
if
(
descriptor_mode_
==
2
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
kpts
[
i
].
angle
=
0.0
;
Get_GSURF_Upright_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
}
else
{
if
(
descriptor_mode_
==
0
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
kpts
[
i
].
angle
=
0.0
;
Get_SURF_Upright_Descriptor_128
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
else
if
(
descriptor_mode_
==
1
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
kpts
[
i
].
angle
=
0.0
;
Get_MSURF_Upright_Descriptor_128
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
else
if
(
descriptor_mode_
==
2
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
kpts
[
i
].
angle
=
0.0
;
Get_GSURF_Upright_Descriptor_128
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
}
}
else
{
if
(
use_extended_
==
false
)
{
if
(
descriptor_mode_
==
0
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
Get_SURF_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
else
if
(
descriptor_mode_
==
1
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
Get_MSURF_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
else
if
(
descriptor_mode_
==
2
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
Get_GSURF_Descriptor_64
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
}
else
{
if
(
descriptor_mode_
==
0
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
Get_SURF_Descriptor_128
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
else
if
(
descriptor_mode_
==
1
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
Get_MSURF_Descriptor_128
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
else
if
(
descriptor_mode_
==
2
)
{
#ifdef _OPENMP
#pragma omp parallel for
#endif
for
(
size_t
i
=
0
;
i
<
kpts
.
size
();
i
++
)
{
Compute_Main_Orientation_SURF
(
kpts
[
i
]);
Get_GSURF_Descriptor_128
(
kpts
[
i
],
desc
.
ptr
<
float
>
(
i
));
}
}
}
}
t2
=
getTickCount
();
tdescriptor_
=
1000.0
*
(
t2
-
t1
)
/
getTickFrequency
();
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the main orientation for a given keypoint
* @param kpt Input keypoint
* @note The orientation is computed using a similar approach as described in the
* original SURF method. See Bay et al., Speeded Up Robust Features, ECCV 2006
*/
void
KAZE
::
Compute_Main_Orientation_SURF
(
cv
::
KeyPoint
&
kpt
)
{
int
ix
=
0
,
iy
=
0
,
idx
=
0
,
s
=
0
,
level
=
0
;
float
xf
=
0.0
,
yf
=
0.0
,
gweight
=
0.0
;
vector
<
float
>
resX
(
109
),
resY
(
109
),
Ang
(
109
);
// Variables for computing the dominant direction
float
sumX
=
0.0
,
sumY
=
0.0
,
max
=
0.0
,
ang1
=
0.0
,
ang2
=
0.0
;
// Get the information from the keypoint
xf
=
kpt
.
pt
.
x
;
yf
=
kpt
.
pt
.
y
;
level
=
kpt
.
class_id
;
s
=
fRound
(
kpt
.
size
/
2.0
);
// Calculate derivatives responses for points within radius of 6*scale
for
(
int
i
=
-
6
;
i
<=
6
;
++
i
)
{
for
(
int
j
=
-
6
;
j
<=
6
;
++
j
)
{
if
(
i
*
i
+
j
*
j
<
36
)
{
iy
=
fRound
(
yf
+
j
*
s
);
ix
=
fRound
(
xf
+
i
*
s
);
if
(
iy
>=
0
&&
iy
<
img_height_
&&
ix
>=
0
&&
ix
<
img_width_
)
{
gweight
=
gaussian
(
iy
-
yf
,
ix
-
xf
,
2.5
*
s
);
resX
[
idx
]
=
gweight
*
(
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
iy
)
+
ix
));
resY
[
idx
]
=
gweight
*
(
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
iy
)
+
ix
));
}
else
{
resX
[
idx
]
=
0.0
;
resY
[
idx
]
=
0.0
;
}
Ang
[
idx
]
=
getAngle
(
resX
[
idx
],
resY
[
idx
]);
++
idx
;
}
}
}
// Loop slides pi/3 window around feature point
for
(
ang1
=
0
;
ang1
<
2.0
*
CV_PI
;
ang1
+=
0.15
f
)
{
ang2
=
(
ang1
+
CV_PI
/
3.0
f
>
2.0
*
CV_PI
?
ang1
-
5.0
f
*
CV_PI
/
3.0
f
:
ang1
+
CV_PI
/
3.0
f
);
sumX
=
sumY
=
0.
f
;
for
(
size_t
k
=
0
;
k
<
Ang
.
size
();
++
k
)
{
// Get angle from the x-axis of the sample point
const
float
&
ang
=
Ang
[
k
];
// Determine whether the point is within the window
if
(
ang1
<
ang2
&&
ang1
<
ang
&&
ang
<
ang2
)
{
sumX
+=
resX
[
k
];
sumY
+=
resY
[
k
];
}
else
if
(
ang2
<
ang1
&&
((
ang
>
0
&&
ang
<
ang2
)
||
(
ang
>
ang1
&&
ang
<
2.0
*
CV_PI
)))
{
sumX
+=
resX
[
k
];
sumY
+=
resY
[
k
];
}
}
// if the vector produced from this window is longer than all
// previous vectors then this forms the new dominant direction
if
(
sumX
*
sumX
+
sumY
*
sumY
>
max
)
{
// store largest orientation
max
=
sumX
*
sumX
+
sumY
*
sumY
;
kpt
.
angle
=
getAngle
(
sumX
,
sumY
);
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the upright descriptor (no rotation invariant)
* of the provided keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional
* Gaussian weighting is performed. The descriptor is inspired from Bay et al.,
* Speeded Up Robust Features, ECCV, 2006
*/
void
KAZE
::
Get_SURF_Upright_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
sample_x
=
0.0
,
sample_y
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
level
=
kpt
.
class_id
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
sample_y
=
k
*
scale
+
yf
;
sample_x
=
l
*
scale
+
xf
;
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Sum the derivatives to the cumulative descriptor
dx
+=
rx
;
dy
+=
ry
;
mdx
+=
fabs
(
rx
);
mdy
+=
fabs
(
ry
);
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dx
;
desc
[
dcount
++
]
=
dy
;
desc
[
dcount
++
]
=
mdx
;
desc
[
dcount
++
]
=
mdy
;
// Store the current length^2 of the vector
len
+=
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the descriptor of the provided keypoint given the
* main orientation
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional
* Gaussian weighting is performed. The descriptor is inspired from Bay et al.,
* Speeded Up Robust Features, ECCV, 2006
*/
void
KAZE
::
Get_SURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rrx
=
0.0
,
rry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point on the rotated axis
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Get the x and y derivatives on the rotated axis
rry
=
rx
*
co
+
ry
*
si
;
rrx
=
-
rx
*
si
+
ry
*
co
;
// Sum the derivatives to the cumulative descriptor
dx
+=
rrx
;
dy
+=
rry
;
mdx
+=
fabs
(
rrx
);
mdy
+=
fabs
(
rry
);
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dx
;
desc
[
dcount
++
]
=
dy
;
desc
[
dcount
++
]
=
mdx
;
desc
[
dcount
++
]
=
mdy
;
// Store the current length^2 of the vector
len
+=
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the upright descriptor (not rotation invariant) of
* the provided keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 24 s x 24 s. Descriptor Length 64. The descriptor is inspired
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
* ECCV 2008
*/
void
KAZE
::
Get_MSURF_Upright_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
,
gauss_s1
=
0.0
,
gauss_s2
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
ys
=
0.0
,
xs
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
;
int
x1
=
0
,
y1
=
0
,
sample_step
=
0
,
pattern_size
=
0
;
int
x2
=
0
,
y2
=
0
,
kx
=
0
,
ky
=
0
,
i
=
0
,
j
=
0
,
dcount
=
0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Subregion centers for the 4x4 gaussian weighting
float
cx
=
-
0.5
,
cy
=
0.5
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
12
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
level
=
kpt
.
class_id
;
i
=
-
8
;
// Calculate descriptor for this interest point
// Area of size 24 s x 24 s
while
(
i
<
pattern_size
)
{
j
=
-
8
;
i
=
i
-
4
;
cx
+=
1.0
;
cy
=
-
0.5
;
while
(
j
<
pattern_size
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
cy
+=
1.0
;
j
=
j
-
4
;
ky
=
i
+
sample_step
;
kx
=
j
+
sample_step
;
ys
=
yf
+
(
ky
*
scale
);
xs
=
xf
+
(
kx
*
scale
);
for
(
int
k
=
i
;
k
<
i
+
9
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
9
;
l
++
)
{
sample_y
=
k
*
scale
+
yf
;
sample_x
=
l
*
scale
+
xf
;
//Get the gaussian weighted x and y responses
gauss_s1
=
gaussian
(
xs
-
sample_x
,
ys
-
sample_y
,
2.5
*
scale
);
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
rx
=
gauss_s1
*
rx
;
ry
=
gauss_s1
*
ry
;
// Sum the derivatives to the cumulative descriptor
dx
+=
rx
;
dy
+=
ry
;
mdx
+=
fabs
(
rx
);
mdy
+=
fabs
(
ry
);
}
}
// Add the values to the descriptor vector
gauss_s2
=
gaussian
(
cx
-
2.0
f
,
cy
-
2.0
f
,
1.5
f
);
desc
[
dcount
++
]
=
dx
*
gauss_s2
;
desc
[
dcount
++
]
=
dy
*
gauss_s2
;
desc
[
dcount
++
]
=
mdx
*
gauss_s2
;
desc
[
dcount
++
]
=
mdy
*
gauss_s2
;
len
+=
(
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
)
*
gauss_s2
*
gauss_s2
;
j
+=
9
;
}
i
+=
9
;
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the descriptor of the provided keypoint given the
* main orientation of the keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 24 s x 24 s. Descriptor Length 64. The descriptor is inspired
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
* ECCV 2008
*/
void
KAZE
::
Get_MSURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
,
gauss_s1
=
0.0
,
gauss_s2
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rrx
=
0.0
,
rry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
ys
=
0.0
,
xs
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
;
int
kx
=
0
,
ky
=
0
,
i
=
0
,
j
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Subregion centers for the 4x4 gaussian weighting
float
cx
=
-
0.5
,
cy
=
0.5
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
12
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
i
=
-
8
;
// Calculate descriptor for this interest point
// Area of size 24 s x 24 s
while
(
i
<
pattern_size
)
{
j
=
-
8
;
i
=
i
-
4
;
cx
+=
1.0
;
cy
=
-
0.5
;
while
(
j
<
pattern_size
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
cy
+=
1.0
;
j
=
j
-
4
;
ky
=
i
+
sample_step
;
kx
=
j
+
sample_step
;
xs
=
xf
+
(
-
kx
*
scale
*
si
+
ky
*
scale
*
co
);
ys
=
yf
+
(
kx
*
scale
*
co
+
ky
*
scale
*
si
);
for
(
int
k
=
i
;
k
<
i
+
9
;
++
k
)
{
for
(
int
l
=
j
;
l
<
j
+
9
;
++
l
)
{
// Get coords of sample point on the rotated axis
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
// Get the gaussian weighted x and y responses
gauss_s1
=
gaussian
(
xs
-
sample_x
,
ys
-
sample_y
,
2.5
*
scale
);
y1
=
fRound
(
sample_y
-
.5
);
x1
=
fRound
(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Get the x and y derivatives on the rotated axis
rry
=
gauss_s1
*
(
rx
*
co
+
ry
*
si
);
rrx
=
gauss_s1
*
(
-
rx
*
si
+
ry
*
co
);
// Sum the derivatives to the cumulative descriptor
dx
+=
rrx
;
dy
+=
rry
;
mdx
+=
fabs
(
rrx
);
mdy
+=
fabs
(
rry
);
}
}
// Add the values to the descriptor vector
gauss_s2
=
gaussian
(
cx
-
2.0
f
,
cy
-
2.0
f
,
1.5
f
);
desc
[
dcount
++
]
=
dx
*
gauss_s2
;
desc
[
dcount
++
]
=
dy
*
gauss_s2
;
desc
[
dcount
++
]
=
mdx
*
gauss_s2
;
desc
[
dcount
++
]
=
mdy
*
gauss_s2
;
len
+=
(
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
)
*
gauss_s2
*
gauss_s2
;
j
+=
9
;
}
i
+=
9
;
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the upright G-SURF descriptor of the provided keypoint
* given the main orientation
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional
* G-SURF descriptor as described in Pablo F. Alcantarilla, Luis M. Bergasa and
* Andrew J. Davison, Gauge-SURF Descriptors, Image and Vision Computing 31(1), 2013
*/
void
KAZE
::
Get_GSURF_Upright_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rxx
=
0.0
,
rxy
=
0.0
,
ryy
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
float
lvv
=
0.0
,
lww
=
0.0
,
modg
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
level
=
kpt
.
class_id
;
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point on the rotated axis
sample_y
=
yf
+
l
*
scale
;
sample_x
=
xf
+
k
*
scale
;
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
modg
=
pow
(
rx
,
2
)
+
pow
(
ry
,
2
);
if
(
modg
!=
0.0
)
{
res1
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y2
)
+
x2
);
rxx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y2
)
+
x2
);
rxy
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y2
)
+
x2
);
ryy
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Lww = (Lx^2 * Lxx + 2*Lx*Lxy*Ly + Ly^2*Lyy) / (Lx^2 + Ly^2)
lww
=
(
pow
(
rx
,
2
)
*
rxx
+
2.0
*
rx
*
rxy
*
ry
+
pow
(
ry
,
2
)
*
ryy
)
/
(
modg
);
// Lvv = (-2*Lx*Lxy*Ly + Lxx*Ly^2 + Lx^2*Lyy) / (Lx^2 + Ly^2)
lvv
=
(
-
2.0
*
rx
*
rxy
*
ry
+
rxx
*
pow
(
ry
,
2
)
+
pow
(
rx
,
2
)
*
ryy
)
/
(
modg
);
}
else
{
lww
=
0.0
;
lvv
=
0.0
;
}
// Sum the derivatives to the cumulative descriptor
dx
+=
lww
;
dy
+=
lvv
;
mdx
+=
fabs
(
lww
);
mdy
+=
fabs
(
lvv
);
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dx
;
desc
[
dcount
++
]
=
dy
;
desc
[
dcount
++
]
=
mdx
;
desc
[
dcount
++
]
=
mdy
;
// Store the current length^2 of the vector
len
+=
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the G-SURF descriptor of the provided keypoint given the
* main orientation
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 64. No additional
* G-SURF descriptor as described in Pablo F. Alcantarilla, Luis M. Bergasa and
* Andrew J. Davison, Gauge-SURF Descriptors, Image and Vision Computing 31(1), 2013
*/
void
KAZE
::
Get_GSURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
dx
=
0.0
,
dy
=
0.0
,
mdx
=
0.0
,
mdy
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rxx
=
0.0
,
rxy
=
0.0
,
ryy
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
float
lvv
=
0.0
,
lww
=
0.0
,
modg
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
64
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dx
=
dy
=
mdx
=
mdy
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point on the rotated axis
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
modg
=
pow
(
rx
,
2
)
+
pow
(
ry
,
2
);
if
(
modg
!=
0.0
)
{
res1
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y2
)
+
x2
);
rxx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y2
)
+
x2
);
rxy
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y2
)
+
x2
);
ryy
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Lww = (Lx^2 * Lxx + 2*Lx*Lxy*Ly + Ly^2*Lyy) / (Lx^2 + Ly^2)
lww
=
(
pow
(
rx
,
2
)
*
rxx
+
2.0
*
rx
*
rxy
*
ry
+
pow
(
ry
,
2
)
*
ryy
)
/
(
modg
);
// Lvv = (-2*Lx*Lxy*Ly + Lxx*Ly^2 + Lx^2*Lyy) / (Lx^2 + Ly^2)
lvv
=
(
-
2.0
*
rx
*
rxy
*
ry
+
rxx
*
pow
(
ry
,
2
)
+
pow
(
rx
,
2
)
*
ryy
)
/
(
modg
);
}
else
{
lww
=
0.0
;
lvv
=
0.0
;
}
// Sum the derivatives to the cumulative descriptor
dx
+=
lww
;
dy
+=
lvv
;
mdx
+=
fabs
(
lww
);
mdy
+=
fabs
(
lvv
);
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dx
;
desc
[
dcount
++
]
=
dy
;
desc
[
dcount
++
]
=
mdx
;
desc
[
dcount
++
]
=
mdy
;
// Store the current length^2 of the vector
len
+=
dx
*
dx
+
dy
*
dy
+
mdx
*
mdx
+
mdy
*
mdy
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the upright extended descriptor (no rotation invariant)
* of the provided keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 128. No additional
* Gaussian weighting is performed. The descriptor is inspired from Bay et al.,
* Speeded Up Robust Features, ECCV, 2006
*/
void
KAZE
::
Get_SURF_Upright_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
rx
=
0.0
,
ry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
sample_x
=
0.0
,
sample_y
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
float
dxp
=
0.0
,
dyp
=
0.0
,
mdxp
=
0.0
,
mdyp
=
0.0
;
float
dxn
=
0.0
,
dyn
=
0.0
,
mdxn
=
0.0
,
mdyn
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
128
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
level
=
kpt
.
class_id
;
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dxp
=
dxn
=
mdxp
=
mdxn
=
0.0
;
dyp
=
dyn
=
mdyp
=
mdyn
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
sample_y
=
k
*
scale
+
yf
;
sample_x
=
l
*
scale
+
xf
;
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Sum the derivatives to the cumulative descriptor
if
(
ry
>=
0.0
)
{
dxp
+=
rx
;
mdxp
+=
fabs
(
rx
);
}
else
{
dxn
+=
rx
;
mdxn
+=
fabs
(
rx
);
}
if
(
rx
>=
0.0
)
{
dyp
+=
ry
;
mdyp
+=
fabs
(
ry
);
}
else
{
dyn
+=
ry
;
mdyn
+=
fabs
(
ry
);
}
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dxp
;
desc
[
dcount
++
]
=
dxn
;
desc
[
dcount
++
]
=
mdxp
;
desc
[
dcount
++
]
=
mdxn
;
desc
[
dcount
++
]
=
dyp
;
desc
[
dcount
++
]
=
dyn
;
desc
[
dcount
++
]
=
mdyp
;
desc
[
dcount
++
]
=
mdyn
;
// Store the current length^2 of the vector
len
+=
dxp
*
dxp
+
dxn
*
dxn
+
mdxp
*
mdxp
+
mdxn
*
mdxn
+
dyp
*
dyp
+
dyn
*
dyn
+
mdyp
*
mdyp
+
mdyn
*
mdyn
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the extended descriptor of the provided keypoint given the
* main orientation
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 128. No additional
* Gaussian weighting is performed. The descriptor is inspired from Bay et al.,
* Speeded Up Robust Features, ECCV, 2006
*/
void
KAZE
::
Get_SURF_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
rx
=
0.0
,
ry
=
0.0
,
rrx
=
0.0
,
rry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
float
dxp
=
0.0
,
dyp
=
0.0
,
mdxp
=
0.0
,
mdyp
=
0.0
;
float
dxn
=
0.0
,
dyn
=
0.0
,
mdxn
=
0.0
,
mdyn
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
128
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dxp
=
dxn
=
mdxp
=
mdxn
=
0.0
;
dyp
=
dyn
=
mdyp
=
mdyn
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point on the rotated axis
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Get the x and y derivatives on the rotated axis
rry
=
rx
*
co
+
ry
*
si
;
rrx
=
-
rx
*
si
+
ry
*
co
;
// Sum the derivatives to the cumulative descriptor
if
(
rry
>=
0.0
)
{
dxp
+=
rrx
;
mdxp
+=
fabs
(
rrx
);
}
else
{
dxn
+=
rrx
;
mdxn
+=
fabs
(
rrx
);
}
if
(
rrx
>=
0.0
)
{
dyp
+=
rry
;
mdyp
+=
fabs
(
rry
);
}
else
{
dyn
+=
rry
;
mdyn
+=
fabs
(
rry
);
}
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dxp
;
desc
[
dcount
++
]
=
dxn
;
desc
[
dcount
++
]
=
mdxp
;
desc
[
dcount
++
]
=
mdxn
;
desc
[
dcount
++
]
=
dyp
;
desc
[
dcount
++
]
=
dyn
;
desc
[
dcount
++
]
=
mdyp
;
desc
[
dcount
++
]
=
mdyn
;
// Store the current length^2 of the vector
len
+=
dxp
*
dxp
+
dxn
*
dxn
+
mdxp
*
mdxp
+
mdxn
*
mdxn
+
dyp
*
dyp
+
dyn
*
dyn
+
mdyp
*
mdyp
+
mdyn
*
mdyn
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the extended upright descriptor (not rotation invariant) of
* the provided keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 24 s x 24 s. Descriptor Length 128. The descriptor is inspired
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
* ECCV 2008
*/
void
KAZE
::
Get_MSURF_Upright_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
gauss_s1
=
0.0
,
gauss_s2
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
ys
=
0.0
,
xs
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
;
int
x1
=
0
,
y1
=
0
,
sample_step
=
0
,
pattern_size
=
0
;
int
x2
=
0
,
y2
=
0
,
kx
=
0
,
ky
=
0
,
i
=
0
,
j
=
0
,
dcount
=
0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
float
dxp
=
0.0
,
dyp
=
0.0
,
mdxp
=
0.0
,
mdyp
=
0.0
;
float
dxn
=
0.0
,
dyn
=
0.0
,
mdxn
=
0.0
,
mdyn
=
0.0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Subregion centers for the 4x4 gaussian weighting
float
cx
=
-
0.5
,
cy
=
0.5
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
128
;
sample_step
=
5
;
pattern_size
=
12
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
level
=
kpt
.
class_id
;
i
=
-
8
;
// Calculate descriptor for this interest point
// Area of size 24 s x 24 s
while
(
i
<
pattern_size
)
{
j
=
-
8
;
i
=
i
-
4
;
cx
+=
1.0
;
cy
=
-
0.5
;
while
(
j
<
pattern_size
)
{
dxp
=
dxn
=
mdxp
=
mdxn
=
0.0
;
dyp
=
dyn
=
mdyp
=
mdyn
=
0.0
;
cy
+=
1.0
;
j
=
j
-
4
;
ky
=
i
+
sample_step
;
kx
=
j
+
sample_step
;
ys
=
yf
+
(
ky
*
scale
);
xs
=
xf
+
(
kx
*
scale
);
for
(
int
k
=
i
;
k
<
i
+
9
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
9
;
l
++
)
{
sample_y
=
k
*
scale
+
yf
;
sample_x
=
l
*
scale
+
xf
;
//Get the gaussian weighted x and y responses
gauss_s1
=
gaussian
(
xs
-
sample_x
,
ys
-
sample_y
,
2.50
*
scale
);
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
rx
=
gauss_s1
*
rx
;
ry
=
gauss_s1
*
ry
;
// Sum the derivatives to the cumulative descriptor
if
(
ry
>=
0.0
)
{
dxp
+=
rx
;
mdxp
+=
fabs
(
rx
);
}
else
{
dxn
+=
rx
;
mdxn
+=
fabs
(
rx
);
}
if
(
rx
>=
0.0
)
{
dyp
+=
ry
;
mdyp
+=
fabs
(
ry
);
}
else
{
dyn
+=
ry
;
mdyn
+=
fabs
(
ry
);
}
}
}
// Add the values to the descriptor vector
gauss_s2
=
gaussian
(
cx
-
2.0
f
,
cy
-
2.0
f
,
1.5
f
);
desc
[
dcount
++
]
=
dxp
*
gauss_s2
;
desc
[
dcount
++
]
=
dxn
*
gauss_s2
;
desc
[
dcount
++
]
=
mdxp
*
gauss_s2
;
desc
[
dcount
++
]
=
mdxn
*
gauss_s2
;
desc
[
dcount
++
]
=
dyp
*
gauss_s2
;
desc
[
dcount
++
]
=
dyn
*
gauss_s2
;
desc
[
dcount
++
]
=
mdyp
*
gauss_s2
;
desc
[
dcount
++
]
=
mdyn
*
gauss_s2
;
// Store the current length^2 of the vector
len
+=
(
dxp
*
dxp
+
dxn
*
dxn
+
mdxp
*
mdxp
+
mdxn
*
mdxn
+
dyp
*
dyp
+
dyn
*
dyn
+
mdyp
*
mdyp
+
mdyn
*
mdyn
)
*
gauss_s2
*
gauss_s2
;
j
+=
9
;
}
i
+=
9
;
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the extended G-SURF descriptor of the provided keypoint
* given the main orientation of the keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 24 s x 24 s. Descriptor Length 128. The descriptor is inspired
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
* ECCV 2008
*/
void
KAZE
::
Get_MSURF_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
gauss_s1
=
0.0
,
gauss_s2
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rrx
=
0.0
,
rry
=
0.0
,
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
ys
=
0.0
,
xs
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
float
dxp
=
0.0
,
dyp
=
0.0
,
mdxp
=
0.0
,
mdyp
=
0.0
;
float
dxn
=
0.0
,
dyn
=
0.0
,
mdxn
=
0.0
,
mdyn
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
;
int
kx
=
0
,
ky
=
0
,
i
=
0
,
j
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Subregion centers for the 4x4 gaussian weighting
float
cx
=
-
0.5
,
cy
=
0.5
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
128
;
sample_step
=
5
;
pattern_size
=
12
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
i
=
-
8
;
// Calculate descriptor for this interest point
// Area of size 24 s x 24 s
while
(
i
<
pattern_size
)
{
j
=
-
8
;
i
=
i
-
4
;
cx
+=
1.0
;
cy
=
-
0.5
;
while
(
j
<
pattern_size
)
{
dxp
=
dxn
=
mdxp
=
mdxn
=
0.0
;
dyp
=
dyn
=
mdyp
=
mdyn
=
0.0
;
cy
+=
1.0
f
;
j
=
j
-
4
;
ky
=
i
+
sample_step
;
kx
=
j
+
sample_step
;
xs
=
xf
+
(
-
kx
*
scale
*
si
+
ky
*
scale
*
co
);
ys
=
yf
+
(
kx
*
scale
*
co
+
ky
*
scale
*
si
);
for
(
int
k
=
i
;
k
<
i
+
9
;
++
k
)
{
for
(
int
l
=
j
;
l
<
j
+
9
;
++
l
)
{
// Get coords of sample point on the rotated axis
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
// Get the gaussian weighted x and y responses
gauss_s1
=
gaussian
(
xs
-
sample_x
,
ys
-
sample_y
,
2.5
*
scale
);
y1
=
fRound
(
sample_y
-
.5
);
x1
=
fRound
(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Get the x and y derivatives on the rotated axis
rry
=
gauss_s1
*
(
rx
*
co
+
ry
*
si
);
rrx
=
gauss_s1
*
(
-
rx
*
si
+
ry
*
co
);
// Sum the derivatives to the cumulative descriptor
if
(
rry
>=
0.0
)
{
dxp
+=
rrx
;
mdxp
+=
fabs
(
rrx
);
}
else
{
dxn
+=
rrx
;
mdxn
+=
fabs
(
rrx
);
}
if
(
rrx
>=
0.0
)
{
dyp
+=
rry
;
mdyp
+=
fabs
(
rry
);
}
else
{
dyn
+=
rry
;
mdyn
+=
fabs
(
rry
);
}
}
}
// Add the values to the descriptor vector
gauss_s2
=
gaussian
(
cx
-
2.0
f
,
cy
-
2.0
f
,
1.5
f
);
desc
[
dcount
++
]
=
dxp
*
gauss_s2
;
desc
[
dcount
++
]
=
dxn
*
gauss_s2
;
desc
[
dcount
++
]
=
mdxp
*
gauss_s2
;
desc
[
dcount
++
]
=
mdxn
*
gauss_s2
;
desc
[
dcount
++
]
=
dyp
*
gauss_s2
;
desc
[
dcount
++
]
=
dyn
*
gauss_s2
;
desc
[
dcount
++
]
=
mdyp
*
gauss_s2
;
desc
[
dcount
++
]
=
mdyn
*
gauss_s2
;
// Store the current length^2 of the vector
len
+=
(
dxp
*
dxp
+
dxn
*
dxn
+
mdxp
*
mdxp
+
mdxn
*
mdxn
+
dyp
*
dyp
+
dyn
*
dyn
+
mdyp
*
mdyp
+
mdyn
*
mdyn
)
*
gauss_s2
*
gauss_s2
;
j
+=
9
;
}
i
+=
9
;
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the G-SURF upright extended descriptor
* (no rotation invariant) of the provided keypoint
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 128. No additional
* G-SURF descriptor as described in Pablo F. Alcantarilla, Luis M. Bergasa and
* Andrew J. Davison, Gauge-SURF Descriptors, Image and Vision Computing 31(1), 2013
*/
void
KAZE
::
Get_GSURF_Upright_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
,
sample_x
=
0.0
,
sample_y
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rxx
=
0.0
,
rxy
=
0.0
,
ryy
=
0.0
,
modg
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
float
dxp
=
0.0
,
dyp
=
0.0
,
mdxp
=
0.0
,
mdyp
=
0.0
;
float
dxn
=
0.0
,
dyn
=
0.0
,
mdxn
=
0.0
,
mdyn
=
0.0
,
lvv
=
0.0
,
lww
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
128
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
level
=
kpt
.
class_id
;
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dxp
=
dxn
=
mdxp
=
mdxn
=
0.0
;
dyp
=
dyn
=
mdyp
=
mdyn
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
sample_y
=
k
*
scale
+
yf
;
sample_x
=
l
*
scale
+
xf
;
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
modg
=
pow
(
rx
,
2
)
+
pow
(
ry
,
2
);
if
(
modg
!=
0.0
)
{
res1
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y2
)
+
x2
);
rxx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y2
)
+
x2
);
rxy
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y2
)
+
x2
);
ryy
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Lww = (Lx^2 * Lxx + 2*Lx*Lxy*Ly + Ly^2*Lyy) / (Lx^2 + Ly^2)
lww
=
(
pow
(
rx
,
2
)
*
rxx
+
2.0
*
rx
*
rxy
*
ry
+
pow
(
ry
,
2
)
*
ryy
)
/
(
modg
);
// Lvv = (-2*Lx*Lxy*Ly + Lxx*Ly^2 + Lx^2*Lyy) / (Lx^2 + Ly^2)
lvv
=
(
-
2.0
*
rx
*
rxy
*
ry
+
rxx
*
pow
(
ry
,
2
)
+
pow
(
rx
,
2
)
*
ryy
)
/
(
modg
);
}
else
{
lww
=
0.0
;
lvv
=
0.0
;
}
// Sum the derivatives to the cumulative descriptor
if
(
lww
>=
0.0
)
{
dxp
+=
lvv
;
mdxp
+=
fabs
(
lvv
);
}
else
{
dxn
+=
lvv
;
mdxn
+=
fabs
(
lvv
);
}
if
(
lvv
>=
0.0
)
{
dyp
+=
lww
;
mdyp
+=
fabs
(
lww
);
}
else
{
dyn
+=
lww
;
mdyn
+=
fabs
(
lww
);
}
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dxp
;
desc
[
dcount
++
]
=
dxn
;
desc
[
dcount
++
]
=
mdxp
;
desc
[
dcount
++
]
=
mdxn
;
desc
[
dcount
++
]
=
dyp
;
desc
[
dcount
++
]
=
dyn
;
desc
[
dcount
++
]
=
mdyp
;
desc
[
dcount
++
]
=
mdyn
;
// Store the current length^2 of the vector
len
+=
dxp
*
dxp
+
dxn
*
dxn
+
mdxp
*
mdxp
+
mdxn
*
mdxn
+
dyp
*
dyp
+
dyn
*
dyn
+
mdyp
*
mdyp
+
mdyn
*
mdyn
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method computes the extended descriptor of the provided keypoint given the
* main orientation
* @param kpt Input keypoint
* @param desc Descriptor vector
* @note Rectangular grid of 20 s x 20 s. Descriptor Length 128. No additional
* G-SURF descriptor as described in Pablo F. Alcantarilla, Luis M. Bergasa and
* Andrew J. Davison, Gauge-SURF Descriptors, Image and Vision Computing 31(1), 2013
*/
void
KAZE
::
Get_GSURF_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
)
{
float
len
=
0.0
,
xf
=
0.0
,
yf
=
0.0
;
float
rx
=
0.0
,
ry
=
0.0
,
rxx
=
0.0
,
rxy
=
0.0
,
ryy
=
0.0
;
float
sample_x
=
0.0
,
sample_y
=
0.0
,
co
=
0.0
,
si
=
0.0
,
angle
=
0.0
;
float
fx
=
0.0
,
fy
=
0.0
,
res1
=
0.0
,
res2
=
0.0
,
res3
=
0.0
,
res4
=
0.0
;
float
dxp
=
0.0
,
dyp
=
0.0
,
mdxp
=
0.0
,
mdyp
=
0.0
;
float
dxn
=
0.0
,
dyn
=
0.0
,
mdxn
=
0.0
,
mdyn
=
0.0
;
float
lvv
=
0.0
,
lww
=
0.0
,
modg
=
0.0
;
int
x1
=
0
,
y1
=
0
,
x2
=
0
,
y2
=
0
,
sample_step
=
0
,
pattern_size
=
0
,
dcount
=
0
;
int
dsize
=
0
,
scale
=
0
,
level
=
0
;
// Set the descriptor size and the sample and pattern sizes
dsize
=
128
;
sample_step
=
5
;
pattern_size
=
10
;
// Get the information from the keypoint
yf
=
kpt
.
pt
.
y
;
xf
=
kpt
.
pt
.
x
;
scale
=
fRound
(
kpt
.
size
/
2.0
);
angle
=
kpt
.
angle
;
level
=
kpt
.
class_id
;
co
=
cos
(
angle
);
si
=
sin
(
angle
);
// Calculate descriptor for this interest point
for
(
int
i
=
-
pattern_size
;
i
<
pattern_size
;
i
+=
sample_step
)
{
for
(
int
j
=
-
pattern_size
;
j
<
pattern_size
;
j
+=
sample_step
)
{
dxp
=
dxn
=
mdxp
=
mdxn
=
0.0
;
dyp
=
dyn
=
mdyp
=
mdyn
=
0.0
;
for
(
int
k
=
i
;
k
<
i
+
sample_step
;
k
++
)
{
for
(
int
l
=
j
;
l
<
j
+
sample_step
;
l
++
)
{
// Get the coordinates of the sample point on the rotated axis
sample_y
=
yf
+
(
l
*
scale
*
co
+
k
*
scale
*
si
);
sample_x
=
xf
+
(
-
l
*
scale
*
si
+
k
*
scale
*
co
);
y1
=
(
int
)(
sample_y
-
.5
);
x1
=
(
int
)(
sample_x
-
.5
);
checkDescriptorLimits
(
x1
,
y1
,
img_width_
,
img_height_
);
y2
=
(
int
)(
sample_y
+
.5
);
x2
=
(
int
)(
sample_x
+
.5
);
checkDescriptorLimits
(
x2
,
y2
,
img_width_
,
img_height_
);
fx
=
sample_x
-
x1
;
fy
=
sample_y
-
y1
;
res1
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lx
.
ptr
<
float
>
(
y2
)
+
x2
);
rx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Ly
.
ptr
<
float
>
(
y2
)
+
x2
);
ry
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
modg
=
pow
(
rx
,
2
)
+
pow
(
ry
,
2
);
if
(
modg
!=
0.0
)
{
res1
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lxx
.
ptr
<
float
>
(
y2
)
+
x2
);
rxx
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lxy
.
ptr
<
float
>
(
y2
)
+
x2
);
rxy
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
res1
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y1
)
+
x1
);
res2
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y1
)
+
x2
);
res3
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y2
)
+
x1
);
res4
=
*
(
evolution_
[
level
].
Lyy
.
ptr
<
float
>
(
y2
)
+
x2
);
ryy
=
(
1.0
-
fx
)
*
(
1.0
-
fy
)
*
res1
+
fx
*
(
1.0
-
fy
)
*
res2
+
(
1.0
-
fx
)
*
fy
*
res3
+
fx
*
fy
*
res4
;
// Lww = (Lx^2 * Lxx + 2*Lx*Lxy*Ly + Ly^2*Lyy) / (Lx^2 + Ly^2)
lww
=
(
pow
(
rx
,
2
)
*
rxx
+
2.0
*
rx
*
rxy
*
ry
+
pow
(
ry
,
2
)
*
ryy
)
/
(
modg
);
// Lvv = (-2*Lx*Lxy*Ly + Lxx*Ly^2 + Lx^2*Lyy) / (Lx^2 + Ly^2)
lvv
=
(
-
2.0
*
rx
*
rxy
*
ry
+
rxx
*
pow
(
ry
,
2
)
+
pow
(
rx
,
2
)
*
ryy
)
/
(
modg
);
}
else
{
lww
=
0.0
;
lvv
=
0.0
;
}
// Sum the derivatives to the cumulative descriptor
if
(
lww
>=
0.0
)
{
dxp
+=
lvv
;
mdxp
+=
fabs
(
lvv
);
}
else
{
dxn
+=
lvv
;
mdxn
+=
fabs
(
lvv
);
}
if
(
lvv
>=
0.0
)
{
dyp
+=
lww
;
mdyp
+=
fabs
(
lww
);
}
else
{
dyn
+=
lww
;
mdyn
+=
fabs
(
lww
);
}
}
}
// Add the values to the descriptor vector
desc
[
dcount
++
]
=
dxp
;
desc
[
dcount
++
]
=
dxn
;
desc
[
dcount
++
]
=
mdxp
;
desc
[
dcount
++
]
=
mdxn
;
desc
[
dcount
++
]
=
dyp
;
desc
[
dcount
++
]
=
dyn
;
desc
[
dcount
++
]
=
mdyp
;
desc
[
dcount
++
]
=
mdyn
;
// Store the current length^2 of the vector
len
+=
dxp
*
dxp
+
dxn
*
dxn
+
mdxp
*
mdxp
+
mdxn
*
mdxn
+
dyp
*
dyp
+
dyn
*
dyn
+
mdyp
*
mdyp
+
mdyn
*
mdyn
;
}
}
// convert to unit vector
len
=
sqrt
(
len
);
for
(
int
i
=
0
;
i
<
dsize
;
i
++
)
{
desc
[
i
]
/=
len
;
}
if
(
USE_CLIPPING_NORMALIZATION
==
true
)
{
clippingDescriptor
(
desc
,
dsize
,
CLIPPING_NORMALIZATION_NITER
,
CLIPPING_NORMALIZATION_RATIO
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method performs a scalar non-linear diffusion step using AOS schemes
* @param Ld Image at a given evolution step
* @param Ldprev Image at a previous evolution step
* @param c Conductivity image
* @param stepsize Stepsize for the nonlinear diffusion evolution
* @note If c is constant, the diffusion will be linear
* If c is a matrix of the same size as Ld, the diffusion will be nonlinear
* The stepsize can be arbitrarilly large
*/
void
KAZE
::
AOS_Step_Scalar
(
cv
::
Mat
&
Ld
,
const
cv
::
Mat
&
Ldprev
,
const
cv
::
Mat
&
c
,
const
float
&
stepsize
)
{
#ifdef _OPENMP
#pragma omp sections
{
#pragma omp section
{
AOS_Rows
(
Ldprev
,
c
,
stepsize
);
}
#pragma omp section
{
AOS_Columns
(
Ldprev
,
c
,
stepsize
);
}
}
#else
AOS_Rows
(
Ldprev
,
c
,
stepsize
);
AOS_Columns
(
Ldprev
,
c
,
stepsize
);
#endif
Ld
=
0.5
*
(
Lty_
+
Ltx_
.
t
());
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method performs performs 1D-AOS for the image rows
* @param Ldprev Image at a previous evolution step
* @param c Conductivity image
* @param stepsize Stepsize for the nonlinear diffusion evolution
*/
void
KAZE
::
AOS_Rows
(
const
cv
::
Mat
&
Ldprev
,
const
cv
::
Mat
&
c
,
const
float
&
stepsize
)
{
// Operate on rows
for
(
int
i
=
0
;
i
<
qr_
.
rows
;
i
++
)
{
for
(
int
j
=
0
;
j
<
qr_
.
cols
;
j
++
)
{
*
(
qr_
.
ptr
<
float
>
(
i
)
+
j
)
=
*
(
c
.
ptr
<
float
>
(
i
)
+
j
)
+
*
(
c
.
ptr
<
float
>
(
i
+
1
)
+
j
);
}
}
for
(
int
j
=
0
;
j
<
py_
.
cols
;
j
++
)
{
*
(
py_
.
ptr
<
float
>
(
0
)
+
j
)
=
*
(
qr_
.
ptr
<
float
>
(
0
)
+
j
);
}
for
(
int
j
=
0
;
j
<
py_
.
cols
;
j
++
)
{
*
(
py_
.
ptr
<
float
>
(
py_
.
rows
-
1
)
+
j
)
=
*
(
qr_
.
ptr
<
float
>
(
qr_
.
rows
-
1
)
+
j
);
}
for
(
int
i
=
1
;
i
<
py_
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
0
;
j
<
py_
.
cols
;
j
++
)
{
*
(
py_
.
ptr
<
float
>
(
i
)
+
j
)
=
*
(
qr_
.
ptr
<
float
>
(
i
-
1
)
+
j
)
+
*
(
qr_
.
ptr
<
float
>
(
i
)
+
j
);
}
}
// a = 1 + t.*p; (p is -1*p)
// b = -t.*q;
ay_
=
1.0
+
stepsize
*
py_
;
// p is -1*p
by_
=
-
stepsize
*
qr_
;
// Do Thomas algorithm to solve the linear system of equations
Thomas
(
ay_
,
by_
,
Ldprev
,
Lty_
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method performs performs 1D-AOS for the image columns
* @param Ldprev Image at a previous evolution step
* @param c Conductivity image
* @param stepsize Stepsize for the nonlinear diffusion evolution
*/
void
KAZE
::
AOS_Columns
(
const
cv
::
Mat
&
Ldprev
,
const
cv
::
Mat
&
c
,
const
float
&
stepsize
)
{
// Operate on columns
for
(
int
j
=
0
;
j
<
qc_
.
cols
;
j
++
)
{
for
(
int
i
=
0
;
i
<
qc_
.
rows
;
i
++
)
{
*
(
qc_
.
ptr
<
float
>
(
i
)
+
j
)
=
*
(
c
.
ptr
<
float
>
(
i
)
+
j
)
+
*
(
c
.
ptr
<
float
>
(
i
)
+
j
+
1
);
}
}
for
(
int
i
=
0
;
i
<
px_
.
rows
;
i
++
)
{
*
(
px_
.
ptr
<
float
>
(
i
))
=
*
(
qc_
.
ptr
<
float
>
(
i
));
}
for
(
int
i
=
0
;
i
<
px_
.
rows
;
i
++
)
{
*
(
px_
.
ptr
<
float
>
(
i
)
+
px_
.
cols
-
1
)
=
*
(
qc_
.
ptr
<
float
>
(
i
)
+
qc_
.
cols
-
1
);
}
for
(
int
j
=
1
;
j
<
px_
.
cols
-
1
;
j
++
)
{
for
(
int
i
=
0
;
i
<
px_
.
rows
;
i
++
)
{
*
(
px_
.
ptr
<
float
>
(
i
)
+
j
)
=
*
(
qc_
.
ptr
<
float
>
(
i
)
+
j
-
1
)
+
*
(
qc_
.
ptr
<
float
>
(
i
)
+
j
);
}
}
// a = 1 + t.*p';
ax_
=
1.0
+
stepsize
*
px_
.
t
();
// b = -t.*q';
bx_
=
-
stepsize
*
qc_
.
t
();
// But take care since we need to transpose the solution!!
Mat
Ldprevt
=
Ldprev
.
t
();
// Do Thomas algorithm to solve the linear system of equations
Thomas
(
ax_
,
bx_
,
Ldprevt
,
Ltx_
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This method does the Thomas algorithm for solving a tridiagonal linear system
* @note The matrix A must be strictly diagonally dominant for a stable solution
*/
void
KAZE
::
Thomas
(
const
cv
::
Mat
&
a
,
const
cv
::
Mat
&
b
,
const
cv
::
Mat
&
Ld
,
cv
::
Mat
&
x
)
{
// Auxiliary variables
int
n
=
a
.
rows
;
Mat
m
=
cv
::
Mat
::
zeros
(
a
.
rows
,
a
.
cols
,
CV_32F
);
Mat
l
=
cv
::
Mat
::
zeros
(
b
.
rows
,
b
.
cols
,
CV_32F
);
Mat
y
=
cv
::
Mat
::
zeros
(
Ld
.
rows
,
Ld
.
cols
,
CV_32F
);
/** A*x = d; */
/** / a1 b1 0 0 0 ... 0 \ / x1 \ = / d1 \ */
/** | c1 a2 b2 0 0 ... 0 | | x2 | = | d2 | */
/** | 0 c2 a3 b3 0 ... 0 | | x3 | = | d3 | */
/** | : : : : 0 ... 0 | | : | = | : | */
/** | : : : : 0 cn-1 an | | xn | = | dn | */
/** 1. LU decomposition
/ L = / 1 \ U = / m1 r1 \
/ | l1 1 | | m2 r2 |
/ | l2 1 | | m3 r3 |
/ | : : : | | : : : |
/ \ ln-1 1 / \ mn / */
for
(
int
j
=
0
;
j
<
m
.
cols
;
j
++
)
{
*
(
m
.
ptr
<
float
>
(
0
)
+
j
)
=
*
(
a
.
ptr
<
float
>
(
0
)
+
j
);
}
for
(
int
j
=
0
;
j
<
y
.
cols
;
j
++
)
{
*
(
y
.
ptr
<
float
>
(
0
)
+
j
)
=
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
);
}
// 1. Forward substitution L*y = d for y
for
(
int
k
=
1
;
k
<
n
;
k
++
)
{
for
(
int
j
=
0
;
j
<
l
.
cols
;
j
++
)
{
*
(
l
.
ptr
<
float
>
(
k
-
1
)
+
j
)
=
*
(
b
.
ptr
<
float
>
(
k
-
1
)
+
j
)
/
*
(
m
.
ptr
<
float
>
(
k
-
1
)
+
j
);
}
for
(
int
j
=
0
;
j
<
m
.
cols
;
j
++
)
{
*
(
m
.
ptr
<
float
>
(
k
)
+
j
)
=
*
(
a
.
ptr
<
float
>
(
k
)
+
j
)
-
*
(
l
.
ptr
<
float
>
(
k
-
1
)
+
j
)
*
(
*
(
b
.
ptr
<
float
>
(
k
-
1
)
+
j
));
}
for
(
int
j
=
0
;
j
<
y
.
cols
;
j
++
)
{
*
(
y
.
ptr
<
float
>
(
k
)
+
j
)
=
*
(
Ld
.
ptr
<
float
>
(
k
)
+
j
)
-
*
(
l
.
ptr
<
float
>
(
k
-
1
)
+
j
)
*
(
*
(
y
.
ptr
<
float
>
(
k
-
1
)
+
j
));
}
}
// 2. Backward substitution U*x = y
for
(
int
j
=
0
;
j
<
y
.
cols
;
j
++
)
{
*
(
x
.
ptr
<
float
>
(
n
-
1
)
+
j
)
=
(
*
(
y
.
ptr
<
float
>
(
n
-
1
)
+
j
))
/
(
*
(
m
.
ptr
<
float
>
(
n
-
1
)
+
j
));
}
for
(
int
i
=
n
-
2
;
i
>=
0
;
i
--
)
{
for
(
int
j
=
0
;
j
<
x
.
cols
;
j
++
)
{
*
(
x
.
ptr
<
float
>
(
i
)
+
j
)
=
(
*
(
y
.
ptr
<
float
>
(
i
)
+
j
)
-
(
*
(
b
.
ptr
<
float
>
(
i
)
+
j
))
*
(
*
(
x
.
ptr
<
float
>
(
i
+
1
)
+
j
)))
/
(
*
(
m
.
ptr
<
float
>
(
i
)
+
j
));
}
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes the angle from the vector given by (X Y). From 0 to 2*Pi
*/
inline
float
getAngle
(
const
float
&
x
,
const
float
&
y
)
{
if
(
x
>=
0
&&
y
>=
0
)
{
return
atan
(
y
/
x
);
}
if
(
x
<
0
&&
y
>=
0
)
{
return
CV_PI
-
atan
(
-
y
/
x
);
}
if
(
x
<
0
&&
y
<
0
)
{
return
CV_PI
+
atan
(
y
/
x
);
}
if
(
x
>=
0
&&
y
<
0
)
{
return
2.0
*
CV_PI
-
atan
(
-
y
/
x
);
}
return
0
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function performs descriptor clipping
* @param desc_ Pointer to the descriptor vector
* @param dsize Size of the descriptor vector
* @param iter Number of iterations
* @param ratio Clipping ratio
*/
inline
void
clippingDescriptor
(
float
*
desc
,
const
int
&
dsize
,
const
int
&
niter
,
const
float
&
ratio
)
{
float
cratio
=
ratio
/
sqrt
(
dsize
);
float
len
=
0.0
;
for
(
int
i
=
0
;
i
<
niter
;
i
++
)
{
len
=
0.0
;
for
(
int
j
=
0
;
j
<
dsize
;
j
++
)
{
if
(
desc
[
j
]
>
cratio
)
{
desc
[
j
]
=
cratio
;
}
else
if
(
desc
[
j
]
<
-
cratio
)
{
desc
[
j
]
=
-
cratio
;
}
len
+=
desc
[
j
]
*
desc
[
j
];
}
// Normalize again
len
=
sqrt
(
len
);
for
(
int
j
=
0
;
j
<
dsize
;
j
++
)
{
desc
[
j
]
=
desc
[
j
]
/
len
;
}
}
}
//**************************************************************************************
//**************************************************************************************
/**
* @brief This function computes the value of a 2D Gaussian function
* @param x X Position
* @param y Y Position
* @param sig Standard Deviation
*/
inline
float
gaussian
(
const
float
&
x
,
const
float
&
y
,
const
float
&
sig
)
{
return
exp
(
-
(
x
*
x
+
y
*
y
)
/
(
2.0
f
*
sig
*
sig
));
}
//**************************************************************************************
//**************************************************************************************
/**
* @brief This function checks descriptor limits
* @param x X Position
* @param y Y Position
* @param width Image width
* @param height Image height
*/
inline
void
checkDescriptorLimits
(
int
&
x
,
int
&
y
,
const
int
&
width
,
const
int
&
height
)
{
if
(
x
<
0
)
{
x
=
0
;
}
if
(
y
<
0
)
{
y
=
0
;
}
if
(
x
>
width
-
1
)
{
x
=
width
-
1
;
}
if
(
y
>
height
-
1
)
{
y
=
height
-
1
;
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This funtion rounds float to nearest integer
* @param flt Input float
* @return dst Nearest integer
*/
inline
int
fRound
(
const
float
&
flt
)
{
return
(
int
)(
flt
+
0.5
f
);
}
modules/features2d/src/kaze/KAZE.h
0 → 100755
View file @
7a594354
/**
* @file KAZE.h
* @brief Main program for detecting and computing descriptors in a nonlinear
* scale space
* @date Jan 21, 2012
* @author Pablo F. Alcantarilla
*/
#ifndef KAZE_H_
#define KAZE_H_
//*************************************************************************************
//*************************************************************************************
// Includes
#include "config.h"
#include "nldiffusion_functions.h"
#include "fed.h"
#include "utils.h"
//*************************************************************************************
//*************************************************************************************
// KAZE Class Declaration
class
KAZE
{
private
:
// Parameters of the Nonlinear diffusion class
float
soffset_
;
// Base scale offset
float
sderivatives_
;
// Standard deviation of the Gaussian for the nonlinear diff. derivatives
int
omax_
;
// Maximum octave level
int
nsublevels_
;
// Number of sublevels per octave level
int
img_width_
;
// Width of the original image
int
img_height_
;
// Height of the original image
bool
save_scale_space_
;
// For saving scale space images
bool
verbosity_
;
// Verbosity level
std
::
vector
<
TEvolution
>
evolution_
;
// Vector of nonlinear diffusion evolution
float
kcontrast_
;
// The contrast parameter for the scalar nonlinear diffusion
float
dthreshold_
;
// Feature detector threshold response
int
diffusivity_
;
// Diffusivity type, 0->PM G1, 1->PM G2, 2-> Weickert
int
descriptor_mode_
;
// Descriptor mode
bool
use_fed_
;
// Set to true in case we want to use FED for the nonlinear diffusion filtering. Set false for using AOS
bool
use_upright_
;
// Set to true in case we want to use the upright version of the descriptors
bool
use_extended_
;
// Set to true in case we want to use the extended version of the descriptors
// Vector of keypoint vectors for finding extrema in multiple threads
std
::
vector
<
std
::
vector
<
cv
::
KeyPoint
>
>
kpts_par_
;
// FED parameters
int
ncycles_
;
// Number of cycles
bool
reordering_
;
// Flag for reordering time steps
std
::
vector
<
std
::
vector
<
float
>
>
tsteps_
;
// Vector of FED dynamic time steps
std
::
vector
<
int
>
nsteps_
;
// Vector of number of steps per cycle
// Computation times variables in ms
double
tkcontrast_
;
// Kcontrast factor computation
double
tnlscale_
;
// Nonlinear Scale space generation
double
tdetector_
;
// Feature detector
double
tmderivatives_
;
// Multiscale derivatives computation
double
tdresponse_
;
// Detector response computation
double
tdescriptor_
;
// Feature descriptor
double
tsubpixel_
;
// Subpixel refinement
// Some auxiliary variables used in the AOS step
cv
::
Mat
Ltx_
,
Lty_
,
px_
,
py_
,
ax_
,
ay_
,
bx_
,
by_
,
qr_
,
qc_
;
public
:
// Constructor
KAZE
(
KAZEOptions
&
options
);
// Destructor
~
KAZE
(
void
);
// Public methods for KAZE interface
void
Allocate_Memory_Evolution
(
void
);
int
Create_Nonlinear_Scale_Space
(
const
cv
::
Mat
&
img
);
void
Feature_Detection
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
);
void
Feature_Description
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
,
cv
::
Mat
&
desc
);
// Methods for saving the scale space set of images and detector responses
void
Save_Nonlinear_Scale_Space
(
void
);
void
Save_Detector_Responses
(
void
);
void
Save_Flow_Responses
(
void
);
private
:
// Feature Detection Methods
void
Compute_KContrast
(
const
cv
::
Mat
&
img
,
const
float
&
kper
);
void
Compute_Multiscale_Derivatives
(
void
);
void
Compute_Detector_Response
(
void
);
void
Determinant_Hessian_Parallel
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
);
void
Find_Extremum_Threading
(
const
int
&
level
);
void
Do_Subpixel_Refinement
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
);
void
Feature_Suppression_Distance
(
std
::
vector
<
cv
::
KeyPoint
>&
kpts
,
const
float
&
mdist
);
// AOS Methods
void
AOS_Step_Scalar
(
cv
::
Mat
&
Ld
,
const
cv
::
Mat
&
Ldprev
,
const
cv
::
Mat
&
c
,
const
float
&
stepsize
);
void
AOS_Rows
(
const
cv
::
Mat
&
Ldprev
,
const
cv
::
Mat
&
c
,
const
float
&
stepsize
);
void
AOS_Columns
(
const
cv
::
Mat
&
Ldprev
,
const
cv
::
Mat
&
c
,
const
float
&
stepsize
);
void
Thomas
(
const
cv
::
Mat
&
a
,
const
cv
::
Mat
&
b
,
const
cv
::
Mat
&
Ld
,
cv
::
Mat
&
x
);
// Feature Description methods
void
Compute_Main_Orientation_SURF
(
cv
::
KeyPoint
&
kpt
);
// Descriptor Mode -> 0 SURF 64
void
Get_SURF_Upright_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
void
Get_SURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
// Descriptor Mode -> 0 SURF 128
void
Get_SURF_Upright_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
void
Get_SURF_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
// Descriptor Mode -> 1 M-SURF 64
void
Get_MSURF_Upright_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
void
Get_MSURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
// Descriptor Mode -> 1 M-SURF 128
void
Get_MSURF_Upright_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
void
Get_MSURF_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
// Descriptor Mode -> 2 G-SURF 64
void
Get_GSURF_Upright_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
void
Get_GSURF_Descriptor_64
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
// Descriptor Mode -> 2 G-SURF 128
void
Get_GSURF_Upright_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
void
Get_GSURF_Descriptor_128
(
const
cv
::
KeyPoint
&
kpt
,
float
*
desc
);
public
:
// Setters
void
Set_Scale_Offset
(
float
soffset
)
{
soffset_
=
soffset
;
}
void
Set_SDerivatives
(
float
sderivatives
)
{
sderivatives_
=
sderivatives
;
}
void
Set_Octave_Max
(
int
omax
)
{
omax_
=
omax
;
}
void
Set_NSublevels
(
int
nsublevels
)
{
nsublevels_
=
nsublevels
;
}
void
Set_Save_Scale_Space_Flag
(
bool
save_scale_space
)
{
save_scale_space_
=
save_scale_space
;
}
void
Set_Image_Width
(
int
img_width
)
{
img_width_
=
img_width
;
}
void
Set_Image_Height
(
int
img_height
)
{
img_height_
=
img_height
;
}
void
Set_Verbosity_Level
(
bool
verbosity
)
{
verbosity_
=
verbosity
;
}
void
Set_KContrast
(
float
kcontrast
)
{
kcontrast_
=
kcontrast
;
}
void
Set_Detector_Threshold
(
float
dthreshold
)
{
dthreshold_
=
dthreshold
;
}
void
Set_Diffusivity_Type
(
int
diffusivity
)
{
diffusivity_
=
diffusivity
;
}
void
Set_Descriptor_Mode
(
int
descriptor_mode
)
{
descriptor_mode_
=
descriptor_mode
;
}
void
Set_Use_FED
(
bool
use_fed
)
{
use_fed_
=
use_fed
;
}
void
Set_Upright
(
bool
use_upright
)
{
use_upright_
=
use_upright
;
}
void
Set_Extended
(
bool
use_extended
)
{
use_extended_
=
use_extended
;
}
// Getters
float
Get_Scale_Offset
(
void
)
{
return
soffset_
;
}
float
Get_SDerivatives
(
void
)
{
return
sderivatives_
;
}
int
Get_Octave_Max
(
void
)
{
return
omax_
;
}
int
Get_NSublevels
(
void
)
{
return
nsublevels_
;
}
bool
Get_Save_Scale_Space_Flag
(
void
)
{
return
save_scale_space_
;
}
int
Get_Image_Width
(
void
)
{
return
img_width_
;
}
int
Get_Image_Height
(
void
)
{
return
img_height_
;
}
bool
Get_Verbosity_Level
(
void
)
{
return
verbosity_
;
}
float
Get_KContrast
(
void
)
{
return
kcontrast_
;
}
float
Get_Detector_Threshold
(
void
)
{
return
dthreshold_
;
}
int
Get_Diffusivity_Type
(
void
)
{
return
diffusivity_
;
}
int
Get_Descriptor_Mode
(
void
)
{
return
descriptor_mode_
;
}
bool
Get_Upright
(
void
)
{
return
use_upright_
;
}
bool
Get_Extended
(
void
)
{
return
use_extended_
;
}
float
Get_Time_KContrast
(
void
)
{
return
tkcontrast_
;
}
float
Get_Time_NLScale
(
void
)
{
return
tnlscale_
;
}
float
Get_Time_Detector
(
void
)
{
return
tdetector_
;
}
float
Get_Time_Multiscale_Derivatives
(
void
)
{
return
tmderivatives_
;
}
float
Get_Time_Detector_Response
(
void
)
{
return
tdresponse_
;
}
float
Get_Time_Descriptor
(
void
)
{
return
tdescriptor_
;
}
float
Get_Time_Subpixel
(
void
)
{
return
tsubpixel_
;
}
};
//*************************************************************************************
//*************************************************************************************
// Inline functions
float
getAngle
(
const
float
&
x
,
const
float
&
y
);
float
gaussian
(
const
float
&
x
,
const
float
&
y
,
const
float
&
sig
);
void
checkDescriptorLimits
(
int
&
x
,
int
&
y
,
const
int
&
width
,
const
int
&
height
);
void
clippingDescriptor
(
float
*
desc
,
const
int
&
dsize
,
const
int
&
niter
,
const
float
&
ratio
);
int
fRound
(
const
float
&
flt
);
//*************************************************************************************
//*************************************************************************************
#endif // KAZE_H_
modules/features2d/src/kaze/config.h
0 → 100644
View file @
7a594354
/**
* @file config.h
* @brief Configuration file
* @date Dec 27, 2011
* @author Pablo F. Alcantarilla
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
//******************************************************************************
//******************************************************************************
// System Includes
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cstdlib>
#include <string>
#include <vector>
#include <math.h>
// OpenCV Includes
#include "precomp.hpp"
// OpenMP Includes
#ifdef _OPENMP
#include <omp.h>
#else
#define omp_get_thread_num() 0
#endif
//*************************************************************************************
//*************************************************************************************
// Some defines
#define NMAX_CHAR 400
// Some default options
const
float
DEFAULT_SCALE_OFFSET
=
1
.
60
;
// Base scale offset (sigma units)
const
float
DEFAULT_OCTAVE_MAX
=
4
.
0
;
// Maximum octave evolution of the image 2^sigma (coarsest scale sigma units)
const
int
DEFAULT_NSUBLEVELS
=
4
;
// Default number of sublevels per scale level
const
float
DEFAULT_DETECTOR_THRESHOLD
=
0
.
001
;
// Detector response threshold to accept point
const
float
DEFAULT_MIN_DETECTOR_THRESHOLD
=
0
.
00001
;
// Minimum Detector response threshold to accept point
const
int
DEFAULT_DESCRIPTOR_MODE
=
1
;
// Descriptor Mode 0->SURF, 1->M-SURF
const
bool
DEFAULT_USE_FED
=
true
;
// 0->AOS, 1->FED
const
bool
DEFAULT_UPRIGHT
=
false
;
// Upright descriptors, not invariant to rotation
const
bool
DEFAULT_EXTENDED
=
false
;
// Extended descriptor, dimension 128
const
bool
DEFAULT_SAVE_SCALE_SPACE
=
false
;
// For saving the scale space images
const
bool
DEFAULT_VERBOSITY
=
false
;
// Verbosity level (0->no verbosity)
const
bool
DEFAULT_SHOW_RESULTS
=
true
;
// For showing the output image with the detected features plus some ratios
const
bool
DEFAULT_SAVE_KEYPOINTS
=
false
;
// For saving the list of keypoints
// Some important configuration variables
const
float
DEFAULT_SIGMA_SMOOTHING_DERIVATIVES
=
1
.
0
;
const
float
DEFAULT_KCONTRAST
=
.
01
;
const
float
KCONTRAST_PERCENTILE
=
0
.
7
;
const
int
KCONTRAST_NBINS
=
300
;
const
bool
COMPUTE_KCONTRAST
=
true
;
const
int
DEFAULT_DIFFUSIVITY_TYPE
=
1
;
// 0 -> PM G1, 1 -> PM G2, 2 -> Weickert
const
bool
USE_CLIPPING_NORMALIZATION
=
false
;
const
float
CLIPPING_NORMALIZATION_RATIO
=
1
.
6
;
const
int
CLIPPING_NORMALIZATION_NITER
=
5
;
//*************************************************************************************
//*************************************************************************************
struct
KAZEOptions
{
KAZEOptions
()
{
// Load the default options
soffset
=
DEFAULT_SCALE_OFFSET
;
omax
=
DEFAULT_OCTAVE_MAX
;
nsublevels
=
DEFAULT_NSUBLEVELS
;
dthreshold
=
DEFAULT_DETECTOR_THRESHOLD
;
use_fed
=
DEFAULT_USE_FED
;
upright
=
DEFAULT_UPRIGHT
;
extended
=
DEFAULT_EXTENDED
;
descriptor
=
DEFAULT_DESCRIPTOR_MODE
;
diffusivity
=
DEFAULT_DIFFUSIVITY_TYPE
;
sderivatives
=
DEFAULT_SIGMA_SMOOTHING_DERIVATIVES
;
save_scale_space
=
DEFAULT_SAVE_SCALE_SPACE
;
save_keypoints
=
DEFAULT_SAVE_KEYPOINTS
;
verbosity
=
DEFAULT_VERBOSITY
;
show_results
=
DEFAULT_SHOW_RESULTS
;
}
float
soffset
;
int
omax
;
int
nsublevels
;
int
img_width
;
int
img_height
;
int
diffusivity
;
float
sderivatives
;
float
dthreshold
;
bool
use_fed
;
bool
upright
;
bool
extended
;
int
descriptor
;
bool
save_scale_space
;
bool
save_keypoints
;
bool
verbosity
;
bool
show_results
;
};
struct
TEvolution
{
cv
::
Mat
Lx
,
Ly
;
// First order spatial derivatives
cv
::
Mat
Lxx
,
Lxy
,
Lyy
;
// Second order spatial derivatives
cv
::
Mat
Lflow
;
// Diffusivity image
cv
::
Mat
Lt
;
// Evolution image
cv
::
Mat
Lsmooth
;
// Smoothed image
cv
::
Mat
Lstep
;
// Evolution step update
cv
::
Mat
Ldet
;
// Detector response
float
etime
;
// Evolution time
float
esigma
;
// Evolution sigma. For linear diffusion t = sigma^2 / 2
float
octave
;
// Image octave
float
sublevel
;
// Image sublevel in each octave
int
sigma_size
;
// Integer esigma. For computing the feature detector responses
};
//*************************************************************************************
//*************************************************************************************
#endif
modules/features2d/src/kaze/fed.cpp
0 → 100644
View file @
7a594354
//=============================================================================
//
// fed.cpp
// Authors: Pablo F. Alcantarilla (1), Jesus Nuevo (2)
// Institutions: Georgia Institute of Technology (1)
// TrueVision Solutions (2)
// Date: 15/09/2013
// Email: pablofdezalc@gmail.com
//
// AKAZE Features Copyright 2013, Pablo F. Alcantarilla, Jesus Nuevo
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================
/**
* @file fed.cpp
* @brief Functions for performing Fast Explicit Diffusion and building the
* nonlinear scale space
* @date Sep 15, 2013
* @author Pablo F. Alcantarilla, Jesus Nuevo
* @note This code is derived from FED/FJ library from Grewenig et al.,
* The FED/FJ library allows solving more advanced problems
* Please look at the following papers for more information about FED:
* [1] S. Grewenig, J. Weickert, C. Schroers, A. Bruhn. Cyclic Schemes for
* PDE-Based Image Analysis. Technical Report No. 327, Department of Mathematics,
* Saarland University, Saarbrücken, Germany, March 2013
* [2] S. Grewenig, J. Weickert, A. Bruhn. From box filtering to fast explicit diffusion.
* DAGM, 2010
*
*/
#include "fed.h"
using
namespace
std
;
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function allocates an array of the least number of time steps such
* that a certain stopping time for the whole process can be obtained and fills
* it with the respective FED time step sizes for one cycle
* The function returns the number of time steps per cycle or 0 on failure
* @param T Desired process stopping time
* @param M Desired number of cycles
* @param tau_max Stability limit for the explicit scheme
* @param reordering Reordering flag
* @param tau The vector with the dynamic step sizes
*/
int
fed_tau_by_process_time
(
const
float
&
T
,
const
int
&
M
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>&
tau
)
{
// All cycles have the same fraction of the stopping time
return
fed_tau_by_cycle_time
(
T
/
(
float
)
M
,
tau_max
,
reordering
,
tau
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function allocates an array of the least number of time steps such
* that a certain stopping time for the whole process can be obtained and fills it
* it with the respective FED time step sizes for one cycle
* The function returns the number of time steps per cycle or 0 on failure
* @param t Desired cycle stopping time
* @param tau_max Stability limit for the explicit scheme
* @param reordering Reordering flag
* @param tau The vector with the dynamic step sizes
*/
int
fed_tau_by_cycle_time
(
const
float
&
t
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>
&
tau
)
{
int
n
=
0
;
// Number of time steps
float
scale
=
0.0
;
// Ratio of t we search to maximal t
// Compute necessary number of time steps
n
=
(
int
)(
ceilf
(
sqrtf
(
3.0
*
t
/
tau_max
+
0.25
f
)
-
0.5
f
-
1.0e-8
f
)
+
0.5
f
);
scale
=
3.0
*
t
/
(
tau_max
*
(
float
)(
n
*
(
n
+
1
)));
// Call internal FED time step creation routine
return
fed_tau_internal
(
n
,
scale
,
tau_max
,
reordering
,
tau
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function allocates an array of time steps and fills it with FED
* time step sizes
* The function returns the number of time steps per cycle or 0 on failure
* @param n Number of internal steps
* @param scale Ratio of t we search to maximal t
* @param tau_max Stability limit for the explicit scheme
* @param reordering Reordering flag
* @param tau The vector with the dynamic step sizes
*/
int
fed_tau_internal
(
const
int
&
n
,
const
float
&
scale
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>
&
tau
)
{
float
c
=
0.0
,
d
=
0.0
;
// Time savers
vector
<
float
>
tauh
;
// Helper vector for unsorted taus
if
(
n
<=
0
)
{
return
0
;
}
// Allocate memory for the time step size
tau
=
vector
<
float
>
(
n
);
if
(
reordering
)
{
tauh
=
vector
<
float
>
(
n
);
}
// Compute time saver
c
=
1.0
f
/
(
4.0
f
*
(
float
)
n
+
2.0
f
);
d
=
scale
*
tau_max
/
2.0
f
;
// Set up originally ordered tau vector
for
(
int
k
=
0
;
k
<
n
;
++
k
)
{
float
h
=
cosf
(
CV_PI
*
(
2.0
f
*
(
float
)
k
+
1.0
f
)
*
c
);
if
(
reordering
)
{
tauh
[
k
]
=
d
/
(
h
*
h
);
}
else
{
tau
[
k
]
=
d
/
(
h
*
h
);
}
}
// Permute list of time steps according to chosen reordering function
int
kappa
=
0
,
prime
=
0
;
if
(
reordering
==
true
)
{
// Choose kappa cycle with k = n/2
// This is a heuristic. We can use Leja ordering instead!!
kappa
=
n
/
2
;
// Get modulus for permutation
prime
=
n
+
1
;
while
(
!
fed_is_prime_internal
(
prime
))
{
prime
++
;
}
// Perform permutation
for
(
int
k
=
0
,
l
=
0
;
l
<
n
;
++
k
,
++
l
)
{
int
index
=
0
;
while
((
index
=
((
k
+
1
)
*
kappa
)
%
prime
-
1
)
>=
n
)
{
k
++
;
}
tau
[
l
]
=
tauh
[
index
];
}
}
return
n
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function checks if a number is prime or not
* @param number Number to check if it is prime or not
* @return true if the number is prime
*/
bool
fed_is_prime_internal
(
const
int
&
number
)
{
bool
is_prime
=
false
;
if
(
number
<=
1
)
{
return
false
;
}
else
if
(
number
==
1
||
number
==
2
||
number
==
3
||
number
==
5
||
number
==
7
)
{
return
true
;
}
else
if
((
number
%
2
)
==
0
||
(
number
%
3
)
==
0
||
(
number
%
5
)
==
0
||
(
number
%
7
)
==
0
)
{
return
false
;
}
else
{
is_prime
=
true
;
int
upperLimit
=
sqrt
(
number
+
1.0
);
int
divisor
=
11
;
while
(
divisor
<=
upperLimit
)
{
if
(
number
%
divisor
==
0
)
{
is_prime
=
false
;
}
divisor
+=
2
;
}
return
is_prime
;
}
}
modules/features2d/src/kaze/fed.h
0 → 100644
View file @
7a594354
#ifndef FED_H
#define FED_H
//******************************************************************************
//******************************************************************************
// Includes
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <cstdlib>
#include <math.h>
#include <vector>
//*************************************************************************************
//*************************************************************************************
// Declaration of functions
int
fed_tau_by_process_time
(
const
float
&
T
,
const
int
&
M
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>&
tau
);
int
fed_tau_by_cycle_time
(
const
float
&
t
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>
&
tau
)
;
int
fed_tau_internal
(
const
int
&
n
,
const
float
&
scale
,
const
float
&
tau_max
,
const
bool
&
reordering
,
std
::
vector
<
float
>
&
tau
);
bool
fed_is_prime_internal
(
const
int
&
number
);
//*************************************************************************************
//*************************************************************************************
#endif // FED_H
modules/features2d/src/kaze/nldiffusion_functions.cpp
0 → 100644
View file @
7a594354
//=============================================================================
//
// nldiffusion_functions.cpp
// Author: Pablo F. Alcantarilla
// Institution: University d'Auvergne
// Address: Clermont Ferrand, France
// Date: 27/12/2011
// Email: pablofdezalc@gmail.com
//
// KAZE Features Copyright 2012, Pablo F. Alcantarilla
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================
/**
* @file nldiffusion_functions.cpp
* @brief Functions for non-linear diffusion applications:
* 2D Gaussian Derivatives
* Perona and Malik conductivity equations
* Perona and Malik evolution
* @date Dec 27, 2011
* @author Pablo F. Alcantarilla
*/
#include "nldiffusion_functions.h"
// Namespaces
using
namespace
std
;
using
namespace
cv
;
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function smoothes an image with a Gaussian kernel
* @param src Input image
* @param dst Output image
* @param ksize_x Kernel size in X-direction (horizontal)
* @param ksize_y Kernel size in Y-direction (vertical)
* @param sigma Kernel standard deviation
*/
void
gaussian_2D_convolution
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
int
ksize_x
,
int
ksize_y
,
float
sigma
)
{
size_t
ksize_x_
=
0
,
ksize_y_
=
0
;
// Compute an appropriate kernel size according to the specified sigma
if
(
sigma
>
ksize_x
||
sigma
>
ksize_y
||
ksize_x
==
0
||
ksize_y
==
0
)
{
ksize_x_
=
ceil
(
2.0
*
(
1.0
+
(
sigma
-
0.8
)
/
(
0.3
)));
ksize_y_
=
ksize_x_
;
}
// The kernel size must be and odd number
if
((
ksize_x_
%
2
)
==
0
)
{
ksize_x_
+=
1
;
}
if
((
ksize_y_
%
2
)
==
0
)
{
ksize_y_
+=
1
;
}
// Perform the Gaussian Smoothing with border replication
GaussianBlur
(
src
,
dst
,
Size
(
ksize_x_
,
ksize_y_
),
sigma
,
sigma
,
cv
::
BORDER_REPLICATE
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes the Perona and Malik conductivity coefficient g1
* g1 = exp(-|dL|^2/k^2)
* @param Lx First order image derivative in X-direction (horizontal)
* @param Ly First order image derivative in Y-direction (vertical)
* @param dst Output image
* @param k Contrast factor parameter
*/
void
pm_g1
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
float
k
)
{
cv
::
exp
(
-
(
Lx
.
mul
(
Lx
)
+
Ly
.
mul
(
Ly
))
/
(
k
*
k
),
dst
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes the Perona and Malik conductivity coefficient g2
* g2 = 1 / (1 + dL^2 / k^2)
* @param Lx First order image derivative in X-direction (horizontal)
* @param Ly First order image derivative in Y-direction (vertical)
* @param dst Output image
* @param k Contrast factor parameter
*/
void
pm_g2
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
float
k
)
{
dst
=
1.
/
(
1.
+
(
Lx
.
mul
(
Lx
)
+
Ly
.
mul
(
Ly
))
/
(
k
*
k
));
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes Weickert conductivity coefficient g3
* @param Lx First order image derivative in X-direction (horizontal)
* @param Ly First order image derivative in Y-direction (vertical)
* @param dst Output image
* @param k Contrast factor parameter
* @note For more information check the following paper: J. Weickert
* Applications of nonlinear diffusion in image processing and computer vision,
* Proceedings of Algorithmy 2000
*/
void
weickert_diffusivity
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
float
k
)
{
Mat
modg
;
cv
::
pow
((
Lx
.
mul
(
Lx
)
+
Ly
.
mul
(
Ly
))
/
(
k
*
k
),
4
,
modg
);
cv
::
exp
(
-
3.315
/
modg
,
dst
);
dst
=
1.0
-
dst
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes a good empirical value for the k contrast factor
* given an input image, the percentile (0-1), the gradient scale and the number of
* bins in the histogram
* @param img Input image
* @param perc Percentile of the image gradient histogram (0-1)
* @param gscale Scale for computing the image gradient histogram
* @param nbins Number of histogram bins
* @param ksize_x Kernel size in X-direction (horizontal) for the Gaussian smoothing kernel
* @param ksize_y Kernel size in Y-direction (vertical) for the Gaussian smoothing kernel
* @return k contrast factor
*/
float
compute_k_percentile
(
const
cv
::
Mat
&
img
,
float
perc
,
float
gscale
,
int
nbins
,
int
ksize_x
,
int
ksize_y
)
{
int
nbin
=
0
,
nelements
=
0
,
nthreshold
=
0
,
k
=
0
;
float
kperc
=
0.0
,
modg
=
0.0
,
lx
=
0.0
,
ly
=
0.0
;
float
npoints
=
0.0
;
float
hmax
=
0.0
;
// Create the array for the histogram
float
*
hist
=
new
float
[
nbins
];
// Create the matrices
Mat
gaussian
=
Mat
::
zeros
(
img
.
rows
,
img
.
cols
,
CV_32F
);
Mat
Lx
=
Mat
::
zeros
(
img
.
rows
,
img
.
cols
,
CV_32F
);
Mat
Ly
=
Mat
::
zeros
(
img
.
rows
,
img
.
cols
,
CV_32F
);
// Set the histogram to zero, just in case
for
(
int
i
=
0
;
i
<
nbins
;
i
++
)
{
hist
[
i
]
=
0.0
;
}
// Perform the Gaussian convolution
gaussian_2D_convolution
(
img
,
gaussian
,
ksize_x
,
ksize_y
,
gscale
);
// Compute the Gaussian derivatives Lx and Ly
Scharr
(
gaussian
,
Lx
,
CV_32F
,
1
,
0
,
1
,
0
,
cv
::
BORDER_DEFAULT
);
Scharr
(
gaussian
,
Ly
,
CV_32F
,
0
,
1
,
1
,
0
,
cv
::
BORDER_DEFAULT
);
// Skip the borders for computing the histogram
for
(
int
i
=
1
;
i
<
gaussian
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
1
;
j
<
gaussian
.
cols
-
1
;
j
++
)
{
lx
=
*
(
Lx
.
ptr
<
float
>
(
i
)
+
j
);
ly
=
*
(
Ly
.
ptr
<
float
>
(
i
)
+
j
);
modg
=
sqrt
(
lx
*
lx
+
ly
*
ly
);
// Get the maximum
if
(
modg
>
hmax
)
{
hmax
=
modg
;
}
}
}
// Skip the borders for computing the histogram
for
(
int
i
=
1
;
i
<
gaussian
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
1
;
j
<
gaussian
.
cols
-
1
;
j
++
)
{
lx
=
*
(
Lx
.
ptr
<
float
>
(
i
)
+
j
);
ly
=
*
(
Ly
.
ptr
<
float
>
(
i
)
+
j
);
modg
=
sqrt
(
lx
*
lx
+
ly
*
ly
);
// Find the correspondent bin
if
(
modg
!=
0.0
)
{
nbin
=
floor
(
nbins
*
(
modg
/
hmax
));
if
(
nbin
==
nbins
)
{
nbin
--
;
}
hist
[
nbin
]
++
;
npoints
++
;
}
}
}
// Now find the perc of the histogram percentile
nthreshold
=
(
size_t
)(
npoints
*
perc
);
for
(
k
=
0
;
nelements
<
nthreshold
&&
k
<
nbins
;
k
++
)
{
nelements
=
nelements
+
hist
[
k
];
}
if
(
nelements
<
nthreshold
)
{
kperc
=
0.03
;
}
else
{
kperc
=
hmax
*
((
float
)(
k
)
/
(
float
)
nbins
);
}
delete
hist
;
return
kperc
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes Scharr image derivatives
* @param src Input image
* @param dst Output image
* @param xorder Derivative order in X-direction (horizontal)
* @param yorder Derivative order in Y-direction (vertical)
* @param scale Scale factor or derivative size
*/
void
compute_scharr_derivatives
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
int
xorder
,
int
yorder
,
int
scale
)
{
Mat
kx
,
ky
;
compute_derivative_kernels
(
kx
,
ky
,
xorder
,
yorder
,
scale
);
sepFilter2D
(
src
,
dst
,
CV_32F
,
kx
,
ky
);
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief Compute derivative kernels for sizes different than 3
* @param _kx Horizontal kernel values
* @param _ky Vertical kernel values
* @param dx Derivative order in X-direction (horizontal)
* @param dy Derivative order in Y-direction (vertical)
* @param scale_ Scale factor or derivative size
*/
void
compute_derivative_kernels
(
cv
::
OutputArray
_kx
,
cv
::
OutputArray
_ky
,
int
dx
,
int
dy
,
int
scale
)
{
int
ksize
=
3
+
2
*
(
scale
-
1
);
// The standard Scharr kernel
if
(
scale
==
1
)
{
getDerivKernels
(
_kx
,
_ky
,
dx
,
dy
,
0
,
true
,
CV_32F
);
return
;
}
_kx
.
create
(
ksize
,
1
,
CV_32F
,
-
1
,
true
);
_ky
.
create
(
ksize
,
1
,
CV_32F
,
-
1
,
true
);
Mat
kx
=
_kx
.
getMat
();
Mat
ky
=
_ky
.
getMat
();
float
w
=
10.0
/
3.0
;
float
norm
=
1.0
/
(
2.0
*
scale
*
(
w
+
2.0
));
for
(
int
k
=
0
;
k
<
2
;
k
++
)
{
Mat
*
kernel
=
k
==
0
?
&
kx
:
&
ky
;
int
order
=
k
==
0
?
dx
:
dy
;
std
::
vector
<
float
>
kerI
(
ksize
);
for
(
int
t
=
0
;
t
<
ksize
;
t
++
)
{
kerI
[
t
]
=
0
;
}
if
(
order
==
0
)
{
kerI
[
0
]
=
norm
,
kerI
[
ksize
/
2
]
=
w
*
norm
,
kerI
[
ksize
-
1
]
=
norm
;
}
else
if
(
order
==
1
)
{
kerI
[
0
]
=
-
1
,
kerI
[
ksize
/
2
]
=
0
,
kerI
[
ksize
-
1
]
=
1
;
}
Mat
temp
(
kernel
->
rows
,
kernel
->
cols
,
CV_32F
,
&
kerI
[
0
]);
temp
.
copyTo
(
*
kernel
);
}
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function performs a scalar non-linear diffusion step
* @param Ld2 Output image in the evolution
* @param c Conductivity image
* @param Lstep Previous image in the evolution
* @param stepsize The step size in time units
* @note Forward Euler Scheme 3x3 stencil
* The function c is a scalar value that depends on the gradient norm
* dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy
*/
void
nld_step_scalar
(
cv
::
Mat
&
Ld
,
const
cv
::
Mat
&
c
,
cv
::
Mat
&
Lstep
,
float
stepsize
)
{
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for
(
int
i
=
1
;
i
<
Lstep
.
rows
-
1
;
i
++
)
{
for
(
int
j
=
1
;
j
<
Lstep
.
cols
-
1
;
j
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
j
+
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
+
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
)));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
j
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
-
1
)));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
i
+
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
+
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
)));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
i
-
1
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
-
1
)
+
j
)));
*
(
Lstep
.
ptr
<
float
>
(
i
)
+
j
)
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
}
for
(
int
j
=
1
;
j
<
Lstep
.
cols
-
1
;
j
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
0
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
0
)
+
j
+
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
+
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
)));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
0
)
+
j
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
0
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
-
1
)));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
0
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
)));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
0
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
0
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
0
)
+
j
)));
*
(
Lstep
.
ptr
<
float
>
(
0
)
+
j
)
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
for
(
int
j
=
1
;
j
<
Lstep
.
cols
-
1
;
j
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
+
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
+
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
-
1
)));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
2
)
+
j
))
+
(
*
(
c
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
))
-
(
*
(
Ld
.
ptr
<
float
>
(
Lstep
.
rows
-
2
)
+
j
)));
*
(
Lstep
.
ptr
<
float
>
(
Lstep
.
rows
-
1
)
+
j
)
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
for
(
int
i
=
1
;
i
<
Lstep
.
rows
-
1
;
i
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
i
)))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
))));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
i
)))
+
(
*
(
c
.
ptr
<
float
>
(
i
))))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
))));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
i
)))
+
(
*
(
c
.
ptr
<
float
>
(
i
+
1
))))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
+
1
)))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
))));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
i
-
1
)))
+
(
*
(
c
.
ptr
<
float
>
(
i
))))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
-
1
))));
*
(
Lstep
.
ptr
<
float
>
(
i
))
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
for
(
int
i
=
1
;
i
<
Lstep
.
rows
-
1
;
i
++
)
{
float
xpos
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)));
float
xneg
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
2
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
2
)));
float
ypos
=
((
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
i
+
1
)
+
Lstep
.
cols
-
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
+
1
)
+
Lstep
.
cols
-
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)));
float
yneg
=
((
*
(
c
.
ptr
<
float
>
(
i
-
1
)
+
Lstep
.
cols
-
1
))
+
(
*
(
c
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)))
*
((
*
(
Ld
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
))
-
(
*
(
Ld
.
ptr
<
float
>
(
i
-
1
)
+
Lstep
.
cols
-
1
)));
*
(
Lstep
.
ptr
<
float
>
(
i
)
+
Lstep
.
cols
-
1
)
=
0.5
*
stepsize
*
(
xpos
-
xneg
+
ypos
-
yneg
);
}
Ld
=
Ld
+
Lstep
;
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function checks if a given pixel is a maximum in a local neighbourhood
* @param img Input image where we will perform the maximum search
* @param dsize Half size of the neighbourhood
* @param value Response value at (x,y) position
* @param row Image row coordinate
* @param col Image column coordinate
* @param same_img Flag to indicate if the image value at (x,y) is in the input image
* @return 1->is maximum, 0->otherwise
*/
bool
check_maximum_neighbourhood
(
const
cv
::
Mat
&
img
,
int
dsize
,
float
value
,
int
row
,
int
col
,
bool
same_img
)
{
bool
response
=
true
;
for
(
int
i
=
row
-
dsize
;
i
<=
row
+
dsize
;
i
++
)
{
for
(
int
j
=
col
-
dsize
;
j
<=
col
+
dsize
;
j
++
)
{
if
(
i
>=
0
&&
i
<
img
.
rows
&&
j
>=
0
&&
j
<
img
.
cols
)
{
if
(
same_img
==
true
)
{
if
(
i
!=
row
||
j
!=
col
)
{
if
((
*
(
img
.
ptr
<
float
>
(
i
)
+
j
))
>
value
)
{
response
=
false
;
return
response
;
}
}
}
else
{
if
((
*
(
img
.
ptr
<
float
>
(
i
)
+
j
))
>
value
)
{
response
=
false
;
return
response
;
}
}
}
}
}
return
response
;
}
modules/features2d/src/kaze/nldiffusion_functions.h
0 → 100755
View file @
7a594354
/**
* @file nldiffusion_functions.h
* @brief Functions for non-linear diffusion applications:
* 2D Gaussian Derivatives
* Perona and Malik conductivity equations
* Perona and Malik evolution
* @date Dec 27, 2011
* @author Pablo F. Alcantarilla
*/
#ifndef NLDIFFUSION_FUNCTIONS_H_
#define NLDIFFUSION_FUNCTIONS_H_
//******************************************************************************
//******************************************************************************
// Includes
#include "config.h"
//*************************************************************************************
//*************************************************************************************
// Gaussian 2D convolution
void
gaussian_2D_convolution
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
int
ksize_x
,
int
ksize_y
,
float
sigma
);
// Diffusivity functions
void
pm_g1
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
float
k
);
void
pm_g2
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
float
k
);
void
weickert_diffusivity
(
const
cv
::
Mat
&
Lx
,
const
cv
::
Mat
&
Ly
,
cv
::
Mat
&
dst
,
float
k
);
float
compute_k_percentile
(
const
cv
::
Mat
&
img
,
float
perc
,
float
gscale
,
int
nbins
,
int
ksize_x
,
int
ksize_y
);
// Image derivatives
void
compute_scharr_derivatives
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
,
int
xorder
,
int
yorder
,
int
scale
);
void
compute_derivative_kernels
(
cv
::
OutputArray
_kx
,
cv
::
OutputArray
_ky
,
int
dx
,
int
dy
,
int
scale
);
// Nonlinear diffusion filtering scalar step
void
nld_step_scalar
(
cv
::
Mat
&
Ld
,
const
cv
::
Mat
&
c
,
cv
::
Mat
&
Lstep
,
float
stepsize
);
// For non-maxima suppresion
bool
check_maximum_neighbourhood
(
const
cv
::
Mat
&
img
,
int
dsize
,
float
value
,
int
row
,
int
col
,
bool
same_img
);
//*************************************************************************************
//*************************************************************************************
#endif // NLDIFFUSION_FUNCTIONS_H_
modules/features2d/src/kaze/utils.cpp
0 → 100644
View file @
7a594354
//=============================================================================
//
// utils.cpp
// Author: Pablo F. Alcantarilla
// Institution: University d'Auvergne
// Address: Clermont Ferrand, France
// Date: 29/12/2011
// Email: pablofdezalc@gmail.com
//
// KAZE Features Copyright 2012, Pablo F. Alcantarilla
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================
/**
* @file utils.cpp
* @brief Some useful functions
* @date Dec 29, 2011
* @author Pablo F. Alcantarilla
*/
#include "utils.h"
using
namespace
std
;
using
namespace
cv
;
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function copies the input image and converts the scale of the copied
* image prior visualization
* @param src Input image
* @param dst Output image
*/
void
copy_and_convert_scale
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
)
{
float
min_val
=
0
,
max_val
=
0
;
src
.
copyTo
(
dst
);
compute_min_32F
(
dst
,
min_val
);
dst
=
dst
-
min_val
;
compute_max_32F
(
dst
,
max_val
);
dst
=
dst
/
max_val
;
}
//*************************************************************************************
//*************************************************************************************
/*
void show_input_options_help(int example) {
fflush(stdout);
cout << endl;
cout << endl;
cout << "KAZE Features" << endl;
cout << "***********************************************************" << endl;
cout << "For running the program you need to type in the command line the following arguments: " << endl;
if (example == 0) {
cout << "./kaze_features img.jpg [options]" << endl;
}
else if (example == 1) {
cout << "./kaze_match img1.jpg img2.pgm homography.txt [options]" << endl;
}
else if (example == 2) {
cout << "./kaze_compare img1.jpg img2.pgm homography.txt [options]" << endl;
}
cout << endl;
cout << "The options are not mandatory. In case you do not specify additional options, default arguments will be used" << endl << endl;
cout << "Here is a description of the additional options: " << endl;
cout << "--verbose " << "\t\t if verbosity is required" << endl;
cout << "--help" << "\t\t for showing the command line options" << endl;
cout << "--soffset" << "\t\t the base scale offset (sigma units)" << endl;
cout << "--omax" << "\t\t maximum octave evolution of the image 2^sigma (coarsest scale)" << endl;
cout << "--nsublevels" << "\t\t number of sublevels per octave" << endl;
cout << "--dthreshold" << "\t\t Feature detector threshold response for accepting points (0.001 can be a good value)" << endl;
cout << "--descriptor" << "\t\t Descriptor Type 0 -> SURF, 1 -> M-SURF, 2 -> G-SURF" << endl;
cout << "--use_fed" "\t\t 1 -> Use FED, 0 -> Use AOS for the nonlinear diffusion filtering" << endl;
cout << "--upright" << "\t\t 0 -> Rotation Invariant, 1 -> No Rotation Invariant" << endl;
cout << "--extended" << "\t\t 0 -> Normal Descriptor (64), 1 -> Extended Descriptor (128)" << endl;
cout << "--output keypoints.txt" << "\t\t For saving the detected keypoints into a .txt file" << endl;
cout << "--save_scale_space" << "\t\t 1 in case we want to save the nonlinear scale space images. 0 otherwise" << endl;
cout << "--show_results" << "\t\t 1 in case we want to show detection results. 0 otherwise" << endl;
cout << endl;
}
*/
\ No newline at end of file
modules/features2d/src/kaze/utils.h
0 → 100644
View file @
7a594354
/**
* @file utils.h
* @brief Some useful functions
* @date Dec 29, 2011
* @author Pablo F. Alcantarilla
*/
#ifndef UTILS_H_
#define UTILS_H_
//******************************************************************************
//******************************************************************************
// OPENCV Includes
#include "precomp.hpp"
// System Includes
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cstdlib>
#include <string>
#include <vector>
#include <fstream>
#include <assert.h>
#include <math.h>
//*************************************************************************************
//*************************************************************************************
// Declaration of Functions
void
compute_min_32F
(
const
cv
::
Mat
&
src
,
float
&
value
);
void
compute_max_32F
(
const
cv
::
Mat
&
src
,
float
&
value
);
void
convert_scale
(
cv
::
Mat
&
src
);
void
copy_and_convert_scale
(
const
cv
::
Mat
&
src
,
cv
::
Mat
&
dst
);
//*************************************************************************************
//*************************************************************************************
#endif // UTILS_H_
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