Merge pull request #9303 from alalek:akaze_update

pull/9299/head
Alexander Alekhin 8 years ago committed by GitHub
commit 922ac1a1ec
  1. 17
      modules/core/include/opencv2/core/utility.hpp
  2. 5
      modules/core/src/matrix.cpp
  3. 4
      modules/features2d/src/akaze.cpp
  4. 354
      modules/features2d/src/kaze/AKAZEFeatures.cpp
  5. 2
      modules/features2d/src/kaze/AKAZEFeatures.h
  6. 48
      modules/features2d/src/kaze/KAZEFeatures.cpp
  7. 2
      modules/features2d/src/kaze/fed.cpp
  8. 2
      modules/features2d/src/kaze/nldiffusion_functions.cpp
  9. 55
      modules/features2d/src/kaze/utils.h
  10. 8
      modules/features2d/test/test_descriptors_invariance.cpp
  11. 117
      modules/features2d/test/test_descriptors_regression.cpp
  12. 2
      modules/features2d/test/test_detectors_invariance.cpp
  13. 5
      modules/photo/src/fast_nlmeans_denoising_opencl.hpp
  14. 4
      modules/stitching/perf/perf_stich.cpp

@ -444,6 +444,23 @@ static inline size_t alignSize(size_t sz, int n)
return (sz + n-1) & -n; return (sz + n-1) & -n;
} }
/** @brief Integer division with result round up.
Use this function instead of `ceil((float)a / b)` expressions.
@sa alignSize
*/
static inline int divUp(int a, unsigned int b)
{
CV_DbgAssert(a >= 0);
return (a + b - 1) / b;
}
/** @overload */
static inline size_t divUp(size_t a, unsigned int b)
{
return (a + b - 1) / b;
}
/** @brief Enables or disables the optimized code. /** @brief Enables or disables the optimized code.
The function can be used to dynamically turn on and off optimized code (code that uses SSE2, AVX, The function can be used to dynamically turn on and off optimized code (code that uses SSE2, AVX,

@ -3406,11 +3406,6 @@ static TransposeInplaceFunc transposeInplaceTab[] =
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
static inline int divUp(int a, int b)
{
return (a + b - 1) / b;
}
static bool ocl_transpose( InputArray _src, OutputArray _dst ) static bool ocl_transpose( InputArray _src, OutputArray _dst )
{ {
const ocl::Device & dev = ocl::Device::getDefault(); const ocl::Device & dev = ocl::Device::getDefault();

@ -113,12 +113,12 @@ namespace cv
if (descriptor_size == 0) if (descriptor_size == 0)
{ {
int t = (6 + 36 + 120) * descriptor_channels; int t = (6 + 36 + 120) * descriptor_channels;
return (int)ceil(t / 8.); return divUp(t, 8);
} }
else else
{ {
// We use the random bit selection length binary descriptor // We use the random bit selection length binary descriptor
return (int)ceil(descriptor_size / 8.); return divUp(descriptor_size, 8);
} }
default: default:

@ -74,12 +74,12 @@ void AKAZEFeatures::Allocate_Memory_Evolution(void) {
Evolution step; Evolution step;
step.size = Size(level_width, level_height); step.size = Size(level_width, level_height);
step.esigma = options_.soffset*pow(2.f, (float)(j) / (float)(options_.nsublevels) + i); step.esigma = options_.soffset*pow(2.f, (float)(j) / (float)(options_.nsublevels) + i);
step.sigma_size = fRound(step.esigma * options_.derivative_factor / power); // In fact sigma_size only depends on j step.sigma_size = cvRound(step.esigma * options_.derivative_factor / power); // In fact sigma_size only depends on j
step.etime = 0.5f * (step.esigma * step.esigma); step.etime = 0.5f * (step.esigma * step.esigma);
step.octave = i; step.octave = i;
step.sublevel = j; step.sublevel = j;
step.octave_ratio = (float)power; step.octave_ratio = (float)power;
step.border = fRound(smax * step.sigma_size) + 1; step.border = cvRound(smax * step.sigma_size) + 1;
evolution_.push_back(step); evolution_.push_back(step);
} }
@ -106,7 +106,7 @@ void AKAZEFeatures::Allocate_Memory_Evolution(void) {
*/ */
static inline int getGaussianKernelSize(float sigma) { static inline int getGaussianKernelSize(float sigma) {
// Compute an appropriate kernel size according to the specified sigma // Compute an appropriate kernel size according to the specified sigma
int ksize = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f))); int ksize = (int)cvCeil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
ksize |= 1; // kernel should be odd ksize |= 1; // kernel should be odd
return ksize; return ksize;
} }
@ -890,11 +890,11 @@ public:
{ {
for (int i = range.start; i < range.end; i++) for (int i = range.start; i < range.end; i++)
{ {
Get_SURF_Descriptor_Upright_64((*keypoints_)[i], descriptors_->ptr<float>(i)); Get_SURF_Descriptor_Upright_64((*keypoints_)[i], descriptors_->ptr<float>(i), descriptors_->cols);
} }
} }
void Get_SURF_Descriptor_Upright_64(const KeyPoint& kpt, float* desc) const; void Get_SURF_Descriptor_Upright_64(const KeyPoint& kpt, float* desc, int desc_size) const;
private: private:
std::vector<KeyPoint>* keypoints_; std::vector<KeyPoint>* keypoints_;
@ -916,11 +916,11 @@ public:
{ {
for (int i = range.start; i < range.end; i++) for (int i = range.start; i < range.end; i++)
{ {
Get_SURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr<float>(i)); Get_SURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr<float>(i), descriptors_->cols);
} }
} }
void Get_SURF_Descriptor_64(const KeyPoint& kpt, float* desc) const; void Get_SURF_Descriptor_64(const KeyPoint& kpt, float* desc, int desc_size) const;
private: private:
std::vector<KeyPoint>* keypoints_; std::vector<KeyPoint>* keypoints_;
@ -942,11 +942,11 @@ public:
{ {
for (int i = range.start; i < range.end; i++) for (int i = range.start; i < range.end; i++)
{ {
Get_MSURF_Upright_Descriptor_64((*keypoints_)[i], descriptors_->ptr<float>(i)); Get_MSURF_Upright_Descriptor_64((*keypoints_)[i], descriptors_->ptr<float>(i), descriptors_->cols);
} }
} }
void Get_MSURF_Upright_Descriptor_64(const KeyPoint& kpt, float* desc) const; void Get_MSURF_Upright_Descriptor_64(const KeyPoint& kpt, float* desc, int desc_size) const;
private: private:
std::vector<KeyPoint>* keypoints_; std::vector<KeyPoint>* keypoints_;
@ -968,11 +968,11 @@ public:
{ {
for (int i = range.start; i < range.end; i++) for (int i = range.start; i < range.end; i++)
{ {
Get_MSURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr<float>(i)); Get_MSURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr<float>(i), descriptors_->cols);
} }
} }
void Get_MSURF_Descriptor_64(const KeyPoint& kpt, float* desc) const; void Get_MSURF_Descriptor_64(const KeyPoint& kpt, float* desc, int desc_size) const;
private: private:
std::vector<KeyPoint>* keypoints_; std::vector<KeyPoint>* keypoints_;
@ -995,11 +995,11 @@ public:
{ {
for (int i = range.start; i < range.end; i++) for (int i = range.start; i < range.end; i++)
{ {
Get_Upright_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr<unsigned char>(i)); Get_Upright_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr<unsigned char>(i), descriptors_->cols);
} }
} }
void Get_Upright_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char* desc) const; void Get_Upright_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char* desc, int desc_size) const;
private: private:
std::vector<KeyPoint>* keypoints_; std::vector<KeyPoint>* keypoints_;
@ -1030,11 +1030,11 @@ public:
{ {
for (int i = range.start; i < range.end; i++) for (int i = range.start; i < range.end; i++)
{ {
Get_Upright_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr<unsigned char>(i)); Get_Upright_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr<unsigned char>(i), descriptors_->cols);
} }
} }
void Get_Upright_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char* desc) const; void Get_Upright_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char* desc, int desc_size) const;
private: private:
std::vector<KeyPoint>* keypoints_; std::vector<KeyPoint>* keypoints_;
@ -1061,11 +1061,11 @@ public:
{ {
for (int i = range.start; i < range.end; i++) for (int i = range.start; i < range.end; i++)
{ {
Get_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr<unsigned char>(i)); Get_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr<unsigned char>(i), descriptors_->cols);
} }
} }
void Get_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char* desc) const; void Get_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char* desc, int desc_size) const;
void MLDB_Fill_Values(float* values, int sample_step, int level, void MLDB_Fill_Values(float* values, int sample_step, int level,
float xf, float yf, float co, float si, float scale) const; float xf, float yf, float co, float si, float scale) const;
void MLDB_Binary_Comparisons(float* values, unsigned char* desc, void MLDB_Binary_Comparisons(float* values, unsigned char* desc,
@ -1100,11 +1100,11 @@ public:
{ {
for (int i = range.start; i < range.end; i++) for (int i = range.start; i < range.end; i++)
{ {
Get_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr<unsigned char>(i)); Get_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr<unsigned char>(i), descriptors_->cols);
} }
} }
void Get_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char* desc) const; void Get_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char* desc, int desc_size) const;
private: private:
std::vector<KeyPoint>* keypoints_; std::vector<KeyPoint>* keypoints_;
@ -1131,20 +1131,17 @@ void AKAZEFeatures::Compute_Descriptors(std::vector<KeyPoint>& kpts, OutputArray
} }
// Allocate memory for the matrix with the descriptors // Allocate memory for the matrix with the descriptors
if (options_.descriptor < AKAZE::DESCRIPTOR_MLDB_UPRIGHT) { int descriptor_size = 64;
descriptors.create((int)kpts.size(), 64, CV_32FC1); int descriptor_type = CV_32FC1;
} if (options_.descriptor >= AKAZE::DESCRIPTOR_MLDB_UPRIGHT)
else { {
// We use the full length binary descriptor -> 486 bits int descriptor_bits = (options_.descriptor_size == 0)
if (options_.descriptor_size == 0) { ? (6 + 36 + 120)*options_.descriptor_channels // the full length binary descriptor -> 486 bits
int t = (6 + 36 + 120)*options_.descriptor_channels; : options_.descriptor_size; // the random bit selection length binary descriptor
descriptors.create((int)kpts.size(), (int)ceil(t / 8.), CV_8UC1); descriptor_size = divUp(descriptor_bits, 8);
} descriptor_type = CV_8UC1;
else {
// We use the random bit selection length binary descriptor
descriptors.create((int)kpts.size(), (int)ceil(options_.descriptor_size / 8.), CV_8UC1);
}
} }
descriptors.create((int)kpts.size(), descriptor_size, descriptor_type);
Mat desc = descriptors.getMat(); Mat desc = descriptors.getMat();
@ -1208,12 +1205,11 @@ void Sample_Derivative_Response_Radius6(const Mat &Lx, const Mat &Ly,
{ 0.00344629f, 0.00318132f, 0.00250252f, 0.00167749f, 0.00095820f, 0.00046640f, 0.00019346f }, { 0.00344629f, 0.00318132f, 0.00250252f, 0.00167749f, 0.00095820f, 0.00046640f, 0.00019346f },
{ 0.00142946f, 0.00131956f, 0.00103800f, 0.00069579f, 0.00039744f, 0.00019346f, 0.00008024f } { 0.00142946f, 0.00131956f, 0.00103800f, 0.00069579f, 0.00039744f, 0.00019346f, 0.00008024f }
}; };
static const int id[] = { 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6 };
static const struct gtable static const struct gtable
{ {
float weight[109]; float weight[109];
int8_t xidx[109]; int xidx[109];
int8_t yidx[109]; int yidx[109];
explicit gtable(void) explicit gtable(void)
{ {
@ -1222,29 +1218,28 @@ void Sample_Derivative_Response_Radius6(const Mat &Lx, const Mat &Ly,
for (int i = -6; i <= 6; ++i) { for (int i = -6; i <= 6; ++i) {
for (int j = -6; j <= 6; ++j) { for (int j = -6; j <= 6; ++j) {
if (i*i + j*j < 36) { if (i*i + j*j < 36) {
weight[k] = gauss25[id[i + 6]][id[j + 6]]; CV_Assert(k < 109);
yidx[k] = static_cast<int8_t>(i); weight[k] = gauss25[abs(i)][abs(j)];
xidx[k] = static_cast<int8_t>(j); yidx[k] = i;
xidx[k] = j;
++k; ++k;
} }
} }
} }
CV_DbgAssert(k == 109);
} }
} g; } g;
const float * lx = Lx.ptr<float>(0); CV_Assert(x0 - 6 * scale >= 0 && x0 + 6 * scale < Lx.cols);
const float * ly = Ly.ptr<float>(0); CV_Assert(y0 - 6 * scale >= 0 && y0 + 6 * scale < Lx.rows);
int cols = Lx.cols;
for (int i = 0; i < 109; i++) {
int j = (y0 + g.yidx[i] * scale) * cols + (x0 + g.xidx[i] * scale);
resX[i] = g.weight[i] * lx[j]; for (int i = 0; i < 109; i++)
resY[i] = g.weight[i] * ly[j]; {
int y = y0 + g.yidx[i] * scale;
int x = x0 + g.xidx[i] * scale;
CV_DbgAssert(isfinite(resX[i])); float w = g.weight[i];
CV_DbgAssert(isfinite(resY[i])); resX[i] = w * Lx.at<float>(y, x);
resY[i] = w * Ly.at<float>(y, x);
} }
} }
@ -1253,7 +1248,7 @@ void Sample_Derivative_Response_Radius6(const Mat &Lx, const Mat &Ly,
* @param a[] Input floating point array to sort * @param a[] Input floating point array to sort
* @param n The length of a[] * @param n The length of a[]
* @param quantum The interval to convert a[i]'s float values to integers * @param quantum The interval to convert a[i]'s float values to integers
* @param max The upper bound of a[], meaning a[i] must be in [0, max] * @param nkeys a[i] < nkeys * quantum
* @param idx[] Output array of the indices: a[idx[i]] forms a sorted array * @param idx[] Output array of the indices: a[idx[i]] forms a sorted array
* @param cum[] Output array of the starting indices of quantized floats * @param cum[] Output array of the starting indices of quantized floats
* @note The values of a[] in [k*quantum, (k + 1)*quantum) is labeled by * @note The values of a[] in [k*quantum, (k + 1)*quantum) is labeled by
@ -1263,25 +1258,35 @@ void Sample_Derivative_Response_Radius6(const Mat &Lx, const Mat &Ly,
*/ */
static inline static inline
void quantized_counting_sort(const float a[], const int n, void quantized_counting_sort(const float a[], const int n,
const float quantum, const float max, const float quantum, const int nkeys,
uint8_t idx[], uint8_t cum[]) int idx[/*n*/], int cum[/*nkeys + 1*/])
{ {
const int nkeys = (int)(max / quantum); memset(cum, 0, sizeof(cum[0]) * (nkeys + 1));
// The size of cum[] must be nkeys + 1
memset(cum, 0, nkeys + 1);
// Count up the quantized values // Count up the quantized values
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
cum[(int)(a[i] / quantum)]++; {
int b = (int)(a[i] / quantum);
if (b < 0 || b >= nkeys)
b = 0;
cum[b]++;
}
// Compute the inclusive prefix sum i.e. the end indices; cum[nkeys] is the total // Compute the inclusive prefix sum i.e. the end indices; cum[nkeys] is the total
for (int i = 1; i <= nkeys; i++) for (int i = 1; i <= nkeys; i++)
{
cum[i] += cum[i - 1]; cum[i] += cum[i - 1];
}
CV_Assert(cum[nkeys] == n);
// Generate the sorted indices; cum[] becomes the exclusive prefix sum i.e. the start indices of keys // Generate the sorted indices; cum[] becomes the exclusive prefix sum i.e. the start indices of keys
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
idx[--cum[(int)(a[i] / quantum)]] = static_cast<uint8_t>(i); {
int b = (int)(a[i] / quantum);
if (b < 0 || b >= nkeys)
b = 0;
idx[--cum[b]] = i;
}
} }
/** /**
@ -1296,9 +1301,9 @@ void Compute_Main_Orientation(KeyPoint& kpt, const std::vector<Evolution>& evolu
// get the right evolution level for this keypoint // get the right evolution level for this keypoint
const Evolution& e = evolution[kpt.class_id]; const Evolution& e = evolution[kpt.class_id];
// Get the information from the keypoint // Get the information from the keypoint
int scale = fRound(0.5f * kpt.size / e.octave_ratio); int scale = cvRound(0.5f * kpt.size / e.octave_ratio);
int x0 = fRound(kpt.pt.x / e.octave_ratio); int x0 = cvRound(kpt.pt.x / e.octave_ratio);
int y0 = fRound(kpt.pt.y / e.octave_ratio); int y0 = cvRound(kpt.pt.y / e.octave_ratio);
// Sample derivatives responses for the points within radius of 6*scale // Sample derivatives responses for the points within radius of 6*scale
const int ang_size = 109; const int ang_size = 109;
@ -1312,17 +1317,18 @@ void Compute_Main_Orientation(KeyPoint& kpt, const std::vector<Evolution>& evolu
// Sort by the angles; angles are labeled by slices of 0.15 radian // Sort by the angles; angles are labeled by slices of 0.15 radian
const int slices = 42; const int slices = 42;
const float ang_step = (float)(2.0 * CV_PI / slices); const float ang_step = (float)(2.0 * CV_PI / slices);
uint8_t slice[slices + 1]; int slice[slices + 1];
uint8_t sorted_idx[ang_size]; int sorted_idx[ang_size];
quantized_counting_sort(Ang, ang_size, ang_step, (float)(2.0 * CV_PI), sorted_idx, slice); quantized_counting_sort(Ang, ang_size, ang_step, slices, sorted_idx, slice);
// Find the main angle by sliding a window of 7-slice size(=PI/3) around the keypoint // Find the main angle by sliding a window of 7-slice size(=PI/3) around the keypoint
const int win = 7; const int win = 7;
float maxX = 0.0f, maxY = 0.0f; float maxX = 0.0f, maxY = 0.0f;
for (int i = slice[0]; i < slice[win]; i++) { for (int i = slice[0]; i < slice[win]; i++) {
maxX += resX[sorted_idx[i]]; const int idx = sorted_idx[i];
maxY += resY[sorted_idx[i]]; maxX += resX[idx];
maxY += resY[idx];
} }
float maxNorm = maxX * maxX + maxY * maxY; float maxNorm = maxX * maxX + maxY * maxY;
@ -1333,8 +1339,9 @@ void Compute_Main_Orientation(KeyPoint& kpt, const std::vector<Evolution>& evolu
float sumX = 0.0f, sumY = 0.0f; float sumX = 0.0f, sumY = 0.0f;
for (int i = slice[sn]; i < slice[sn + win]; i++) { for (int i = slice[sn]; i < slice[sn + win]; i++) {
sumX += resX[sorted_idx[i]]; const int idx = sorted_idx[i];
sumY += resY[sorted_idx[i]]; sumX += resX[idx];
sumY += resY[idx];
} }
float norm = sumX * sumX + sumY * sumY; float norm = sumX * sumX + sumY * sumY;
@ -1350,12 +1357,14 @@ void Compute_Main_Orientation(KeyPoint& kpt, const std::vector<Evolution>& evolu
float sumX = 0.0f, sumY = 0.0f; float sumX = 0.0f, sumY = 0.0f;
for (int i = slice[sn]; i < slice[slices]; i++) { for (int i = slice[sn]; i < slice[slices]; i++) {
sumX += resX[sorted_idx[i]]; const int idx = sorted_idx[i];
sumY += resY[sorted_idx[i]]; sumX += resX[idx];
sumY += resY[idx];
} }
for (int i = slice[0]; i < slice[remain]; i++) { for (int i = slice[0]; i < slice[remain]; i++) {
sumX += resX[sorted_idx[i]]; const int idx = sorted_idx[i];
sumY += resY[sorted_idx[i]]; sumX += resX[idx];
sumY += resY[idx];
} }
float norm = sumX * sumX + sumY * sumY; float norm = sumX * sumX + sumY * sumY;
@ -1410,7 +1419,10 @@ void AKAZEFeatures::Compute_Keypoints_Orientation(std::vector<KeyPoint>& kpts) c
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
* ECCV 2008 * ECCV 2008
*/ */
void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const KeyPoint& kpt, float *desc) const { void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const KeyPoint& kpt, float *desc, int desc_size) const {
const int dsize = 64;
CV_Assert(desc_size == dsize);
float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0; 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 rx = 0.0, ry = 0.0, len = 0.0, xf = 0.0, yf = 0.0, ys = 0.0, xs = 0.0;
@ -1418,7 +1430,7 @@ void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const
int x1 = 0, y1 = 0, sample_step = 0, pattern_size = 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; 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; 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; int scale = 0;
// Subregion centers for the 4x4 gaussian weighting // Subregion centers for the 4x4 gaussian weighting
float cx = -0.5f, cy = 0.5f; float cx = -0.5f, cy = 0.5f;
@ -1426,13 +1438,12 @@ void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const
const std::vector<Evolution>& evolution = *evolution_; const std::vector<Evolution>& evolution = *evolution_;
// Set the descriptor size and the sample and pattern sizes // Set the descriptor size and the sample and pattern sizes
dsize = 64;
sample_step = 5; sample_step = 5;
pattern_size = 12; pattern_size = 12;
// Get the information from the keypoint // Get the information from the keypoint
ratio = (float)(1 << kpt.octave); ratio = (float)(1 << kpt.octave);
scale = fRound(0.5f*kpt.size / ratio); scale = cvRound(0.5f*kpt.size / ratio);
const int level = kpt.class_id; const int level = kpt.class_id;
Mat Lx = evolution[level].Mx; Mat Lx = evolution[level].Mx;
Mat Ly = evolution[level].My; Mat Ly = evolution[level].My;
@ -1469,11 +1480,11 @@ void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const
//Get the gaussian weighted x and y responses //Get the gaussian weighted x and y responses
gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.50f*scale); gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.50f*scale);
y1 = (int)(sample_y - .5); y1 = (int)(sample_y - .5f);
x1 = (int)(sample_x - .5); x1 = (int)(sample_x - .5f);
y2 = (int)(sample_y + .5); y2 = (int)(sample_y + .5f);
x2 = (int)(sample_x + .5); x2 = (int)(sample_x + .5f);
fx = sample_x - x1; fx = sample_x - x1;
fy = sample_y - y1; fy = sample_y - y1;
@ -1517,6 +1528,8 @@ void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const
i += 9; i += 9;
} }
CV_Assert(dcount == desc_size);
// convert to unit vector // convert to unit vector
len = sqrt(len); len = sqrt(len);
@ -1535,7 +1548,10 @@ void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const
* from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching,
* ECCV 2008 * ECCV 2008
*/ */
void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, float *desc) const { void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, float *desc, int desc_size) const {
const int dsize = 64;
CV_Assert(desc_size == dsize);
float dx = 0.0, dy = 0.0, mdx = 0.0, mdy = 0.0, gauss_s1 = 0.0, gauss_s2 = 0.0; 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 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;
@ -1543,7 +1559,7 @@ void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, f
float fx = 0.0, fy = 0.0, ratio = 0.0, res1 = 0.0, res2 = 0.0, res3 = 0.0, res4 = 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 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 kx = 0, ky = 0, i = 0, j = 0, dcount = 0;
int scale = 0, dsize = 0; int scale = 0;
// Subregion centers for the 4x4 gaussian weighting // Subregion centers for the 4x4 gaussian weighting
float cx = -0.5f, cy = 0.5f; float cx = -0.5f, cy = 0.5f;
@ -1551,14 +1567,13 @@ void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, f
const std::vector<Evolution>& evolution = *evolution_; const std::vector<Evolution>& evolution = *evolution_;
// Set the descriptor size and the sample and pattern sizes // Set the descriptor size and the sample and pattern sizes
dsize = 64;
sample_step = 5; sample_step = 5;
pattern_size = 12; pattern_size = 12;
// Get the information from the keypoint // Get the information from the keypoint
ratio = (float)(1 << kpt.octave); ratio = (float)(1 << kpt.octave);
scale = fRound(0.5f*kpt.size / ratio); scale = cvRound(0.5f*kpt.size / ratio);
angle = (kpt.angle * static_cast<float>(CV_PI)) / 180.f; angle = kpt.angle * static_cast<float>(CV_PI / 180.f);
const int level = kpt.class_id; const int level = kpt.class_id;
Mat Lx = evolution[level].Mx; Mat Lx = evolution[level].Mx;
Mat Ly = evolution[level].My; Mat Ly = evolution[level].My;
@ -1598,11 +1613,11 @@ void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, f
// Get the gaussian weighted x and y responses // Get the gaussian weighted x and y responses
gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale);
y1 = fRound(sample_y - 0.5f); y1 = cvRound(sample_y - 0.5f);
x1 = fRound(sample_x - 0.5f); x1 = cvRound(sample_x - 0.5f);
y2 = fRound(sample_y + 0.5f); y2 = cvRound(sample_y + 0.5f);
x2 = fRound(sample_x + 0.5f); x2 = cvRound(sample_x + 0.5f);
// fix crash: indexing with out-of-bounds index, this might happen near the edges of image // fix crash: indexing with out-of-bounds index, this might happen near the edges of image
// clip values so they fit into the image // clip values so they fit into the image
@ -1655,6 +1670,8 @@ void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, f
i += 9; i += 9;
} }
CV_Assert(dcount == desc_size);
// convert to unit vector // convert to unit vector
len = sqrt(len); len = sqrt(len);
@ -1670,7 +1687,7 @@ void MSURF_Descriptor_64_Invoker::Get_MSURF_Descriptor_64(const KeyPoint& kpt, f
* @param kpt Input keypoint * @param kpt Input keypoint
* @param desc Descriptor vector * @param desc Descriptor vector
*/ */
void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char *desc) const { void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char *desc, int desc_size) const {
float di = 0.0, dx = 0.0, dy = 0.0; 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 ri = 0.0, rx = 0.0, ry = 0.0, xf = 0.0, yf = 0.0;
@ -1682,16 +1699,14 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons
const AKAZEOptions & options = *options_; const AKAZEOptions & options = *options_;
const std::vector<Evolution>& evolution = *evolution_; const std::vector<Evolution>& evolution = *evolution_;
// Matrices for the M-LDB descriptor // Buffer for the M-LDB descriptor
Mat values[3] = { const int max_channels = 3;
Mat(4, options.descriptor_channels, CV_32FC1), CV_Assert(options.descriptor_channels <= max_channels);
Mat(9, options.descriptor_channels, CV_32FC1), float values[16*max_channels];
Mat(16, options.descriptor_channels, CV_32FC1)
};
// Get the information from the keypoint // Get the information from the keypoint
ratio = (float)(1 << kpt.octave); ratio = (float)(1 << kpt.octave);
scale = fRound(0.5f*kpt.size / ratio); scale = cvRound(0.5f*kpt.size / ratio);
const int level = kpt.class_id; const int level = kpt.class_id;
Mat Lx = evolution[level].Mx; Mat Lx = evolution[level].Mx;
Mat Ly = evolution[level].My; Mat Ly = evolution[level].My;
@ -1701,12 +1716,15 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons
// For 2x2 grid, 3x3 grid and 4x4 grid // For 2x2 grid, 3x3 grid and 4x4 grid
const int pattern_size = options_->descriptor_pattern_size; const int pattern_size = options_->descriptor_pattern_size;
int sample_step[3] = { CV_Assert((pattern_size & 1) == 0);
const int sample_step[3] = {
pattern_size, pattern_size,
static_cast<int>(ceil(pattern_size*2./3.)), divUp(pattern_size * 2, 3),
pattern_size / 2 divUp(pattern_size, 2)
}; };
memset(desc, 0, desc_size);
// For the three grids // For the three grids
for (int z = 0; z < 3; z++) { for (int z = 0; z < 3; z++) {
dcount2 = 0; dcount2 = 0;
@ -1723,8 +1741,8 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons
sample_y = yf + l*scale; sample_y = yf + l*scale;
sample_x = xf + k*scale; sample_x = xf + k*scale;
y1 = fRound(sample_y); y1 = cvRound(sample_y);
x1 = fRound(sample_x); x1 = cvRound(sample_x);
ri = *(Lt.ptr<float>(y1)+x1); ri = *(Lt.ptr<float>(y1)+x1);
rx = *(Lx.ptr<float>(y1)+x1); rx = *(Lx.ptr<float>(y1)+x1);
@ -1741,7 +1759,7 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons
dx /= nsamples; dx /= nsamples;
dy /= nsamples; dy /= nsamples;
float *val = values[z].ptr<float>(dcount2); float *val = &values[dcount2*max_channels];
*(val) = di; *(val) = di;
*(val+1) = dx; *(val+1) = dx;
*(val+2) = dy; *(val+2) = dy;
@ -1753,13 +1771,11 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons
const int num = (z + 2) * (z + 2); const int num = (z + 2) * (z + 2);
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
for (int j = i + 1; j < num; j++) { for (int j = i + 1; j < num; j++) {
const float * valI = values[z].ptr<float>(i); const float * valI = &values[i*max_channels];
const float * valJ = values[z].ptr<float>(j); const float * valJ = &values[j*max_channels];
for (int k = 0; k < 3; ++k) { for (int k = 0; k < 3; ++k) {
if (*(valI + k) > *(valJ + k)) { if (*(valI + k) > *(valJ + k)) {
desc[dcount1 / 8] |= (1 << (dcount1 % 8)); desc[dcount1 / 8] |= (1 << (dcount1 % 8));
} else {
desc[dcount1 / 8] &= ~(1 << (dcount1 % 8));
} }
dcount1++; dcount1++;
} }
@ -1767,6 +1783,9 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons
} }
} // for (int z = 0; z < 3; z++) } // for (int z = 0; z < 3; z++)
CV_Assert(dcount1 <= desc_size*8);
CV_Assert(divUp(dcount1, 8) == desc_size);
} }
void MLDB_Full_Descriptor_Invoker::MLDB_Fill_Values(float* values, int sample_step, const int level, void MLDB_Full_Descriptor_Invoker::MLDB_Fill_Values(float* values, int sample_step, const int level,
@ -1791,8 +1810,8 @@ void MLDB_Full_Descriptor_Invoker::MLDB_Fill_Values(float* values, int sample_st
float sample_y = yf + (l*co * scale + k*si*scale); float sample_y = yf + (l*co * scale + k*si*scale);
float sample_x = xf + (-l*si * scale + k*co*scale); float sample_x = xf + (-l*si * scale + k*co*scale);
int y1 = fRound(sample_y); int y1 = cvRound(sample_y);
int x1 = fRound(sample_x); int x1 = cvRound(sample_x);
// fix crash: indexing with out-of-bounds index, this might happen near the edges of image // fix crash: indexing with out-of-bounds index, this might happen near the edges of image
// clip values so they fit into the image // clip values so they fit into the image
@ -1852,10 +1871,6 @@ void MLDB_Full_Descriptor_Invoker::MLDB_Binary_Comparisons(float* values, unsign
if (ival > ivalues[chan * j + pos]) { if (ival > ivalues[chan * j + pos]) {
desc[dpos >> 3] |= (1 << (dpos & 7)); desc[dpos >> 3] |= (1 << (dpos & 7));
} }
else {
desc[dpos >> 3] &= ~(1 << (dpos & 7));
}
dpos++; dpos++;
} }
} }
@ -1869,30 +1884,41 @@ void MLDB_Full_Descriptor_Invoker::MLDB_Binary_Comparisons(float* values, unsign
* @param kpt Input keypoint * @param kpt Input keypoint
* @param desc Descriptor vector * @param desc Descriptor vector
*/ */
void MLDB_Full_Descriptor_Invoker::Get_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char *desc) const { void MLDB_Full_Descriptor_Invoker::Get_MLDB_Full_Descriptor(const KeyPoint& kpt, unsigned char *desc, int desc_size) const {
const int max_channels = 3; const int max_channels = 3;
CV_Assert(options_->descriptor_channels <= max_channels); CV_Assert(options_->descriptor_channels <= max_channels);
const int pattern_size = options_->descriptor_pattern_size;
float values[16*max_channels]; float values[16*max_channels];
const double size_mult[3] = {1, 2.0/3.0, 1.0/2.0}; CV_Assert((pattern_size & 1) == 0);
//const double size_mult[3] = {1, 2.0/3.0, 1.0/2.0};
const int sample_step[3] = { // static_cast<int>(ceil(pattern_size * size_mult[lvl]))
pattern_size,
divUp(pattern_size * 2, 3),
divUp(pattern_size, 2)
};
float ratio = (float)(1 << kpt.octave); float ratio = (float)(1 << kpt.octave);
float scale = (float)fRound(0.5f*kpt.size / ratio); float scale = (float)cvRound(0.5f*kpt.size / ratio);
float xf = kpt.pt.x / ratio; float xf = kpt.pt.x / ratio;
float yf = kpt.pt.y / ratio; float yf = kpt.pt.y / ratio;
float angle = (kpt.angle * static_cast<float>(CV_PI)) / 180.f; float angle = kpt.angle * static_cast<float>(CV_PI / 180.f);
float co = cos(angle); float co = cos(angle);
float si = sin(angle); float si = sin(angle);
int pattern_size = options_->descriptor_pattern_size;
int dpos = 0; memset(desc, 0, desc_size);
for(int lvl = 0; lvl < 3; lvl++) {
int dpos = 0;
for(int lvl = 0; lvl < 3; lvl++)
{
int val_count = (lvl + 2) * (lvl + 2); int val_count = (lvl + 2) * (lvl + 2);
int sample_step = static_cast<int>(ceil(pattern_size * size_mult[lvl])); MLDB_Fill_Values(values, sample_step[lvl], kpt.class_id, xf, yf, co, si, scale);
MLDB_Fill_Values(values, sample_step, kpt.class_id, xf, yf, co, si, scale);
MLDB_Binary_Comparisons(values, desc, val_count, dpos); MLDB_Binary_Comparisons(values, desc, val_count, dpos);
} }
CV_Assert(dpos == 486);
CV_Assert(divUp(dpos, 8) == desc_size);
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -1903,7 +1929,7 @@ void MLDB_Full_Descriptor_Invoker::Get_MLDB_Full_Descriptor(const KeyPoint& kpt,
* @param kpt Input keypoint * @param kpt Input keypoint
* @param desc Descriptor vector * @param desc Descriptor vector
*/ */
void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char *desc) const { void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char *desc, int desc_size) const {
float di = 0.f, dx = 0.f, dy = 0.f; float di = 0.f, dx = 0.f, dy = 0.f;
float rx = 0.f, ry = 0.f; float rx = 0.f, ry = 0.f;
@ -1915,8 +1941,8 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint&
// Get the information from the keypoint // Get the information from the keypoint
float ratio = (float)(1 << kpt.octave); float ratio = (float)(1 << kpt.octave);
int scale = fRound(0.5f*kpt.size / ratio); int scale = cvRound(0.5f*kpt.size / ratio);
float angle = (kpt.angle * static_cast<float>(CV_PI)) / 180.f; float angle = kpt.angle * static_cast<float>(CV_PI / 180.f);
const int level = kpt.class_id; const int level = kpt.class_id;
Mat Lx = evolution[level].Mx; Mat Lx = evolution[level].Mx;
Mat Ly = evolution[level].My; Mat Ly = evolution[level].My;
@ -1927,17 +1953,25 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint&
float si = sin(angle); float si = sin(angle);
// Allocate memory for the matrix of values // Allocate memory for the matrix of values
Mat values((4 + 9 + 16)*options.descriptor_channels, 1, CV_32FC1); // Buffer for the M-LDB descriptor
const int max_channels = 3;
const int channels = options.descriptor_channels;
CV_Assert(channels <= max_channels);
float values[(4 + 9 + 16)*max_channels];
// Sample everything, but only do the comparisons // Sample everything, but only do the comparisons
vector<int> steps(3); const int pattern_size = options.descriptor_pattern_size;
steps.at(0) = options.descriptor_pattern_size; CV_Assert((pattern_size & 1) == 0);
steps.at(1) = (int)ceil(2.f*options.descriptor_pattern_size / 3.f); const int sample_steps[3] = {
steps.at(2) = options.descriptor_pattern_size / 2; pattern_size,
divUp(pattern_size * 2, 3),
divUp(pattern_size, 2)
};
for (int i = 0; i < descriptorSamples_.rows; i++) { for (int i = 0; i < descriptorSamples_.rows; i++) {
const int *coords = descriptorSamples_.ptr<int>(i); const int *coords = descriptorSamples_.ptr<int>(i);
int sample_step = steps.at(coords[0]); CV_Assert(coords[0] >= 0 && coords[0] < 3);
const int sample_step = sample_steps[coords[0]];
di = 0.0f; di = 0.0f;
dx = 0.0f; dx = 0.0f;
dy = 0.0f; dy = 0.0f;
@ -1949,8 +1983,8 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint&
sample_y = yf + (l*scale*co + k*scale*si); sample_y = yf + (l*scale*co + k*scale*si);
sample_x = xf + (-l*scale*si + k*scale*co); sample_x = xf + (-l*scale*si + k*scale*co);
y1 = fRound(sample_y); y1 = cvRound(sample_y);
x1 = fRound(sample_x); x1 = cvRound(sample_x);
di += *(Lt.ptr<float>(y1)+x1); di += *(Lt.ptr<float>(y1)+x1);
@ -1970,26 +2004,27 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint&
} }
} }
*(values.ptr<float>(options.descriptor_channels*i)) = di; float* pValues = &values[channels * i];
pValues[0] = di;
if (options.descriptor_channels == 2) { if (channels == 2) {
*(values.ptr<float>(options.descriptor_channels*i + 1)) = dx; pValues[1] = dx;
} }
else if (options.descriptor_channels == 3) { else if (channels == 3) {
*(values.ptr<float>(options.descriptor_channels*i + 1)) = dx; pValues[1] = dx;
*(values.ptr<float>(options.descriptor_channels*i + 2)) = dy; pValues[2] = dy;
} }
} }
// Do the comparisons // Do the comparisons
const float *vals = values.ptr<float>(0);
const int *comps = descriptorBits_.ptr<int>(0); const int *comps = descriptorBits_.ptr<int>(0);
CV_Assert(divUp(descriptorBits_.rows, 8) == desc_size);
memset(desc, 0, desc_size);
for (int i = 0; i<descriptorBits_.rows; i++) { for (int i = 0; i<descriptorBits_.rows; i++) {
if (vals[comps[2 * i]] > vals[comps[2 * i + 1]]) { if (values[comps[2 * i]] > values[comps[2 * i + 1]]) {
desc[i / 8] |= (1 << (i % 8)); desc[i / 8] |= (1 << (i % 8));
} else {
desc[i / 8] &= ~(1 << (i % 8));
} }
} }
} }
@ -2002,7 +2037,7 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint&
* @param kpt Input keypoint * @param kpt Input keypoint
* @param desc Descriptor vector * @param desc Descriptor vector
*/ */
void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char *desc) const { void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(const KeyPoint& kpt, unsigned char *desc, int desc_size) const {
float di = 0.0f, dx = 0.0f, dy = 0.0f; float di = 0.0f, dx = 0.0f, dy = 0.0f;
float rx = 0.0f, ry = 0.0f; float rx = 0.0f, ry = 0.0f;
@ -2014,7 +2049,7 @@ void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(
// Get the information from the keypoint // Get the information from the keypoint
float ratio = (float)(1 << kpt.octave); float ratio = (float)(1 << kpt.octave);
int scale = fRound(0.5f*kpt.size / ratio); int scale = cvRound(0.5f*kpt.size / ratio);
const int level = kpt.class_id; const int level = kpt.class_id;
Mat Lx = evolution[level].Mx; Mat Lx = evolution[level].Mx;
Mat Ly = evolution[level].My; Mat Ly = evolution[level].My;
@ -2025,14 +2060,18 @@ void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(
// Allocate memory for the matrix of values // Allocate memory for the matrix of values
Mat values ((4 + 9 + 16)*options.descriptor_channels, 1, CV_32FC1); Mat values ((4 + 9 + 16)*options.descriptor_channels, 1, CV_32FC1);
vector<int> steps(3); const int pattern_size = options.descriptor_pattern_size;
steps.at(0) = options.descriptor_pattern_size; CV_Assert((pattern_size & 1) == 0);
steps.at(1) = static_cast<int>(ceil(2.f*options.descriptor_pattern_size / 3.f)); const int sample_steps[3] = {
steps.at(2) = options.descriptor_pattern_size / 2; pattern_size,
divUp(pattern_size * 2, 3),
divUp(pattern_size, 2)
};
for (int i = 0; i < descriptorSamples_.rows; i++) { for (int i = 0; i < descriptorSamples_.rows; i++) {
const int *coords = descriptorSamples_.ptr<int>(i); const int *coords = descriptorSamples_.ptr<int>(i);
int sample_step = steps.at(coords[0]); CV_Assert(coords[0] >= 0 && coords[0] < 3);
int sample_step = sample_steps[coords[0]];
di = 0.0f, dx = 0.0f, dy = 0.0f; di = 0.0f, dx = 0.0f, dy = 0.0f;
for (int k = coords[1]; k < coords[1] + sample_step; k++) { for (int k = coords[1]; k < coords[1] + sample_step; k++) {
@ -2042,8 +2081,8 @@ void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(
sample_y = yf + l*scale; sample_y = yf + l*scale;
sample_x = xf + k*scale; sample_x = xf + k*scale;
y1 = fRound(sample_y); y1 = cvRound(sample_y);
x1 = fRound(sample_x); x1 = cvRound(sample_x);
di += *(Lt.ptr<float>(y1)+x1); di += *(Lt.ptr<float>(y1)+x1);
if (options.descriptor_channels > 1) { if (options.descriptor_channels > 1) {
@ -2076,11 +2115,12 @@ void Upright_MLDB_Descriptor_Subset_Invoker::Get_Upright_MLDB_Descriptor_Subset(
const float *vals = values.ptr<float>(0); const float *vals = values.ptr<float>(0);
const int *comps = descriptorBits_.ptr<int>(0); const int *comps = descriptorBits_.ptr<int>(0);
CV_Assert(divUp(descriptorBits_.rows, 8) == desc_size);
memset(desc, 0, desc_size);
for (int i = 0; i<descriptorBits_.rows; i++) { for (int i = 0; i<descriptorBits_.rows; i++) {
if (vals[comps[2 * i]] > vals[comps[2 * i + 1]]) { if (vals[comps[2 * i]] > vals[comps[2 * i + 1]]) {
desc[i / 8] |= (1 << (i % 8)); desc[i / 8] |= (1 << (i % 8));
} else {
desc[i / 8] &= ~(1 << (i % 8));
} }
} }
} }
@ -2120,7 +2160,7 @@ void generateDescriptorSubsample(Mat& sampleList, Mat& comparisons, int nbits,
for (int i = 0, c = 0; i < 3; i++) { for (int i = 0, c = 0; i < 3; i++) {
int gdiv = i + 2; //grid divisions, per row int gdiv = i + 2; //grid divisions, per row
int gsz = gdiv*gdiv; int gsz = gdiv*gdiv;
int psz = (int)ceil(2.f*pattern_size / (float)gdiv); int psz = divUp(2*pattern_size, gdiv);
for (int j = 0; j < gsz; j++) { for (int j = 0; j < gsz; j++) {
for (int k = j + 1; k < gsz; k++, c++) { for (int k = j + 1; k < gsz; k++, c++) {
@ -2134,12 +2174,12 @@ void generateDescriptorSubsample(Mat& sampleList, Mat& comparisons, int nbits,
} }
RNG rng(1024); RNG rng(1024);
Mat_<int> comps = Mat_<int>(nchannels * (int)ceil(nbits / (float)nchannels), 2); const int npicks = divUp(nbits, nchannels);
Mat_<int> comps = Mat_<int>(nchannels * npicks, 2);
comps = 1000; comps = 1000;
// Select some samples. A sample includes all channels // Select some samples. A sample includes all channels
int count = 0; int count = 0;
int npicks = (int)ceil(nbits / (float)nchannels);
Mat_<int> samples(29, 3); Mat_<int> samples(29, 3);
Mat_<int> fullcopy = fullM.clone(); Mat_<int> fullcopy = fullM.clone();
samples = -1; samples = -1;

@ -25,6 +25,8 @@ struct Evolution
octave = 0; octave = 0;
sublevel = 0; sublevel = 0;
sigma_size = 0; sigma_size = 0;
octave_ratio = 0.0f;
border = 0;
} }
UMat Lx, Ly; ///< First order spatial derivatives UMat Lx, Ly; ///< First order spatial derivatives

@ -68,7 +68,7 @@ void KAZEFeatures::Allocate_Memory_Evolution(void) {
aux.Ldet = Mat::zeros(options_.img_height, options_.img_width, CV_32F); aux.Ldet = Mat::zeros(options_.img_height, options_.img_width, CV_32F);
aux.esigma = options_.soffset*pow((float)2.0f, (float)(j) / (float)(options_.nsublevels)+i); aux.esigma = options_.soffset*pow((float)2.0f, (float)(j) / (float)(options_.nsublevels)+i);
aux.etime = 0.5f*(aux.esigma*aux.esigma); aux.etime = 0.5f*(aux.esigma*aux.esigma);
aux.sigma_size = fRound(aux.esigma); aux.sigma_size = cvRound(aux.esigma);
aux.octave = i; aux.octave = i;
aux.sublevel = j; aux.sublevel = j;
evolution_.push_back(aux); evolution_.push_back(aux);
@ -363,10 +363,10 @@ void KAZEFeatures::Determinant_Hessian(std::vector<KeyPoint>& kpts)
if (is_extremum == true) { if (is_extremum == true) {
// Check that the point is under the image limits for the descriptor computation // 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); left_x = cvRound(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); right_x = cvRound(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); up_y = cvRound(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); down_y = cvRound(kpts_par_[i][j].pt.y + smax*kpts_par_[i][j].size);
if (left_x < 0 || right_x >= evolution_[level].Ldet.cols || if (left_x < 0 || right_x >= evolution_[level].Ldet.cols ||
up_y < 0 || down_y >= evolution_[level].Ldet.rows) { up_y < 0 || down_y >= evolution_[level].Ldet.rows) {
@ -587,14 +587,14 @@ void KAZEFeatures::Compute_Main_Orientation(KeyPoint &kpt, const std::vector<TEv
xf = kpt.pt.x; xf = kpt.pt.x;
yf = kpt.pt.y; yf = kpt.pt.y;
level = kpt.class_id; level = kpt.class_id;
s = fRound(kpt.size / 2.0f); s = cvRound(kpt.size / 2.0f);
// Calculate derivatives responses for points within radius of 6*scale // Calculate derivatives responses for points within radius of 6*scale
for (int i = -6; i <= 6; ++i) { for (int i = -6; i <= 6; ++i) {
for (int j = -6; j <= 6; ++j) { for (int j = -6; j <= 6; ++j) {
if (i*i + j*j < 36) { if (i*i + j*j < 36) {
iy = fRound(yf + j*s); iy = cvRound(yf + j*s);
ix = fRound(xf + i*s); ix = cvRound(xf + i*s);
if (iy >= 0 && iy < options.img_height && ix >= 0 && ix < options.img_width) { if (iy >= 0 && iy < options.img_height && ix >= 0 && ix < options.img_width) {
gweight = gaussian(iy - yf, ix - xf, 2.5f*s); gweight = gaussian(iy - yf, ix - xf, 2.5f*s);
@ -606,7 +606,7 @@ void KAZEFeatures::Compute_Main_Orientation(KeyPoint &kpt, const std::vector<TEv
resY[idx] = 0.0; resY[idx] = 0.0;
} }
Ang[idx] = getAngle(resX[idx], resY[idx]); Ang[idx] = fastAtan2(resX[idx], resY[idx]) * (float)(CV_PI / 180.0f);
++idx; ++idx;
} }
} }
@ -638,7 +638,7 @@ void KAZEFeatures::Compute_Main_Orientation(KeyPoint &kpt, const std::vector<TEv
if (sumX*sumX + sumY*sumY > max) { if (sumX*sumX + sumY*sumY > max) {
// store largest orientation // store largest orientation
max = sumX*sumX + sumY*sumY; max = sumX*sumX + sumY*sumY;
kpt.angle = getAngle(sumX, sumY) * 180.f / static_cast<float>(CV_PI); kpt.angle = fastAtan2(sumX, sumY);
} }
} }
} }
@ -676,7 +676,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_64(const KeyPoint &kpt
// Get the information from the keypoint // Get the information from the keypoint
yf = kpt.pt.y; yf = kpt.pt.y;
xf = kpt.pt.x; xf = kpt.pt.x;
scale = fRound(kpt.size / 2.0f); scale = cvRound(kpt.size / 2.0f);
level = kpt.class_id; level = kpt.class_id;
i = -8; i = -8;
@ -804,8 +804,8 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const KeyPoint &kpt, float
// Get the information from the keypoint // Get the information from the keypoint
yf = kpt.pt.y; yf = kpt.pt.y;
xf = kpt.pt.x; xf = kpt.pt.x;
scale = fRound(kpt.size / 2.0f); scale = cvRound(kpt.size / 2.0f);
angle = (kpt.angle * static_cast<float>(CV_PI)) / 180.f; angle = kpt.angle * static_cast<float>(CV_PI / 180.f);
level = kpt.class_id; level = kpt.class_id;
co = cos(angle); co = cos(angle);
si = sin(angle); si = sin(angle);
@ -843,13 +843,13 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const KeyPoint &kpt, float
// Get the gaussian weighted x and y responses // Get the gaussian weighted x and y responses
gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale);
y1 = fRound(sample_y - 0.5f); y1 = cvFloor(sample_y);
x1 = fRound(sample_x - 0.5f); x1 = cvFloor(sample_x);
checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height); checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height);
y2 = (int)(sample_y + 0.5f); y2 = y1 + 1;
x2 = (int)(sample_x + 0.5f); x2 = x1 + 1;
checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height); checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height);
@ -935,7 +935,7 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Upright_Descriptor_128(const KeyPoint &kp
// Get the information from the keypoint // Get the information from the keypoint
yf = kpt.pt.y; yf = kpt.pt.y;
xf = kpt.pt.x; xf = kpt.pt.x;
scale = fRound(kpt.size / 2.0f); scale = cvRound(kpt.size / 2.0f);
level = kpt.class_id; level = kpt.class_id;
i = -8; i = -8;
@ -1087,8 +1087,8 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const KeyPoint &kpt, float
// Get the information from the keypoint // Get the information from the keypoint
yf = kpt.pt.y; yf = kpt.pt.y;
xf = kpt.pt.x; xf = kpt.pt.x;
scale = fRound(kpt.size / 2.0f); scale = cvRound(kpt.size / 2.0f);
angle = (kpt.angle * static_cast<float>(CV_PI)) / 180.f; angle = kpt.angle * static_cast<float>(CV_PI / 180.f);
level = kpt.class_id; level = kpt.class_id;
co = cos(angle); co = cos(angle);
si = sin(angle); si = sin(angle);
@ -1129,13 +1129,13 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const KeyPoint &kpt, float
// Get the gaussian weighted x and y responses // Get the gaussian weighted x and y responses
gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale);
y1 = fRound(sample_y - 0.5f); y1 = cvFloor(sample_y);
x1 = fRound(sample_x - 0.5f); x1 = cvFloor(sample_x);
checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height); checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height);
y2 = (int)(sample_y + 0.5f); y2 = y1 + 1;
x2 = (int)(sample_x + 0.5f); x2 = x1 + 1;
checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height); checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height);

@ -72,7 +72,7 @@ int fed_tau_by_cycle_time(const float& t, const float& tau_max,
float scale = 0.0; // Ratio of t we search to maximal t float scale = 0.0; // Ratio of t we search to maximal t
// Compute necessary number of time steps // Compute necessary number of time steps
n = (int)(ceilf(sqrtf(3.0f*t/tau_max+0.25f)-0.5f-1.0e-8f)+ 0.5f); n = cvCeil(sqrtf(3.0f*t/tau_max+0.25f)-0.5f-1.0e-8f);
scale = 3.0f*t/(tau_max*(float)(n*(n+1))); scale = 3.0f*t/(tau_max*(float)(n*(n+1)));
// Call internal FED time step creation routine // Call internal FED time step creation routine

@ -49,7 +49,7 @@ void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int
// Compute an appropriate kernel size according to the specified sigma // Compute an appropriate kernel size according to the specified sigma
if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0) { if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0) {
ksize_x_ = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f))); ksize_x_ = cvCeil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
ksize_y_ = ksize_x_; ksize_y_ = ksize_x_;
} }

@ -1,31 +1,6 @@
#ifndef __OPENCV_FEATURES_2D_KAZE_UTILS_H__ #ifndef __OPENCV_FEATURES_2D_KAZE_UTILS_H__
#define __OPENCV_FEATURES_2D_KAZE_UTILS_H__ #define __OPENCV_FEATURES_2D_KAZE_UTILS_H__
/* ************************************************************************* */
/**
* @brief This function computes the angle from the vector given by (X Y). From 0 to 2*Pi
*/
inline float getAngle(float x, float y) {
if (x >= 0 && y >= 0) {
return atanf(y / x);
}
if (x < 0 && y >= 0) {
return static_cast<float>(CV_PI)-atanf(-y / x);
}
if (x < 0 && y < 0) {
return static_cast<float>(CV_PI)+atanf(y / x);
}
if (x >= 0 && y < 0) {
return static_cast<float>(2.0 * CV_PI) - atanf(-y / x);
}
return 0;
}
/* ************************************************************************* */ /* ************************************************************************* */
/** /**
* @brief This function computes the value of a 2D Gaussian function * @brief This function computes the value of a 2D Gaussian function
@ -64,34 +39,4 @@ inline void checkDescriptorLimits(int &x, int &y, int width, int height) {
} }
} }
/* ************************************************************************* */
/**
* @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.5f);
}
/* ************************************************************************* */
/**
* @brief Exponentiation by squaring
* @param flt Exponentiation base
* @return dst Exponentiation value
*/
inline int fastpow(int base, int exp) {
int res = 1;
while(exp > 0) {
if(exp & 1) {
exp--;
res *= base;
} else {
exp /= 2;
base *= base;
}
}
return res;
}
#endif #endif

@ -11,7 +11,7 @@ using std::tr1::make_tuple;
using std::tr1::get; using std::tr1::get;
using namespace testing; using namespace testing;
#define SHOW_DEBUG_LOG 0 #define SHOW_DEBUG_LOG 1
typedef std::tr1::tuple<std::string, Ptr<FeatureDetector>, Ptr<DescriptorExtractor>, float> typedef std::tr1::tuple<std::string, Ptr<FeatureDetector>, Ptr<DescriptorExtractor>, float>
String_FeatureDetector_DescriptorExtractor_Float_t; String_FeatureDetector_DescriptorExtractor_Float_t;
@ -72,7 +72,7 @@ TEST_P(DescriptorRotationInvariance, rotation)
vector<KeyPoint> keypoints0; vector<KeyPoint> keypoints0;
Mat descriptors0; Mat descriptors0;
featureDetector->detect(image0, keypoints0, mask0); featureDetector->detect(image0, keypoints0, mask0);
std::cout << "Intial keypoints: " << keypoints0.size() << std::endl; std::cout << "Keypoints: " << keypoints0.size() << std::endl;
EXPECT_GE(keypoints0.size(), 15u); EXPECT_GE(keypoints0.size(), 15u);
descriptorExtractor->compute(image0, keypoints0, descriptors0); descriptorExtractor->compute(image0, keypoints0, descriptors0);
@ -109,7 +109,7 @@ TEST_P(DescriptorRotationInvariance, rotation)
#if SHOW_DEBUG_LOG #if SHOW_DEBUG_LOG
std::cout std::cout
<< "angle = " << angle << "angle = " << angle
<< ", keypoints = " << keypoints1.size() << ", inliers = " << descInliersCount
<< ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size() << ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
<< std::endl; << std::endl;
#endif #endif
@ -121,6 +121,7 @@ TEST_P(DescriptorScaleInvariance, scale)
{ {
vector<KeyPoint> keypoints0; vector<KeyPoint> keypoints0;
featureDetector->detect(image0, keypoints0); featureDetector->detect(image0, keypoints0);
std::cout << "Keypoints: " << keypoints0.size() << std::endl;
EXPECT_GE(keypoints0.size(), 15u); EXPECT_GE(keypoints0.size(), 15u);
Mat descriptors0; Mat descriptors0;
descriptorExtractor->compute(image0, keypoints0, descriptors0); descriptorExtractor->compute(image0, keypoints0, descriptors0);
@ -159,6 +160,7 @@ TEST_P(DescriptorScaleInvariance, scale)
#if SHOW_DEBUG_LOG #if SHOW_DEBUG_LOG
std::cout std::cout
<< "scale = " << scale << "scale = " << scale
<< ", inliers = " << descInliersCount
<< ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size() << ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
<< std::endl; << std::endl;
#endif #endif

@ -56,6 +56,7 @@ static void writeMatInBin( const Mat& mat, const string& filename )
FILE* f = fopen( filename.c_str(), "wb"); FILE* f = fopen( filename.c_str(), "wb");
if( f ) if( f )
{ {
CV_Assert(4 == sizeof(int));
int type = mat.type(); int type = mat.type();
fwrite( (void*)&mat.rows, sizeof(int), 1, f ); fwrite( (void*)&mat.rows, sizeof(int), 1, f );
fwrite( (void*)&mat.cols, sizeof(int), 1, f ); fwrite( (void*)&mat.cols, sizeof(int), 1, f );
@ -72,6 +73,7 @@ static Mat readMatFromBin( const string& filename )
FILE* f = fopen( filename.c_str(), "rb" ); FILE* f = fopen( filename.c_str(), "rb" );
if( f ) if( f )
{ {
CV_Assert(4 == sizeof(int));
int rows, cols, type, dataSize; int rows, cols, type, dataSize;
size_t elements_read1 = fread( (void*)&rows, sizeof(int), 1, f ); size_t elements_read1 = fread( (void*)&rows, sizeof(int), 1, f );
size_t elements_read2 = fread( (void*)&cols, sizeof(int), 1, f ); size_t elements_read2 = fread( (void*)&cols, sizeof(int), 1, f );
@ -123,24 +125,37 @@ protected:
CV_Assert( DataType<ValueType>::type == validDescriptors.type() ); CV_Assert( DataType<ValueType>::type == validDescriptors.type() );
int dimension = validDescriptors.cols; int dimension = validDescriptors.cols;
DistanceType curMaxDist = std::numeric_limits<DistanceType>::min(); DistanceType curMaxDist = 0;
size_t exact_count = 0, failed_count = 0;
for( int y = 0; y < validDescriptors.rows; y++ ) for( int y = 0; y < validDescriptors.rows; y++ )
{ {
DistanceType dist = distance( validDescriptors.ptr<ValueType>(y), calcDescriptors.ptr<ValueType>(y), dimension ); DistanceType dist = distance( validDescriptors.ptr<ValueType>(y), calcDescriptors.ptr<ValueType>(y), dimension );
if (dist == 0)
exact_count++;
if( dist > curMaxDist ) if( dist > curMaxDist )
{
if (dist > maxDist)
failed_count++;
curMaxDist = dist; curMaxDist = dist;
}
#if 0
if (dist > 0)
{
std::cout << "i=" << y << " fail_count=" << failed_count << " dist=" << dist << std::endl;
std::cout << "valid: " << validDescriptors.row(y) << std::endl;
std::cout << " calc: " << calcDescriptors.row(y) << std::endl;
}
#endif
} }
float exact_percents = (100 * (float)exact_count / validDescriptors.rows);
float failed_percents = (100 * (float)failed_count / validDescriptors.rows);
stringstream ss; stringstream ss;
ss << "Max distance between valid and computed descriptors " << curMaxDist; ss << "Exact count (dist == 0): " << exact_count << " (" << (int)exact_percents << "%)" << std::endl
if( curMaxDist <= maxDist ) << "Failed count (dist > " << maxDist << "): " << failed_count << " (" << (int)failed_percents << "%)" << std::endl
ss << "." << endl; << "Max distance between valid and computed descriptors (" << validDescriptors.size() << "): " << curMaxDist;
else EXPECT_LE(failed_percents, 20.0f);
{ std::cout << ss.str() << std::endl;
ss << ">" << maxDist << " - bad accuracy!"<< endl;
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
}
ts->printf(cvtest::TS::LOG, ss.str().c_str() );
} }
void emptyDataTest() void emptyDataTest()
@ -202,22 +217,57 @@ protected:
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
return; return;
} }
const std::string keypoints_filename = string(ts->get_data_path()) +
(detector.empty()
? (FEATURES2D_DIR + "/" + std::string("keypoints.xml.gz"))
: (DESCRIPTOR_DIR + "/" + name + "_keypoints.xml.gz"));
FileStorage fs(keypoints_filename, FileStorage::READ);
vector<KeyPoint> keypoints; vector<KeyPoint> keypoints;
FileStorage fs( string(ts->get_data_path()) + FEATURES2D_DIR + "/keypoints.xml.gz", FileStorage::READ ); EXPECT_TRUE(fs.isOpened()) << "Keypoint testdata is missing. Re-computing and re-writing keypoints testdata...";
if(!detector.empty()) { if (!fs.isOpened())
detector->detect(img, keypoints); {
} else { fs.open(keypoints_filename, FileStorage::WRITE);
read( fs.getFirstTopLevelNode(), keypoints ); ASSERT_TRUE(fs.isOpened()) << "File for writting keypoints can not be opened.";
if (detector.empty())
{
Ptr<ORB> fd = ORB::create();
fd->detect(img, keypoints);
}
else
{
detector->detect(img, keypoints);
}
write(fs, "keypoints", keypoints);
fs.release();
} }
if(!keypoints.empty()) else
{
read(fs.getFirstTopLevelNode(), keypoints);
fs.release();
}
if(!detector.empty())
{
vector<KeyPoint> calcKeypoints;
detector->detect(img, calcKeypoints);
// TODO validate received keypoints
int diff = abs((int)calcKeypoints.size() - (int)keypoints.size());
if (diff > 0)
{
std::cout << "Keypoints difference: " << diff << std::endl;
EXPECT_LE(diff, (int)(keypoints.size() * 0.03f));
}
}
ASSERT_FALSE(keypoints.empty());
{ {
Mat calcDescriptors; Mat calcDescriptors;
double t = (double)getTickCount(); double t = (double)getTickCount();
dextractor->compute( img, keypoints, calcDescriptors ); dextractor->compute(img, keypoints, calcDescriptors);
t = getTickCount() - t; t = getTickCount() - t;
ts->printf(cvtest::TS::LOG, "\nAverage time of computing one descriptor = %g ms.\n", t/((double)getTickFrequency()*1000.)/calcDescriptors.rows); ts->printf(cvtest::TS::LOG, "\nAverage time of computing one descriptor = %g ms.\n", t/((double)getTickFrequency()*1000.)/calcDescriptors.rows);
if( calcDescriptors.rows != (int)keypoints.size() ) if (calcDescriptors.rows != (int)keypoints.size())
{ {
ts->printf( cvtest::TS::LOG, "Count of computed descriptors and keypoints count must be equal.\n" ); ts->printf( cvtest::TS::LOG, "Count of computed descriptors and keypoints count must be equal.\n" );
ts->printf( cvtest::TS::LOG, "Count of keypoints is %d.\n", (int)keypoints.size() ); ts->printf( cvtest::TS::LOG, "Count of keypoints is %d.\n", (int)keypoints.size() );
@ -226,7 +276,7 @@ protected:
return; return;
} }
if( calcDescriptors.cols != dextractor->descriptorSize() || calcDescriptors.type() != dextractor->descriptorType() ) if (calcDescriptors.cols != dextractor->descriptorSize() || calcDescriptors.type() != dextractor->descriptorType())
{ {
ts->printf( cvtest::TS::LOG, "Incorrect descriptor size or descriptor type.\n" ); ts->printf( cvtest::TS::LOG, "Incorrect descriptor size or descriptor type.\n" );
ts->printf( cvtest::TS::LOG, "Expected size is %d.\n", dextractor->descriptorSize() ); ts->printf( cvtest::TS::LOG, "Expected size is %d.\n", dextractor->descriptorSize() );
@ -239,33 +289,14 @@ protected:
// TODO read and write descriptor extractor parameters and check them // TODO read and write descriptor extractor parameters and check them
Mat validDescriptors = readDescriptors(); Mat validDescriptors = readDescriptors();
if( !validDescriptors.empty() ) EXPECT_FALSE(validDescriptors.empty()) << "Descriptors testdata is missing. Re-writing descriptors testdata...";
compareDescriptors( validDescriptors, calcDescriptors ); if (!validDescriptors.empty())
else
{ {
if( !writeDescriptors( calcDescriptors ) ) compareDescriptors(validDescriptors, calcDescriptors);
{
ts->printf( cvtest::TS::LOG, "Descriptors can not be written.\n" );
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
return;
}
}
}
if(!fs.isOpened())
{
ts->printf( cvtest::TS::LOG, "Compute and write keypoints.\n" );
fs.open( string(ts->get_data_path()) + FEATURES2D_DIR + "/keypoints.xml.gz", FileStorage::WRITE );
if( fs.isOpened() )
{
Ptr<ORB> fd = ORB::create();
fd->detect(img, keypoints);
write( fs, "keypoints", keypoints );
} }
else else
{ {
ts->printf(cvtest::TS::LOG, "File for writting keypoints can not be opened.\n"); ASSERT_TRUE(writeDescriptors(calcDescriptors)) << "Descriptors can not be written.";
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
return;
} }
} }
} }
@ -344,7 +375,7 @@ TEST( Features2d_DescriptorExtractor_KAZE, regression )
TEST( Features2d_DescriptorExtractor_AKAZE, regression ) TEST( Features2d_DescriptorExtractor_AKAZE, regression )
{ {
CV_DescriptorExtractorTest<Hamming> test( "descriptor-akaze", CV_DescriptorExtractorTest<Hamming> test( "descriptor-akaze",
(CV_DescriptorExtractorTest<Hamming>::DistanceType)12.f, (CV_DescriptorExtractorTest<Hamming>::DistanceType)(486*0.05f),
AKAZE::create(), AKAZE::create(),
Hamming(), AKAZE::create()); Hamming(), AKAZE::create());
test.safe_run(); test.safe_run();

@ -11,7 +11,7 @@ using std::tr1::make_tuple;
using std::tr1::get; using std::tr1::get;
using namespace testing; using namespace testing;
#define SHOW_DEBUG_LOG 0 #define SHOW_DEBUG_LOG 1
typedef std::tr1::tuple<std::string, Ptr<FeatureDetector>, float, float> String_FeatureDetector_Float_Float_t; typedef std::tr1::tuple<std::string, Ptr<FeatureDetector>, float, float> String_FeatureDetector_Float_Float_t;
const static std::string IMAGE_TSUKUBA = "features2d/tsukuba.png"; const static std::string IMAGE_TSUKUBA = "features2d/tsukuba.png";

@ -23,11 +23,6 @@ enum
CTA_SIZE_DEFAULT = 256 CTA_SIZE_DEFAULT = 256
}; };
static int divUp(int a, int b)
{
return (a + b - 1) / b;
}
template <typename FT, typename ST, typename WT> template <typename FT, typename ST, typename WT>
static bool ocl_calcAlmostDist2Weight(UMat & almostDist2Weight, static bool ocl_calcAlmostDist2Weight(UMat & almostDist2Weight,
int searchWindowSize, int templateWindowSize, int searchWindowSize, int templateWindowSize,

@ -102,7 +102,7 @@ PERF_TEST_P(stitchDatasets, affine, testing::Combine(AFFINE_DATASETS, TEST_DETEC
Mat pano; Mat pano;
vector<Mat> imgs; vector<Mat> imgs;
int width, height, allowed_diff = 10; int width, height, allowed_diff = 20;
Ptr<detail::FeaturesFinder> featuresFinder = getFeatureFinder(detector); Ptr<detail::FeaturesFinder> featuresFinder = getFeatureFinder(detector);
if(dataset == "budapest") if(dataset == "budapest")
@ -117,7 +117,7 @@ PERF_TEST_P(stitchDatasets, affine, testing::Combine(AFFINE_DATASETS, TEST_DETEC
height = 1158; height = 1158;
// this dataset is big, the results between surf and orb differ slightly, // this dataset is big, the results between surf and orb differ slightly,
// but both are still good // but both are still good
allowed_diff = 27; allowed_diff = 50;
} }
else if (dataset == "newspaper") else if (dataset == "newspaper")
{ {

Loading…
Cancel
Save