diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp index c844c171b2..41ccb4b88c 100644 --- a/modules/core/include/opencv2/core/utility.hpp +++ b/modules/core/include/opencv2/core/utility.hpp @@ -444,6 +444,23 @@ static inline size_t alignSize(size_t sz, int 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. The function can be used to dynamically turn on and off optimized code (code that uses SSE2, AVX, diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index bc851704a7..ec09e2117b 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -3406,11 +3406,6 @@ static TransposeInplaceFunc transposeInplaceTab[] = #ifdef HAVE_OPENCL -static inline int divUp(int a, int b) -{ - return (a + b - 1) / b; -} - static bool ocl_transpose( InputArray _src, OutputArray _dst ) { const ocl::Device & dev = ocl::Device::getDefault(); diff --git a/modules/features2d/src/akaze.cpp b/modules/features2d/src/akaze.cpp index 570d74778a..baca3c6677 100644 --- a/modules/features2d/src/akaze.cpp +++ b/modules/features2d/src/akaze.cpp @@ -113,12 +113,12 @@ namespace cv if (descriptor_size == 0) { int t = (6 + 36 + 120) * descriptor_channels; - return (int)ceil(t / 8.); + return divUp(t, 8); } else { // We use the random bit selection length binary descriptor - return (int)ceil(descriptor_size / 8.); + return divUp(descriptor_size, 8); } default: diff --git a/modules/features2d/src/kaze/AKAZEFeatures.cpp b/modules/features2d/src/kaze/AKAZEFeatures.cpp index 1f4e67c8dc..16c2cad032 100644 --- a/modules/features2d/src/kaze/AKAZEFeatures.cpp +++ b/modules/features2d/src/kaze/AKAZEFeatures.cpp @@ -74,12 +74,12 @@ void AKAZEFeatures::Allocate_Memory_Evolution(void) { Evolution step; step.size = Size(level_width, level_height); 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.octave = i; step.sublevel = j; 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); } @@ -106,7 +106,7 @@ void AKAZEFeatures::Allocate_Memory_Evolution(void) { */ static inline int getGaussianKernelSize(float 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 return ksize; } @@ -890,11 +890,11 @@ public: { for (int i = range.start; i < range.end; i++) { - Get_SURF_Descriptor_Upright_64((*keypoints_)[i], descriptors_->ptr(i)); + Get_SURF_Descriptor_Upright_64((*keypoints_)[i], descriptors_->ptr(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: std::vector* keypoints_; @@ -916,11 +916,11 @@ public: { for (int i = range.start; i < range.end; i++) { - Get_SURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr(i)); + Get_SURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr(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: std::vector* keypoints_; @@ -942,11 +942,11 @@ public: { for (int i = range.start; i < range.end; i++) { - Get_MSURF_Upright_Descriptor_64((*keypoints_)[i], descriptors_->ptr(i)); + Get_MSURF_Upright_Descriptor_64((*keypoints_)[i], descriptors_->ptr(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: std::vector* keypoints_; @@ -968,11 +968,11 @@ public: { for (int i = range.start; i < range.end; i++) { - Get_MSURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr(i)); + Get_MSURF_Descriptor_64((*keypoints_)[i], descriptors_->ptr(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: std::vector* keypoints_; @@ -995,11 +995,11 @@ public: { for (int i = range.start; i < range.end; i++) { - Get_Upright_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr(i)); + Get_Upright_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr(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: std::vector* keypoints_; @@ -1030,11 +1030,11 @@ public: { for (int i = range.start; i < range.end; i++) { - Get_Upright_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr(i)); + Get_Upright_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr(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: std::vector* keypoints_; @@ -1061,11 +1061,11 @@ public: { for (int i = range.start; i < range.end; i++) { - Get_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr(i)); + Get_MLDB_Full_Descriptor((*keypoints_)[i], descriptors_->ptr(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, float xf, float yf, float co, float si, float scale) const; void MLDB_Binary_Comparisons(float* values, unsigned char* desc, @@ -1100,11 +1100,11 @@ public: { for (int i = range.start; i < range.end; i++) { - Get_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr(i)); + Get_MLDB_Descriptor_Subset((*keypoints_)[i], descriptors_->ptr(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: std::vector* keypoints_; @@ -1131,20 +1131,17 @@ void AKAZEFeatures::Compute_Descriptors(std::vector& kpts, OutputArray } // Allocate memory for the matrix with the descriptors - if (options_.descriptor < AKAZE::DESCRIPTOR_MLDB_UPRIGHT) { - descriptors.create((int)kpts.size(), 64, CV_32FC1); - } - else { - // We use the full length binary descriptor -> 486 bits - if (options_.descriptor_size == 0) { - int t = (6 + 36 + 120)*options_.descriptor_channels; - descriptors.create((int)kpts.size(), (int)ceil(t / 8.), 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); - } + int descriptor_size = 64; + int descriptor_type = CV_32FC1; + if (options_.descriptor >= AKAZE::DESCRIPTOR_MLDB_UPRIGHT) + { + int descriptor_bits = (options_.descriptor_size == 0) + ? (6 + 36 + 120)*options_.descriptor_channels // the full length binary descriptor -> 486 bits + : options_.descriptor_size; // the random bit selection length binary descriptor + descriptor_size = divUp(descriptor_bits, 8); + descriptor_type = CV_8UC1; } + descriptors.create((int)kpts.size(), descriptor_size, descriptor_type); 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.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 { float weight[109]; - int8_t xidx[109]; - int8_t yidx[109]; + int xidx[109]; + int yidx[109]; 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 j = -6; j <= 6; ++j) { if (i*i + j*j < 36) { - weight[k] = gauss25[id[i + 6]][id[j + 6]]; - yidx[k] = static_cast(i); - xidx[k] = static_cast(j); + CV_Assert(k < 109); + weight[k] = gauss25[abs(i)][abs(j)]; + yidx[k] = i; + xidx[k] = j; ++k; } } } - CV_DbgAssert(k == 109); } } g; - const float * lx = Lx.ptr(0); - const float * ly = Ly.ptr(0); - int cols = Lx.cols; + CV_Assert(x0 - 6 * scale >= 0 && x0 + 6 * scale < Lx.cols); + CV_Assert(y0 - 6 * scale >= 0 && y0 + 6 * scale < Lx.rows); - for (int i = 0; i < 109; i++) { - int j = (y0 + g.yidx[i] * scale) * cols + (x0 + g.xidx[i] * scale); + for (int i = 0; i < 109; i++) + { + int y = y0 + g.yidx[i] * scale; + int x = x0 + g.xidx[i] * scale; - resX[i] = g.weight[i] * lx[j]; - resY[i] = g.weight[i] * ly[j]; - - CV_DbgAssert(isfinite(resX[i])); - CV_DbgAssert(isfinite(resY[i])); + float w = g.weight[i]; + resX[i] = w * Lx.at(y, x); + resY[i] = w * Ly.at(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 n The length of a[] * @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 cum[] Output array of the starting indices of quantized floats * @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 void quantized_counting_sort(const float a[], const int n, - const float quantum, const float max, - uint8_t idx[], uint8_t cum[]) + const float quantum, const int nkeys, + int idx[/*n*/], int cum[/*nkeys + 1*/]) { - const int nkeys = (int)(max / quantum); - - // The size of cum[] must be nkeys + 1 - memset(cum, 0, nkeys + 1); + memset(cum, 0, sizeof(cum[0]) * (nkeys + 1)); // Count up the quantized values 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 for (int i = 1; i <= nkeys; i++) + { 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 for (int i = 0; i < n; i++) - idx[--cum[(int)(a[i] / quantum)]] = static_cast(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& evolu // get the right evolution level for this keypoint const Evolution& e = evolution[kpt.class_id]; // Get the information from the keypoint - int scale = fRound(0.5f * kpt.size / e.octave_ratio); - int x0 = fRound(kpt.pt.x / e.octave_ratio); - int y0 = fRound(kpt.pt.y / e.octave_ratio); + int scale = cvRound(0.5f * kpt.size / e.octave_ratio); + int x0 = cvRound(kpt.pt.x / e.octave_ratio); + int y0 = cvRound(kpt.pt.y / e.octave_ratio); // Sample derivatives responses for the points within radius of 6*scale const int ang_size = 109; @@ -1312,17 +1317,18 @@ void Compute_Main_Orientation(KeyPoint& kpt, const std::vector& evolu // Sort by the angles; angles are labeled by slices of 0.15 radian const int slices = 42; const float ang_step = (float)(2.0 * CV_PI / slices); - uint8_t slice[slices + 1]; - uint8_t sorted_idx[ang_size]; - quantized_counting_sort(Ang, ang_size, ang_step, (float)(2.0 * CV_PI), sorted_idx, slice); + int slice[slices + 1]; + int sorted_idx[ang_size]; + 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 const int win = 7; float maxX = 0.0f, maxY = 0.0f; for (int i = slice[0]; i < slice[win]; i++) { - maxX += resX[sorted_idx[i]]; - maxY += resY[sorted_idx[i]]; + const int idx = sorted_idx[i]; + maxX += resX[idx]; + maxY += resY[idx]; } float maxNorm = maxX * maxX + maxY * maxY; @@ -1333,8 +1339,9 @@ void Compute_Main_Orientation(KeyPoint& kpt, const std::vector& evolu float sumX = 0.0f, sumY = 0.0f; for (int i = slice[sn]; i < slice[sn + win]; i++) { - sumX += resX[sorted_idx[i]]; - sumY += resY[sorted_idx[i]]; + const int idx = sorted_idx[i]; + sumX += resX[idx]; + sumY += resY[idx]; } float norm = sumX * sumX + sumY * sumY; @@ -1350,12 +1357,14 @@ void Compute_Main_Orientation(KeyPoint& kpt, const std::vector& evolu float sumX = 0.0f, sumY = 0.0f; for (int i = slice[sn]; i < slice[slices]; i++) { - sumX += resX[sorted_idx[i]]; - sumY += resY[sorted_idx[i]]; + const int idx = sorted_idx[i]; + sumX += resX[idx]; + sumY += resY[idx]; } for (int i = slice[0]; i < slice[remain]; i++) { - sumX += resX[sorted_idx[i]]; - sumY += resY[sorted_idx[i]]; + const int idx = sorted_idx[i]; + sumX += resX[idx]; + sumY += resY[idx]; } float norm = sumX * sumX + sumY * sumY; @@ -1410,7 +1419,10 @@ void AKAZEFeatures::Compute_Keypoints_Orientation(std::vector& kpts) c * from Agrawal et al., CenSurE: Center Surround Extremas for Realtime Feature Detection and Matching, * 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 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 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; + int scale = 0; // Subregion centers for the 4x4 gaussian weighting 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_; // 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.5f*kpt.size / ratio); + scale = cvRound(0.5f*kpt.size / ratio); const int level = kpt.class_id; Mat Lx = evolution[level].Mx; 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 gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.50f*scale); - y1 = (int)(sample_y - .5); - x1 = (int)(sample_x - .5); + y1 = (int)(sample_y - .5f); + x1 = (int)(sample_x - .5f); - y2 = (int)(sample_y + .5); - x2 = (int)(sample_x + .5); + y2 = (int)(sample_y + .5f); + x2 = (int)(sample_x + .5f); fx = sample_x - x1; fy = sample_y - y1; @@ -1517,6 +1528,8 @@ void MSURF_Upright_Descriptor_64_Invoker::Get_MSURF_Upright_Descriptor_64(const i += 9; } + CV_Assert(dcount == desc_size); + // convert to unit vector 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, * 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 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; 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; + int scale = 0; // Subregion centers for the 4x4 gaussian weighting 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_; // 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.5f*kpt.size / ratio); - angle = (kpt.angle * static_cast(CV_PI)) / 180.f; + scale = cvRound(0.5f*kpt.size / ratio); + angle = kpt.angle * static_cast(CV_PI / 180.f); const int level = kpt.class_id; Mat Lx = evolution[level].Mx; 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 gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); - y1 = fRound(sample_y - 0.5f); - x1 = fRound(sample_x - 0.5f); + y1 = cvRound(sample_y - 0.5f); + x1 = cvRound(sample_x - 0.5f); - y2 = fRound(sample_y + 0.5f); - x2 = fRound(sample_x + 0.5f); + y2 = cvRound(sample_y + 0.5f); + x2 = cvRound(sample_x + 0.5f); // fix crash: indexing with out-of-bounds index, this might happen near the edges of 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; } + CV_Assert(dcount == desc_size); + // convert to unit vector 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 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 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 std::vector& evolution = *evolution_; - // Matrices for the M-LDB descriptor - Mat values[3] = { - Mat(4, options.descriptor_channels, CV_32FC1), - Mat(9, options.descriptor_channels, CV_32FC1), - Mat(16, options.descriptor_channels, CV_32FC1) - }; + // Buffer for the M-LDB descriptor + const int max_channels = 3; + CV_Assert(options.descriptor_channels <= max_channels); + float values[16*max_channels]; // Get the information from the keypoint 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; Mat Lx = evolution[level].Mx; 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 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, - static_cast(ceil(pattern_size*2./3.)), - pattern_size / 2 + divUp(pattern_size * 2, 3), + divUp(pattern_size, 2) }; + memset(desc, 0, desc_size); + // For the three grids for (int z = 0; z < 3; z++) { dcount2 = 0; @@ -1723,8 +1741,8 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons sample_y = yf + l*scale; sample_x = xf + k*scale; - y1 = fRound(sample_y); - x1 = fRound(sample_x); + y1 = cvRound(sample_y); + x1 = cvRound(sample_x); ri = *(Lt.ptr(y1)+x1); rx = *(Lx.ptr(y1)+x1); @@ -1741,7 +1759,7 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons dx /= nsamples; dy /= nsamples; - float *val = values[z].ptr(dcount2); + float *val = &values[dcount2*max_channels]; *(val) = di; *(val+1) = dx; *(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); for (int i = 0; i < num; i++) { for (int j = i + 1; j < num; j++) { - const float * valI = values[z].ptr(i); - const float * valJ = values[z].ptr(j); + const float * valI = &values[i*max_channels]; + const float * valJ = &values[j*max_channels]; for (int k = 0; k < 3; ++k) { if (*(valI + k) > *(valJ + k)) { desc[dcount1 / 8] |= (1 << (dcount1 % 8)); - } else { - desc[dcount1 / 8] &= ~(1 << (dcount1 % 8)); } dcount1++; } @@ -1767,6 +1783,9 @@ void Upright_MLDB_Full_Descriptor_Invoker::Get_Upright_MLDB_Full_Descriptor(cons } } // 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, @@ -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_x = xf + (-l*si * scale + k*co*scale); - int y1 = fRound(sample_y); - int x1 = fRound(sample_x); + int y1 = cvRound(sample_y); + int x1 = cvRound(sample_x); // fix crash: indexing with out-of-bounds index, this might happen near the edges of 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]) { desc[dpos >> 3] |= (1 << (dpos & 7)); } - else { - desc[dpos >> 3] &= ~(1 << (dpos & 7)); - } - dpos++; } } @@ -1869,30 +1884,41 @@ void MLDB_Full_Descriptor_Invoker::MLDB_Binary_Comparisons(float* values, unsign * @param kpt Input keypoint * @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; CV_Assert(options_->descriptor_channels <= max_channels); + const int pattern_size = options_->descriptor_pattern_size; + 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(ceil(pattern_size * size_mult[lvl])) + pattern_size, + divUp(pattern_size * 2, 3), + divUp(pattern_size, 2) + }; 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 yf = kpt.pt.y / ratio; - float angle = (kpt.angle * static_cast(CV_PI)) / 180.f; + float angle = kpt.angle * static_cast(CV_PI / 180.f); float co = cos(angle); float si = sin(angle); - int pattern_size = options_->descriptor_pattern_size; + + memset(desc, 0, desc_size); int dpos = 0; - for(int lvl = 0; lvl < 3; lvl++) { - + for(int lvl = 0; lvl < 3; lvl++) + { int val_count = (lvl + 2) * (lvl + 2); - int sample_step = static_cast(ceil(pattern_size * size_mult[lvl])); - MLDB_Fill_Values(values, sample_step, kpt.class_id, xf, yf, co, si, scale); + MLDB_Fill_Values(values, sample_step[lvl], kpt.class_id, xf, yf, co, si, scale); 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 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 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 float ratio = (float)(1 << kpt.octave); - int scale = fRound(0.5f*kpt.size / ratio); - float angle = (kpt.angle * static_cast(CV_PI)) / 180.f; + int scale = cvRound(0.5f*kpt.size / ratio); + float angle = kpt.angle * static_cast(CV_PI / 180.f); const int level = kpt.class_id; Mat Lx = evolution[level].Mx; Mat Ly = evolution[level].My; @@ -1927,17 +1953,25 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint& float si = sin(angle); // 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 - vector steps(3); - steps.at(0) = options.descriptor_pattern_size; - steps.at(1) = (int)ceil(2.f*options.descriptor_pattern_size / 3.f); - steps.at(2) = options.descriptor_pattern_size / 2; + const int pattern_size = options.descriptor_pattern_size; + CV_Assert((pattern_size & 1) == 0); + const int sample_steps[3] = { + pattern_size, + divUp(pattern_size * 2, 3), + divUp(pattern_size, 2) + }; for (int i = 0; i < descriptorSamples_.rows; i++) { const int *coords = descriptorSamples_.ptr(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; dx = 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_x = xf + (-l*scale*si + k*scale*co); - y1 = fRound(sample_y); - x1 = fRound(sample_x); + y1 = cvRound(sample_y); + x1 = cvRound(sample_x); di += *(Lt.ptr(y1)+x1); @@ -1970,26 +2004,27 @@ void MLDB_Descriptor_Subset_Invoker::Get_MLDB_Descriptor_Subset(const KeyPoint& } } - *(values.ptr(options.descriptor_channels*i)) = di; + float* pValues = &values[channels * i]; + pValues[0] = di; - if (options.descriptor_channels == 2) { - *(values.ptr(options.descriptor_channels*i + 1)) = dx; + if (channels == 2) { + pValues[1] = dx; } - else if (options.descriptor_channels == 3) { - *(values.ptr(options.descriptor_channels*i + 1)) = dx; - *(values.ptr(options.descriptor_channels*i + 2)) = dy; + else if (channels == 3) { + pValues[1] = dx; + pValues[2] = dy; } } // Do the comparisons - const float *vals = values.ptr(0); const int *comps = descriptorBits_.ptr(0); + CV_Assert(divUp(descriptorBits_.rows, 8) == desc_size); + memset(desc, 0, desc_size); + for (int i = 0; i vals[comps[2 * i + 1]]) { + if (values[comps[2 * i]] > values[comps[2 * i + 1]]) { 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 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 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 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; Mat Lx = evolution[level].Mx; 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 Mat values ((4 + 9 + 16)*options.descriptor_channels, 1, CV_32FC1); - vector steps(3); - steps.at(0) = options.descriptor_pattern_size; - steps.at(1) = static_cast(ceil(2.f*options.descriptor_pattern_size / 3.f)); - steps.at(2) = options.descriptor_pattern_size / 2; + const int pattern_size = options.descriptor_pattern_size; + CV_Assert((pattern_size & 1) == 0); + const int sample_steps[3] = { + pattern_size, + divUp(pattern_size * 2, 3), + divUp(pattern_size, 2) + }; for (int i = 0; i < descriptorSamples_.rows; i++) { const int *coords = descriptorSamples_.ptr(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; 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_x = xf + k*scale; - y1 = fRound(sample_y); - x1 = fRound(sample_x); + y1 = cvRound(sample_y); + x1 = cvRound(sample_x); di += *(Lt.ptr(y1)+x1); 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(0); const int *comps = descriptorBits_.ptr(0); + CV_Assert(divUp(descriptorBits_.rows, 8) == desc_size); + memset(desc, 0, desc_size); + for (int i = 0; i vals[comps[2 * i + 1]]) { 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++) { int gdiv = i + 2; //grid divisions, per row 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 k = j + 1; k < gsz; k++, c++) { @@ -2134,12 +2174,12 @@ void generateDescriptorSubsample(Mat& sampleList, Mat& comparisons, int nbits, } RNG rng(1024); - Mat_ comps = Mat_(nchannels * (int)ceil(nbits / (float)nchannels), 2); + const int npicks = divUp(nbits, nchannels); + Mat_ comps = Mat_(nchannels * npicks, 2); comps = 1000; // Select some samples. A sample includes all channels int count = 0; - int npicks = (int)ceil(nbits / (float)nchannels); Mat_ samples(29, 3); Mat_ fullcopy = fullM.clone(); samples = -1; diff --git a/modules/features2d/src/kaze/AKAZEFeatures.h b/modules/features2d/src/kaze/AKAZEFeatures.h index 885d0032b9..9f44b57937 100644 --- a/modules/features2d/src/kaze/AKAZEFeatures.h +++ b/modules/features2d/src/kaze/AKAZEFeatures.h @@ -25,6 +25,8 @@ struct Evolution octave = 0; sublevel = 0; sigma_size = 0; + octave_ratio = 0.0f; + border = 0; } UMat Lx, Ly; ///< First order spatial derivatives diff --git a/modules/features2d/src/kaze/KAZEFeatures.cpp b/modules/features2d/src/kaze/KAZEFeatures.cpp index 29d85d3285..6e7024c78c 100644 --- a/modules/features2d/src/kaze/KAZEFeatures.cpp +++ b/modules/features2d/src/kaze/KAZEFeatures.cpp @@ -68,7 +68,7 @@ void KAZEFeatures::Allocate_Memory_Evolution(void) { 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.etime = 0.5f*(aux.esigma*aux.esigma); - aux.sigma_size = fRound(aux.esigma); + aux.sigma_size = cvRound(aux.esigma); aux.octave = i; aux.sublevel = j; evolution_.push_back(aux); @@ -363,10 +363,10 @@ void KAZEFeatures::Determinant_Hessian(std::vector& kpts) 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); + left_x = cvRound(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 = cvRound(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 || up_y < 0 || down_y >= evolution_[level].Ldet.rows) { @@ -587,14 +587,14 @@ void KAZEFeatures::Compute_Main_Orientation(KeyPoint &kpt, const std::vector= 0 && iy < options.img_height && ix >= 0 && ix < options.img_width) { gweight = gaussian(iy - yf, ix - xf, 2.5f*s); @@ -606,7 +606,7 @@ void KAZEFeatures::Compute_Main_Orientation(KeyPoint &kpt, const std::vector max) { // store largest orientation max = sumX*sumX + sumY*sumY; - kpt.angle = getAngle(sumX, sumY) * 180.f / static_cast(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 yf = kpt.pt.y; xf = kpt.pt.x; - scale = fRound(kpt.size / 2.0f); + scale = cvRound(kpt.size / 2.0f); level = kpt.class_id; i = -8; @@ -804,8 +804,8 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_64(const KeyPoint &kpt, float // Get the information from the keypoint yf = kpt.pt.y; xf = kpt.pt.x; - scale = fRound(kpt.size / 2.0f); - angle = (kpt.angle * static_cast(CV_PI)) / 180.f; + scale = cvRound(kpt.size / 2.0f); + angle = kpt.angle * static_cast(CV_PI / 180.f); level = kpt.class_id; co = cos(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 gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); - y1 = fRound(sample_y - 0.5f); - x1 = fRound(sample_x - 0.5f); + y1 = cvFloor(sample_y); + x1 = cvFloor(sample_x); checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height); - y2 = (int)(sample_y + 0.5f); - x2 = (int)(sample_x + 0.5f); + y2 = y1 + 1; + x2 = x1 + 1; 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 yf = kpt.pt.y; xf = kpt.pt.x; - scale = fRound(kpt.size / 2.0f); + scale = cvRound(kpt.size / 2.0f); level = kpt.class_id; i = -8; @@ -1087,8 +1087,8 @@ void KAZE_Descriptor_Invoker::Get_KAZE_Descriptor_128(const KeyPoint &kpt, float // Get the information from the keypoint yf = kpt.pt.y; xf = kpt.pt.x; - scale = fRound(kpt.size / 2.0f); - angle = (kpt.angle * static_cast(CV_PI)) / 180.f; + scale = cvRound(kpt.size / 2.0f); + angle = kpt.angle * static_cast(CV_PI / 180.f); level = kpt.class_id; co = cos(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 gauss_s1 = gaussian(xs - sample_x, ys - sample_y, 2.5f*scale); - y1 = fRound(sample_y - 0.5f); - x1 = fRound(sample_x - 0.5f); + y1 = cvFloor(sample_y); + x1 = cvFloor(sample_x); checkDescriptorLimits(x1, y1, options_.img_width, options_.img_height); - y2 = (int)(sample_y + 0.5f); - x2 = (int)(sample_x + 0.5f); + y2 = y1 + 1; + x2 = x1 + 1; checkDescriptorLimits(x2, y2, options_.img_width, options_.img_height); diff --git a/modules/features2d/src/kaze/fed.cpp b/modules/features2d/src/kaze/fed.cpp index cb47628e03..2026b83875 100644 --- a/modules/features2d/src/kaze/fed.cpp +++ b/modules/features2d/src/kaze/fed.cpp @@ -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 // 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))); // Call internal FED time step creation routine diff --git a/modules/features2d/src/kaze/nldiffusion_functions.cpp b/modules/features2d/src/kaze/nldiffusion_functions.cpp index c6e606820e..16b9615328 100644 --- a/modules/features2d/src/kaze/nldiffusion_functions.cpp +++ b/modules/features2d/src/kaze/nldiffusion_functions.cpp @@ -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 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_; } diff --git a/modules/features2d/src/kaze/utils.h b/modules/features2d/src/kaze/utils.h index d9bfbe4472..44e5b76935 100644 --- a/modules/features2d/src/kaze/utils.h +++ b/modules/features2d/src/kaze/utils.h @@ -1,31 +1,6 @@ #ifndef __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(CV_PI)-atanf(-y / x); - } - - if (x < 0 && y < 0) { - return static_cast(CV_PI)+atanf(y / x); - } - - if (x >= 0 && y < 0) { - return static_cast(2.0 * CV_PI) - atanf(-y / x); - } - - return 0; -} - /* ************************************************************************* */ /** * @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 diff --git a/modules/features2d/test/test_descriptors_invariance.cpp b/modules/features2d/test/test_descriptors_invariance.cpp index 1edb7807be..2ab37dd5ce 100644 --- a/modules/features2d/test/test_descriptors_invariance.cpp +++ b/modules/features2d/test/test_descriptors_invariance.cpp @@ -11,7 +11,7 @@ using std::tr1::make_tuple; using std::tr1::get; using namespace testing; -#define SHOW_DEBUG_LOG 0 +#define SHOW_DEBUG_LOG 1 typedef std::tr1::tuple, Ptr, float> String_FeatureDetector_DescriptorExtractor_Float_t; @@ -72,7 +72,7 @@ TEST_P(DescriptorRotationInvariance, rotation) vector keypoints0; Mat descriptors0; 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); descriptorExtractor->compute(image0, keypoints0, descriptors0); @@ -109,7 +109,7 @@ TEST_P(DescriptorRotationInvariance, rotation) #if SHOW_DEBUG_LOG std::cout << "angle = " << angle - << ", keypoints = " << keypoints1.size() + << ", inliers = " << descInliersCount << ", descInliersRatio = " << static_cast(descInliersCount) / keypoints0.size() << std::endl; #endif @@ -121,6 +121,7 @@ TEST_P(DescriptorScaleInvariance, scale) { vector keypoints0; featureDetector->detect(image0, keypoints0); + std::cout << "Keypoints: " << keypoints0.size() << std::endl; EXPECT_GE(keypoints0.size(), 15u); Mat descriptors0; descriptorExtractor->compute(image0, keypoints0, descriptors0); @@ -159,6 +160,7 @@ TEST_P(DescriptorScaleInvariance, scale) #if SHOW_DEBUG_LOG std::cout << "scale = " << scale + << ", inliers = " << descInliersCount << ", descInliersRatio = " << static_cast(descInliersCount) / keypoints0.size() << std::endl; #endif diff --git a/modules/features2d/test/test_descriptors_regression.cpp b/modules/features2d/test/test_descriptors_regression.cpp index d6fd30d951..0862649bd9 100644 --- a/modules/features2d/test/test_descriptors_regression.cpp +++ b/modules/features2d/test/test_descriptors_regression.cpp @@ -56,6 +56,7 @@ static void writeMatInBin( const Mat& mat, const string& filename ) FILE* f = fopen( filename.c_str(), "wb"); if( f ) { + CV_Assert(4 == sizeof(int)); int type = mat.type(); fwrite( (void*)&mat.rows, 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" ); if( f ) { + CV_Assert(4 == sizeof(int)); int rows, cols, type, dataSize; size_t elements_read1 = fread( (void*)&rows, sizeof(int), 1, f ); size_t elements_read2 = fread( (void*)&cols, sizeof(int), 1, f ); @@ -123,24 +125,37 @@ protected: CV_Assert( DataType::type == validDescriptors.type() ); int dimension = validDescriptors.cols; - DistanceType curMaxDist = std::numeric_limits::min(); + DistanceType curMaxDist = 0; + size_t exact_count = 0, failed_count = 0; for( int y = 0; y < validDescriptors.rows; y++ ) { DistanceType dist = distance( validDescriptors.ptr(y), calcDescriptors.ptr(y), dimension ); + if (dist == 0) + exact_count++; if( dist > curMaxDist ) + { + if (dist > maxDist) + failed_count++; 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; - ss << "Max distance between valid and computed descriptors " << curMaxDist; - if( curMaxDist <= maxDist ) - ss << "." << endl; - else - { - ss << ">" << maxDist << " - bad accuracy!"<< endl; - ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); - } - ts->printf(cvtest::TS::LOG, ss.str().c_str() ); + ss << "Exact count (dist == 0): " << exact_count << " (" << (int)exact_percents << "%)" << std::endl + << "Failed count (dist > " << maxDist << "): " << failed_count << " (" << (int)failed_percents << "%)" << std::endl + << "Max distance between valid and computed descriptors (" << validDescriptors.size() << "): " << curMaxDist; + EXPECT_LE(failed_percents, 20.0f); + std::cout << ss.str() << std::endl; } void emptyDataTest() @@ -202,22 +217,57 @@ protected: ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); 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 keypoints; - FileStorage fs( string(ts->get_data_path()) + FEATURES2D_DIR + "/keypoints.xml.gz", FileStorage::READ ); - if(!detector.empty()) { - detector->detect(img, keypoints); - } else { - read( fs.getFirstTopLevelNode(), keypoints ); + EXPECT_TRUE(fs.isOpened()) << "Keypoint testdata is missing. Re-computing and re-writing keypoints testdata..."; + if (!fs.isOpened()) + { + fs.open(keypoints_filename, FileStorage::WRITE); + ASSERT_TRUE(fs.isOpened()) << "File for writting keypoints can not be opened."; + if (detector.empty()) + { + Ptr 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 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; double t = (double)getTickCount(); - dextractor->compute( img, keypoints, calcDescriptors ); + dextractor->compute(img, keypoints, calcDescriptors); t = getTickCount() - t; 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 keypoints is %d.\n", (int)keypoints.size() ); @@ -226,7 +276,7 @@ protected: 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, "Expected size is %d.\n", dextractor->descriptorSize() ); @@ -239,33 +289,14 @@ protected: // TODO read and write descriptor extractor parameters and check them Mat validDescriptors = readDescriptors(); - if( !validDescriptors.empty() ) - compareDescriptors( validDescriptors, calcDescriptors ); - else + EXPECT_FALSE(validDescriptors.empty()) << "Descriptors testdata is missing. Re-writing descriptors testdata..."; + if (!validDescriptors.empty()) { - if( !writeDescriptors( 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 fd = ORB::create(); - fd->detect(img, keypoints); - write( fs, "keypoints", keypoints ); + compareDescriptors(validDescriptors, calcDescriptors); } else { - ts->printf(cvtest::TS::LOG, "File for writting keypoints can not be opened.\n"); - ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA ); - return; + ASSERT_TRUE(writeDescriptors(calcDescriptors)) << "Descriptors can not be written."; } } } @@ -344,7 +375,7 @@ TEST( Features2d_DescriptorExtractor_KAZE, regression ) TEST( Features2d_DescriptorExtractor_AKAZE, regression ) { CV_DescriptorExtractorTest test( "descriptor-akaze", - (CV_DescriptorExtractorTest::DistanceType)12.f, + (CV_DescriptorExtractorTest::DistanceType)(486*0.05f), AKAZE::create(), Hamming(), AKAZE::create()); test.safe_run(); diff --git a/modules/features2d/test/test_detectors_invariance.cpp b/modules/features2d/test/test_detectors_invariance.cpp index 86a67b37e4..873bf46472 100644 --- a/modules/features2d/test/test_detectors_invariance.cpp +++ b/modules/features2d/test/test_detectors_invariance.cpp @@ -11,7 +11,7 @@ using std::tr1::make_tuple; using std::tr1::get; using namespace testing; -#define SHOW_DEBUG_LOG 0 +#define SHOW_DEBUG_LOG 1 typedef std::tr1::tuple, float, float> String_FeatureDetector_Float_Float_t; const static std::string IMAGE_TSUKUBA = "features2d/tsukuba.png"; diff --git a/modules/photo/src/fast_nlmeans_denoising_opencl.hpp b/modules/photo/src/fast_nlmeans_denoising_opencl.hpp index 216ba6dd62..b19adbda96 100644 --- a/modules/photo/src/fast_nlmeans_denoising_opencl.hpp +++ b/modules/photo/src/fast_nlmeans_denoising_opencl.hpp @@ -23,11 +23,6 @@ enum CTA_SIZE_DEFAULT = 256 }; -static int divUp(int a, int b) -{ - return (a + b - 1) / b; -} - template static bool ocl_calcAlmostDist2Weight(UMat & almostDist2Weight, int searchWindowSize, int templateWindowSize, diff --git a/modules/stitching/perf/perf_stich.cpp b/modules/stitching/perf/perf_stich.cpp index d5ee593d8c..f0ac6561ff 100644 --- a/modules/stitching/perf/perf_stich.cpp +++ b/modules/stitching/perf/perf_stich.cpp @@ -102,7 +102,7 @@ PERF_TEST_P(stitchDatasets, affine, testing::Combine(AFFINE_DATASETS, TEST_DETEC Mat pano; vector imgs; - int width, height, allowed_diff = 10; + int width, height, allowed_diff = 20; Ptr featuresFinder = getFeatureFinder(detector); if(dataset == "budapest") @@ -117,7 +117,7 @@ PERF_TEST_P(stitchDatasets, affine, testing::Combine(AFFINE_DATASETS, TEST_DETEC height = 1158; // this dataset is big, the results between surf and orb differ slightly, // but both are still good - allowed_diff = 27; + allowed_diff = 50; } else if (dataset == "newspaper") {