pull/3042/head
edgarriba 11 years ago
commit 1dec1645e5
  1. 6
      cmake/OpenCVDetectPython.cmake
  2. 8827
      data/haarcascades/haarcascade_mcs_eyepair_big.xml
  3. 10091
      data/haarcascades/haarcascade_mcs_eyepair_small.xml
  4. 7633
      data/haarcascades/haarcascade_mcs_leftear.xml
  5. 19209
      data/haarcascades/haarcascade_mcs_lefteye.xml
  6. 24071
      data/haarcascades/haarcascade_mcs_lefteye_alt.xml
  7. 17680
      data/haarcascades/haarcascade_mcs_mouth.xml
  8. 39332
      data/haarcascades/haarcascade_mcs_nose.xml
  9. 7931
      data/haarcascades/haarcascade_mcs_rightear.xml
  10. 34105
      data/haarcascades/haarcascade_mcs_righteye.xml
  11. 22351
      data/haarcascades/haarcascade_mcs_righteye_alt.xml
  12. 37318
      data/haarcascades/haarcascade_mcs_upperbody.xml
  13. 61401
      data/softcascade/inria_caltech-17.01.2013.xml
  14. 61409
      data/softcascade/soft-cascade-17.12.2012.xml
  15. 2
      doc/CMakeLists.txt
  16. 23
      doc/tutorials/features2d/feature_description/feature_description.rst
  17. 12
      doc/tutorials/features2d/feature_detection/feature_detection.rst
  18. 112
      doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.rst
  19. 5
      doc/tutorials/features2d/feature_homography/feature_homography.rst
  20. 2
      doc/tutorials/introduction/android_binary_package/android_dev_intro.rst
  21. 362
      modules/calib3d/doc/camera_calibration_and_3d_reconstruction.rst
  22. BIN
      modules/calib3d/doc/pics/fisheye_undistorted.jpg
  23. 61
      modules/calib3d/include/opencv2/calib3d.hpp
  24. 1612
      modules/calib3d/src/fisheye.cpp
  25. 61
      modules/calib3d/src/fisheye.hpp
  26. 613
      modules/calib3d/test/test_fisheye.cpp
  27. 75
      modules/core/doc/basic_structures.rst
  28. 54
      modules/core/include/opencv2/core.hpp
  29. 2
      modules/core/include/opencv2/core/core_c.h
  30. 8
      modules/core/include/opencv2/core/cuda.hpp
  31. 37
      modules/core/include/opencv2/core/mat.hpp
  32. 51
      modules/core/include/opencv2/core/mat.inl.hpp
  33. 2
      modules/core/include/opencv2/core/types_c.h
  34. 96
      modules/core/include/opencv2/core/utility.hpp
  35. 244
      modules/core/src/arithm.cpp
  36. 4
      modules/core/src/convert.cpp
  37. 16
      modules/core/src/dxt.cpp
  38. 26
      modules/core/src/lapack.cpp
  39. 1119
      modules/core/src/lda.cpp
  40. 1
      modules/core/src/matmul.cpp
  41. 45
      modules/core/src/matrix.cpp
  42. 7
      modules/core/src/ocl.cpp
  43. 4
      modules/core/src/opencl/fft.cl
  44. 2
      modules/core/src/opencl/minmaxloc.cl
  45. 10
      modules/core/src/stat.cpp
  46. 9
      modules/core/src/umatrix.cpp
  47. 4
      modules/core/test/ocl/test_dft.cpp
  48. 49
      modules/core/test/test_mat.cpp
  49. 18
      modules/core/test/test_umat.cpp
  50. 35
      modules/features2d/doc/common_interfaces_of_descriptor_extractors.rst
  51. 281
      modules/features2d/doc/common_interfaces_of_feature_detectors.rst
  52. 276
      modules/features2d/doc/common_interfaces_of_generic_descriptor_matchers.rst
  53. 76
      modules/features2d/doc/feature_detection_and_description.rst
  54. 1
      modules/features2d/doc/features2d.rst
  55. 651
      modules/features2d/include/opencv2/features2d.hpp
  56. 184
      modules/features2d/src/brief.cpp
  57. 16
      modules/features2d/src/brisk.cpp
  58. 154
      modules/features2d/src/descriptors.cpp
  59. 226
      modules/features2d/src/detectors.cpp
  60. 177
      modules/features2d/src/dynamic.cpp
  61. 53
      modules/features2d/src/evaluation.cpp
  62. 45
      modules/features2d/src/features2d_init.cpp
  63. 734
      modules/features2d/src/freak.cpp
  64. 19
      modules/features2d/src/generated_16.i
  65. 35
      modules/features2d/src/generated_32.i
  66. 67
      modules/features2d/src/generated_64.i
  67. 399
      modules/features2d/src/matchers.cpp
  68. 472
      modules/features2d/src/stardetector.cpp
  69. 22
      modules/features2d/test/test_descriptors_regression.cpp
  70. 18
      modules/features2d/test/test_detectors_regression.cpp
  71. 12
      modules/features2d/test/test_keypoints.cpp
  72. 60
      modules/flann/include/opencv2/flann/dist.h
  73. 6
      modules/imgcodecs/src/grfmt_jpeg2000.cpp
  74. 2
      modules/imgcodecs/src/loadsave.cpp
  75. 107
      modules/imgproc/doc/colormaps.rst
  76. 28
      modules/imgproc/doc/filtering.rst
  77. 1
      modules/imgproc/doc/imgproc.rst
  78. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_autumn.jpg
  79. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_bone.jpg
  80. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_cool.jpg
  81. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_hot.jpg
  82. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_hsv.jpg
  83. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_jet.jpg
  84. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_mkpj1.jpg
  85. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_mkpj2.jpg
  86. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_ocean.jpg
  87. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_pink.jpg
  88. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_rainbow.jpg
  89. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_spring.jpg
  90. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_summer.jpg
  91. BIN
      modules/imgproc/doc/pics/colormaps/colorscale_winter.jpg
  92. 18
      modules/imgproc/include/opencv2/imgproc.hpp
  93. 72
      modules/imgproc/src/clahe.cpp
  94. 20
      modules/imgproc/src/color.cpp
  95. 530
      modules/imgproc/src/colormap.cpp
  96. 5
      modules/imgproc/src/imgwarp.cpp
  97. 37
      modules/imgproc/src/morph.cpp
  98. 5
      modules/imgproc/src/opencl/histogram.cl
  99. 6
      modules/imgproc/src/opencl/pyr_down.cl
  100. 4
      modules/imgproc/src/opencl/remap.cl
  101. Some files were not shown because too many files have changed in this diff Show More

@ -26,6 +26,12 @@ function(find_python preferred_version min_version library_env include_dir_env
libs_found libs_version_string libraries library debug_libraries
debug_library include_path include_dir include_dir2 packages_path
numpy_include_dirs numpy_version)
ocv_check_environment_variables(${executable})
if(${executable})
set(PYTHON_EXECUTABLE "${${executable}}")
endif()
if(WIN32 AND NOT ${executable})
# search for executable with the same bitness as resulting binaries
# standard FindPythonInterp always prefers executable from system path

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -33,7 +33,7 @@ if(BUILD_DOCS AND HAVE_SPHINX)
endif()
endforeach()
set(FIXED_ORDER_MODULES core imgproc imgcodecs videoio highgui video calib3d features2d objdetect ml flann photo stitching nonfree contrib legacy)
set(FIXED_ORDER_MODULES core imgproc imgcodecs videoio highgui video calib3d features2d objdetect ml flann photo stitching)
list(REMOVE_ITEM BASE_MODULES ${FIXED_ORDER_MODULES})

@ -23,7 +23,7 @@ Theory
Code
====
This tutorial code's is shown lines below. You can also download it from `here <https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp>`_
This tutorial code's is shown lines below.
.. code-block:: cpp
@ -32,9 +32,10 @@ This tutorial code's is shown lines below. You can also download it from `here <
#include "opencv2/core.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/nonfree.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
void readme();
@ -50,25 +51,19 @@ This tutorial code's is shown lines below. You can also download it from `here <
if( !img_1.data || !img_2.data )
{ return -1; }
//-- Step 1: Detect the keypoints using SURF Detector
//-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
int minHessian = 400;
SurfFeatureDetector detector( minHessian );
Ptr<SURF> detector = SURF::create();
detector->setMinHessian(minHessian);
std::vector<KeyPoint> keypoints_1, keypoints_2;
detector.detect( img_1, keypoints_1 );
detector.detect( img_2, keypoints_2 );
//-- Step 2: Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor;
Mat descriptors_1, descriptors_2;
extractor.compute( img_1, keypoints_1, descriptors_1 );
extractor.compute( img_2, keypoints_2, descriptors_2 );
detector->detectAndCompute( img_1, keypoints_1, descriptors_1 );
detector->detectAndCompute( img_2, keypoints_2, descriptors_2 );
//-- Step 3: Matching descriptor vectors with a brute force matcher
//-- Step 2: Matching descriptor vectors with a brute force matcher
BFMatcher matcher(NORM_L2);
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );

@ -22,7 +22,7 @@ Theory
Code
====
This tutorial code's is shown lines below. You can also download it from `here <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/features2D/SURF_detector.cpp>`_
This tutorial code's is shown lines below.
.. code-block:: cpp
@ -30,11 +30,11 @@ This tutorial code's is shown lines below. You can also download it from `here <
#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/nonfree/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/nonfree.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
void readme();
@ -53,12 +53,12 @@ This tutorial code's is shown lines below. You can also download it from `here <
//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;
SurfFeatureDetector detector( minHessian );
Ptr<SURF> detector = SURF::create( minHessian );
std::vector<KeyPoint> keypoints_1, keypoints_2;
detector.detect( img_1, keypoints_1 );
detector.detect( img_2, keypoints_2 );
detector->detect( img_1, keypoints_1 );
detector->detect( img_2, keypoints_2 );
//-- Draw keypoints
Mat img_keypoints_1; Mat img_keypoints_2;

@ -19,10 +19,116 @@ Theory
Code
====
This tutorial code's is shown lines below. You can also download it from `here <https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/features2D/SURF_FlannMatcher.cpp>`_
This tutorial code's is shown lines below.
.. code-block:: cpp
/**
* @file SURF_FlannMatcher
* @brief SURF detector + descriptor + FLANN Matcher
* @author A. Huaman
*/
#include <stdio.h>
#include <iostream>
#include <stdio.h>
#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
void readme();
/**
* @function main
* @brief Main function
*/
int main( int argc, char** argv )
{
if( argc != 3 )
{ readme(); return -1; }
Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
if( !img_1.data || !img_2.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;
SurfFeatureDetector detector( minHessian );
std::vector<KeyPoint> keypoints_1, keypoints_2;
detector.detect( img_1, keypoints_1 );
detector.detect( img_2, keypoints_2 );
//-- Step 2: Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor;
Mat descriptors_1, descriptors_2;
extractor.compute( img_1, keypoints_1, descriptors_1 );
extractor.compute( img_2, keypoints_2, descriptors_2 );
//-- Step 3: Matching descriptor vectors using FLANN matcher
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );
double max_dist = 0; double min_dist = 100;
//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_1.rows; i++ )
{ double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );
//-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist,
//-- or a small arbitary value ( 0.02 ) in the event that min_dist is very
//-- small)
//-- PS.- radiusMatch can also be used here.
std::vector< DMatch > good_matches;
for( int i = 0; i < descriptors_1.rows; i++ )
{ if( matches[i].distance <= max(2*min_dist, 0.02) )
{ good_matches.push_back( matches[i]); }
}
//-- Draw only "good" matches
Mat img_matches;
drawMatches( img_1, keypoints_1, img_2, keypoints_2,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Show detected matches
imshow( "Good Matches", img_matches );
for( int i = 0; i < (int)good_matches.size(); i++ )
{ printf( "-- Good Match [%d] Keypoint 1: %d -- Keypoint 2: %d \n", i, good_matches[i].queryIdx, good_matches[i].trainIdx ); }
waitKey(0);
return 0;
}
/**
* @function readme
*/
void readme()
{ std::cout << " Usage: ./SURF_FlannMatcher <img1> <img2>" << std::endl; }
.. literalinclude:: ../../../../samples/cpp/tutorial_code/features2D/SURF_FlannMatcher.cpp
:language: cpp
Explanation
============

@ -20,7 +20,7 @@ Theory
Code
====
This tutorial code's is shown lines below. You can also download it from `here <http://code.opencv.org/projects/opencv/repository/revisions/master/raw/samples/cpp/tutorial_code/features2D/SURF_Homography.cpp>`_
This tutorial code's is shown lines below.
.. code-block:: cpp
@ -30,9 +30,10 @@ This tutorial code's is shown lines below. You can also download it from `here <
#include "opencv2/features2d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/nonfree.hpp"
#include "opencv2/xfeatures2d.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
void readme();

@ -5,7 +5,7 @@
Introduction into Android Development
*************************************
This guide was designed to help you in learning Android development basics and seting up your
This guide was designed to help you in learning Android development basics and setting up your
working environment quickly. It was written with Windows 7 in mind, though it would work with Linux
(Ubuntu), Mac OS X and any other OS supported by Android SDK.

@ -887,7 +887,7 @@ is minimized. If the parameter ``method`` is set to the default value 0, the fun
uses all the point pairs to compute an initial homography estimate with a simple least-squares scheme.
However, if not all of the point pairs (
:math:`srcPoints_i`,:math:`dstPoints_i` ) fit the rigid perspective transformation (that is, there
:math:`srcPoints_i`, :math:`dstPoints_i` ) fit the rigid perspective transformation (that is, there
are some outliers), this initial estimate will be poor.
In this case, you can use one of the two robust methods. Both methods, ``RANSAC`` and ``LMeDS`` , try many different random subsets
of the corresponding point pairs (of four pairs each), estimate
@ -910,7 +910,7 @@ if there are no outliers and the noise is rather small, use the default method (
The function is used to find initial intrinsic and extrinsic matrices.
Homography matrix is determined up to a scale. Thus, it is normalized so that
:math:`h_{33}=1` .
:math:`h_{33}=1`. Note that whenever an H matrix cannot be estimated, an empty one will be returned.
.. seealso::
@ -1525,6 +1525,364 @@ The function reconstructs 3-dimensional points (in homogeneous coordinates) by u
:ocv:func:`reprojectImageTo3D`
fisheye
----------
The methods in this namespace use a so-called fisheye camera model. ::
namespace fisheye
{
//! projects 3D points using fisheye model
void projectPoints(InputArray objectPoints, OutputArray imagePoints, const Affine3d& affine,
InputArray K, InputArray D, double alpha = 0, OutputArray jacobian = noArray());
//! projects points using fisheye model
void projectPoints(InputArray objectPoints, OutputArray imagePoints, InputArray rvec, InputArray tvec,
InputArray K, InputArray D, double alpha = 0, OutputArray jacobian = noArray());
//! distorts 2D points using fisheye model
void distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha = 0);
//! undistorts 2D points using fisheye model
void undistortPoints(InputArray distorted, OutputArray undistorted,
InputArray K, InputArray D, InputArray R = noArray(), InputArray P = noArray());
//! computing undistortion and rectification maps for image transform by cv::remap()
//! If D is empty zero distortion is used, if R or P is empty identity matrixes are used
void initUndistortRectifyMap(InputArray K, InputArray D, InputArray R, InputArray P,
const cv::Size& size, int m1type, OutputArray map1, OutputArray map2);
//! undistorts image, optionally changes resolution and camera matrix.
void undistortImage(InputArray distorted, OutputArray undistorted,
InputArray K, InputArray D, InputArray Knew = cv::noArray(), const Size& new_size = Size());
//! estimates new camera matrix for undistortion or rectification
void estimateNewCameraMatrixForUndistortRectify(InputArray K, InputArray D, const Size &image_size, InputArray R,
OutputArray P, double balance = 0.0, const Size& new_size = Size(), double fov_scale = 1.0);
//! performs camera calibaration
double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size,
InputOutputArray K, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags = 0,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON));
//! stereo rectification estimation
void stereoRectify(InputArray K1, InputArray D1, InputArray K2, InputArray D2, const Size &imageSize, InputArray R, InputArray tvec,
OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags, const Size &newImageSize = Size(),
double balance = 0.0, double fov_scale = 1.0);
//! performs stereo calibration
double stereoCalibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2,
InputOutputArray K1, InputOutputArray D1, InputOutputArray K2, InputOutputArray D2, Size imageSize,
OutputArray R, OutputArray T, int flags = CALIB_FIX_INTRINSIC,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON));
};
Definitions:
Let P be a point in 3D of coordinates X in the world reference frame (stored in the matrix X)
The coordinate vector of P in the camera reference frame is:
.. class:: center
.. math::
Xc = R X + T
where R is the rotation matrix corresponding to the rotation vector om: R = rodrigues(om);
call x, y and z the 3 coordinates of Xc:
.. class:: center
.. math::
x = Xc_1 \\
y = Xc_2 \\
z = Xc_3
The pinehole projection coordinates of P is [a; b] where
.. class:: center
.. math::
a = x / z \ and \ b = y / z \\
r^2 = a^2 + b^2 \\
\theta = atan(r)
Fisheye distortion:
.. class:: center
.. math::
\theta_d = \theta (1 + k_1 \theta^2 + k_2 \theta^4 + k_3 \theta^6 + k_4 \theta^8)
The distorted point coordinates are [x'; y'] where
..class:: center
.. math::
x' = (\theta_d / r) x \\
y' = (\theta_d / r) y
Finally, convertion into pixel coordinates: The final pixel coordinates vector [u; v] where:
.. class:: center
.. math::
u = f_x (x' + \alpha y') + c_x \\
v = f_y yy + c_y
fisheye::projectPoints
---------------------------
Projects points using fisheye model
.. ocv:function:: void fisheye::projectPoints(InputArray objectPoints, OutputArray imagePoints, const Affine3d& affine, InputArray K, InputArray D, double alpha = 0, OutputArray jacobian = noArray())
.. ocv:function:: void fisheye::projectPoints(InputArray objectPoints, OutputArray imagePoints, InputArray rvec, InputArray tvec, InputArray K, InputArray D, double alpha = 0, OutputArray jacobian = noArray())
:param objectPoints: Array of object points, 1xN/Nx1 3-channel (or ``vector<Point3f>`` ), where N is the number of points in the view.
:param rvec: Rotation vector. See :ocv:func:`Rodrigues` for details.
:param tvec: Translation vector.
:param K: Camera matrix :math:`K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}`.
:param D: Input vector of distortion coefficients :math:`(k_1, k_2, k_3, k_4)`.
:param alpha: The skew coefficient.
:param imagePoints: Output array of image points, 2xN/Nx2 1-channel or 1xN/Nx1 2-channel, or ``vector<Point2f>``.
:param jacobian: Optional output 2Nx15 jacobian matrix of derivatives of image points with respect to components of the focal lengths, coordinates of the principal point, distortion coefficients, rotation vector, translation vector, and the skew. In the old interface different components of the jacobian are returned via different output parameters.
The function computes projections of 3D points to the image plane given intrinsic and extrinsic camera parameters. Optionally, the function computes Jacobians - matrices of partial derivatives of image points coordinates (as functions of all the input parameters) with respect to the particular parameters, intrinsic and/or extrinsic.
fisheye::distortPoints
-------------------------
Distorts 2D points using fisheye model.
.. ocv:function:: void fisheye::distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha = 0)
:param undistorted: Array of object points, 1xN/Nx1 2-channel (or ``vector<Point2f>`` ), where N is the number of points in the view.
:param K: Camera matrix :math:`K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}`.
:param D: Input vector of distortion coefficients :math:`(k_1, k_2, k_3, k_4)`.
:param alpha: The skew coefficient.
:param distorted: Output array of image points, 1xN/Nx1 2-channel, or ``vector<Point2f>`` .
fisheye::undistortPoints
-----------------------------
Undistorts 2D points using fisheye model
.. ocv:function:: void fisheye::undistortPoints(InputArray distorted, OutputArray undistorted, InputArray K, InputArray D, InputArray R = noArray(), InputArray P = noArray())
:param distorted: Array of object points, 1xN/Nx1 2-channel (or ``vector<Point2f>`` ), where N is the number of points in the view.
:param K: Camera matrix :math:`K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}`.
:param D: Input vector of distortion coefficients :math:`(k_1, k_2, k_3, k_4)`.
:param R: Rectification transformation in the object space: 3x3 1-channel, or vector: 3x1/1x3 1-channel or 1x1 3-channel
:param P: New camera matrix (3x3) or new projection matrix (3x4)
:param undistorted: Output array of image points, 1xN/Nx1 2-channel, or ``vector<Point2f>`` .
fisheye::initUndistortRectifyMap
-------------------------------------
Computes undistortion and rectification maps for image transform by cv::remap(). If D is empty zero distortion is used, if R or P is empty identity matrixes are used.
.. ocv:function:: void fisheye::initUndistortRectifyMap(InputArray K, InputArray D, InputArray R, InputArray P, const cv::Size& size, int m1type, OutputArray map1, OutputArray map2)
:param K: Camera matrix :math:`K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}`.
:param D: Input vector of distortion coefficients :math:`(k_1, k_2, k_3, k_4)`.
:param R: Rectification transformation in the object space: 3x3 1-channel, or vector: 3x1/1x3 1-channel or 1x1 3-channel
:param P: New camera matrix (3x3) or new projection matrix (3x4)
:param size: Undistorted image size.
:param m1type: Type of the first output map that can be CV_32FC1 or CV_16SC2 . See convertMaps() for details.
:param map1: The first output map.
:param map2: The second output map.
fisheye::undistortImage
-----------------------
Transforms an image to compensate for fisheye lens distortion.
.. ocv:function:: void fisheye::undistortImage(InputArray distorted, OutputArray undistorted, InputArray K, InputArray D, InputArray Knew = cv::noArray(), const Size& new_size = Size())
:param distorted: image with fisheye lens distortion.
:param K: Camera matrix :math:`K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}`.
:param D: Input vector of distortion coefficients :math:`(k_1, k_2, k_3, k_4)`.
:param Knew: Camera matrix of the distorted image. By default, it is the identity matrix but you may additionally scale and shift the result by using a different matrix.
:param undistorted: Output image with compensated fisheye lens distortion.
The function transforms an image to compensate radial and tangential lens distortion.
The function is simply a combination of
:ocv:func:`fisheye::initUndistortRectifyMap` (with unity ``R`` ) and
:ocv:func:`remap` (with bilinear interpolation). See the former function for details of the transformation being performed.
See below the results of undistortImage.
* a\) result of :ocv:func:`undistort` of perspective camera model (all possible coefficients (k_1, k_2, k_3, k_4, k_5, k_6) of distortion were optimized under calibration)
* b\) result of :ocv:func:`fisheye::undistortImage` of fisheye camera model (all possible coefficients (k_1, k_2, k_3, k_4) of fisheye distortion were optimized under calibration)
* c\) original image was captured with fisheye lens
Pictures a) and b) almost the same. But if we consider points of image located far from the center of image, we can notice that on image a) these points are distorted.
.. image:: pics/fisheye_undistorted.jpg
fisheye::estimateNewCameraMatrixForUndistortRectify
----------------------------------------------------------
Estimates new camera matrix for undistortion or rectification.
.. ocv:function:: void fisheye::estimateNewCameraMatrixForUndistortRectify(InputArray K, InputArray D, const Size &image_size, InputArray R, OutputArray P, double balance = 0.0, const Size& new_size = Size(), double fov_scale = 1.0)
:param K: Camera matrix :math:`K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}`.
:param D: Input vector of distortion coefficients :math:`(k_1, k_2, k_3, k_4)`.
:param R: Rectification transformation in the object space: 3x3 1-channel, or vector: 3x1/1x3 1-channel or 1x1 3-channel
:param P: New camera matrix (3x3) or new projection matrix (3x4)
:param balance: Sets the new focal length in range between the min focal length and the max focal length. Balance is in range of [0, 1].
:param fov_scale: Divisor for new focal length.
fisheye::stereoRectify
------------------------------
Stereo rectification for fisheye camera model
.. ocv:function:: void fisheye::stereoRectify(InputArray K1, InputArray D1, InputArray K2, InputArray D2, const Size &imageSize, InputArray R, InputArray tvec, OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags, const Size &newImageSize = Size(), double balance = 0.0, double fov_scale = 1.0)
:param K1: First camera matrix.
:param K2: Second camera matrix.
:param D1: First camera distortion parameters.
:param D2: Second camera distortion parameters.
:param imageSize: Size of the image used for stereo calibration.
:param rotation: Rotation matrix between the coordinate systems of the first and the second cameras.
:param tvec: Translation vector between coordinate systems of the cameras.
:param R1: Output 3x3 rectification transform (rotation matrix) for the first camera.
:param R2: Output 3x3 rectification transform (rotation matrix) for the second camera.
:param P1: Output 3x4 projection matrix in the new (rectified) coordinate systems for the first camera.
:param P2: Output 3x4 projection matrix in the new (rectified) coordinate systems for the second camera.
:param Q: Output :math:`4 \times 4` disparity-to-depth mapping matrix (see :ocv:func:`reprojectImageTo3D` ).
:param flags: Operation flags that may be zero or ``CV_CALIB_ZERO_DISPARITY`` . If the flag is set, the function makes the principal points of each camera have the same pixel coordinates in the rectified views. And if the flag is not set, the function may still shift the images in the horizontal or vertical direction (depending on the orientation of epipolar lines) to maximize the useful image area.
:param alpha: Free scaling parameter. If it is -1 or absent, the function performs the default scaling. Otherwise, the parameter should be between 0 and 1. ``alpha=0`` means that the rectified images are zoomed and shifted so that only valid pixels are visible (no black areas after rectification). ``alpha=1`` means that the rectified image is decimated and shifted so that all the pixels from the original images from the cameras are retained in the rectified images (no source image pixels are lost). Obviously, any intermediate value yields an intermediate result between those two extreme cases.
:param newImageSize: New image resolution after rectification. The same size should be passed to :ocv:func:`initUndistortRectifyMap` (see the ``stereo_calib.cpp`` sample in OpenCV samples directory). When (0,0) is passed (default), it is set to the original ``imageSize`` . Setting it to larger value can help you preserve details in the original image, especially when there is a big radial distortion.
:param roi1: Optional output rectangles inside the rectified images where all the pixels are valid. If ``alpha=0`` , the ROIs cover the whole images. Otherwise, they are likely to be smaller (see the picture below).
:param roi2: Optional output rectangles inside the rectified images where all the pixels are valid. If ``alpha=0`` , the ROIs cover the whole images. Otherwise, they are likely to be smaller (see the picture below).
:param balance: Sets the new focal length in range between the min focal length and the max focal length. Balance is in range of [0, 1].
:param fov_scale: Divisor for new focal length.
fisheye::calibrate
----------------------------
Performs camera calibaration
.. ocv:function:: double fisheye::calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size, InputOutputArray K, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags = 0, TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON))
:param objectPoints: vector of vectors of calibration pattern points in the calibration pattern coordinate space.
:param imagePoints: vector of vectors of the projections of calibration pattern points. ``imagePoints.size()`` and ``objectPoints.size()`` and ``imagePoints[i].size()`` must be equal to ``objectPoints[i].size()`` for each ``i``.
:param image_size: Size of the image used only to initialize the intrinsic camera matrix.
:param K: Output 3x3 floating-point camera matrix :math:`A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}` . If ``fisheye::CALIB_USE_INTRINSIC_GUESS``/ is specified, some or all of ``fx, fy, cx, cy`` must be initialized before calling the function.
:param D: Output vector of distortion coefficients :math:`(k_1, k_2, k_3, k_4)`.
:param rvecs: Output vector of rotation vectors (see :ocv:func:`Rodrigues` ) estimated for each pattern view. That is, each k-th rotation vector together with the corresponding k-th translation vector (see the next output parameter description) brings the calibration pattern from the model coordinate space (in which object points are specified) to the world coordinate space, that is, a real position of the calibration pattern in the k-th pattern view (k=0.. *M* -1).
:param tvecs: Output vector of translation vectors estimated for each pattern view.
:param flags: Different flags that may be zero or a combination of the following values:
* **fisheye::CALIB_USE_INTRINSIC_GUESS** ``cameraMatrix`` contains valid initial values of ``fx, fy, cx, cy`` that are optimized further. Otherwise, ``(cx, cy)`` is initially set to the image center ( ``imageSize`` is used), and focal distances are computed in a least-squares fashion.
* **fisheye::CALIB_RECOMPUTE_EXTRINSIC** Extrinsic will be recomputed after each iteration of intrinsic optimization.
* **fisheye::CALIB_CHECK_COND** The functions will check validity of condition number.
* **fisheye::CALIB_FIX_SKEW** Skew coefficient (alpha) is set to zero and stay zero.
* **fisheye::CALIB_FIX_K1..4** Selected distortion coefficients are set to zeros and stay zero.
:param criteria: Termination criteria for the iterative optimization algorithm.
fisheye::stereoCalibrate
----------------------------
Performs stereo calibration
.. ocv:function:: double fisheye::stereoCalibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, InputOutputArray K1, InputOutputArray D1, InputOutputArray K2, InputOutputArray D2, Size imageSize, OutputArray R, OutputArray T, int flags = CALIB_FIX_INTRINSIC, TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON))
:param objectPoints: Vector of vectors of the calibration pattern points.
:param imagePoints1: Vector of vectors of the projections of the calibration pattern points, observed by the first camera.
:param imagePoints2: Vector of vectors of the projections of the calibration pattern points, observed by the second camera.
:param K1: Input/output first camera matrix: :math:`\vecthreethree{f_x^{(j)}}{0}{c_x^{(j)}}{0}{f_y^{(j)}}{c_y^{(j)}}{0}{0}{1}` , :math:`j = 0,\, 1` . If any of ``fisheye::CALIB_USE_INTRINSIC_GUESS`` , ``fisheye::CV_CALIB_FIX_INTRINSIC`` are specified, some or all of the matrix components must be initialized.
:param D1: Input/output vector of distortion coefficients :math:`(k_1, k_2, k_3, k_4)` of 4 elements.
:param K2: Input/output second camera matrix. The parameter is similar to ``K1`` .
:param D2: Input/output lens distortion coefficients for the second camera. The parameter is similar to ``D1`` .
:param imageSize: Size of the image used only to initialize intrinsic camera matrix.
:param R: Output rotation matrix between the 1st and the 2nd camera coordinate systems.
:param T: Output translation vector between the coordinate systems of the cameras.
:param flags: Different flags that may be zero or a combination of the following values:
* **fisheye::CV_CALIB_FIX_INTRINSIC** Fix ``K1, K2?`` and ``D1, D2?`` so that only ``R, T`` matrices are estimated.
* **fisheye::CALIB_USE_INTRINSIC_GUESS** ``K1, K2`` contains valid initial values of ``fx, fy, cx, cy`` that are optimized further. Otherwise, ``(cx, cy)`` is initially set to the image center (``imageSize`` is used), and focal distances are computed in a least-squares fashion.
* **fisheye::CALIB_RECOMPUTE_EXTRINSIC** Extrinsic will be recomputed after each iteration of intrinsic optimization.
* **fisheye::CALIB_CHECK_COND** The functions will check validity of condition number.
* **fisheye::CALIB_FIX_SKEW** Skew coefficient (alpha) is set to zero and stay zero.
* **fisheye::CALIB_FIX_K1..4** Selected distortion coefficients are set to zeros and stay zero.
:param criteria: Termination criteria for the iterative optimization algorithm.
.. [BT98] Birchfield, S. and Tomasi, C. A pixel dissimilarity measure that is insensitive to image sampling. IEEE Transactions on Pattern Analysis and Machine Intelligence. 1998.

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

@ -46,6 +46,7 @@
#include "opencv2/core.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/core/affine.hpp"
namespace cv
{
@ -417,6 +418,66 @@ CV_EXPORTS_W Ptr<StereoSGBM> createStereoSGBM(int minDisparity, int numDispariti
int speckleWindowSize = 0, int speckleRange = 0,
int mode = StereoSGBM::MODE_SGBM);
namespace fisheye
{
enum{
CALIB_USE_INTRINSIC_GUESS = 1,
CALIB_RECOMPUTE_EXTRINSIC = 2,
CALIB_CHECK_COND = 4,
CALIB_FIX_SKEW = 8,
CALIB_FIX_K1 = 16,
CALIB_FIX_K2 = 32,
CALIB_FIX_K3 = 64,
CALIB_FIX_K4 = 128,
CALIB_FIX_INTRINSIC = 256
};
//! projects 3D points using fisheye model
CV_EXPORTS void projectPoints(InputArray objectPoints, OutputArray imagePoints, const Affine3d& affine,
InputArray K, InputArray D, double alpha = 0, OutputArray jacobian = noArray());
//! projects points using fisheye model
CV_EXPORTS void projectPoints(InputArray objectPoints, OutputArray imagePoints, InputArray rvec, InputArray tvec,
InputArray K, InputArray D, double alpha = 0, OutputArray jacobian = noArray());
//! distorts 2D points using fisheye model
CV_EXPORTS void distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha = 0);
//! undistorts 2D points using fisheye model
CV_EXPORTS void undistortPoints(InputArray distorted, OutputArray undistorted,
InputArray K, InputArray D, InputArray R = noArray(), InputArray P = noArray());
//! computing undistortion and rectification maps for image transform by cv::remap()
//! If D is empty zero distortion is used, if R or P is empty identity matrixes are used
CV_EXPORTS void initUndistortRectifyMap(InputArray K, InputArray D, InputArray R, InputArray P,
const cv::Size& size, int m1type, OutputArray map1, OutputArray map2);
//! undistorts image, optionally changes resolution and camera matrix. If Knew zero identity matrix is used
CV_EXPORTS void undistortImage(InputArray distorted, OutputArray undistorted,
InputArray K, InputArray D, InputArray Knew = cv::noArray(), const Size& new_size = Size());
//! estimates new camera matrix for undistortion or rectification
CV_EXPORTS void estimateNewCameraMatrixForUndistortRectify(InputArray K, InputArray D, const Size &image_size, InputArray R,
OutputArray P, double balance = 0.0, const Size& new_size = Size(), double fov_scale = 1.0);
//! performs camera calibaration
CV_EXPORTS double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size,
InputOutputArray K, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags = 0,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON));
//! stereo rectification estimation
CV_EXPORTS void stereoRectify(InputArray K1, InputArray D1, InputArray K2, InputArray D2, const Size &imageSize, InputArray R, InputArray tvec,
OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags, const Size &newImageSize = Size(),
double balance = 0.0, double fov_scale = 1.0);
//! performs stereo calibaration
CV_EXPORTS double stereoCalibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2,
InputOutputArray K1, InputOutputArray D1, InputOutputArray K2, InputOutputArray D2, Size imageSize,
OutputArray R, OutputArray T, int flags = CALIB_FIX_INTRINSIC,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, DBL_EPSILON));
}
} // cv
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,61 @@
#ifndef FISHEYE_INTERNAL_H
#define FISHEYE_INTERNAL_H
#include "precomp.hpp"
namespace cv { namespace internal {
struct CV_EXPORTS IntrinsicParams
{
Vec2d f;
Vec2d c;
Vec4d k;
double alpha;
std::vector<int> isEstimate;
IntrinsicParams();
IntrinsicParams(Vec2d f, Vec2d c, Vec4d k, double alpha = 0);
IntrinsicParams operator+(const Mat& a);
IntrinsicParams& operator =(const Mat& a);
void Init(const cv::Vec2d& f, const cv::Vec2d& c, const cv::Vec4d& k = Vec4d(0,0,0,0), const double& alpha = 0);
};
void projectPoints(cv::InputArray objectPoints, cv::OutputArray imagePoints,
cv::InputArray _rvec,cv::InputArray _tvec,
const IntrinsicParams& param, cv::OutputArray jacobian);
void ComputeExtrinsicRefine(const Mat& imagePoints, const Mat& objectPoints, Mat& rvec,
Mat& tvec, Mat& J, const int MaxIter,
const IntrinsicParams& param, const double thresh_cond);
CV_EXPORTS Mat ComputeHomography(Mat m, Mat M);
CV_EXPORTS Mat NormalizePixels(const Mat& imagePoints, const IntrinsicParams& param);
void InitExtrinsics(const Mat& _imagePoints, const Mat& _objectPoints, const IntrinsicParams& param, Mat& omckk, Mat& Tckk);
void CalibrateExtrinsics(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints,
const IntrinsicParams& param, const int check_cond,
const double thresh_cond, InputOutputArray omc, InputOutputArray Tc);
void ComputeJacobians(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints,
const IntrinsicParams& param, InputArray omc, InputArray Tc,
const int& check_cond, const double& thresh_cond, Mat& JJ2_inv, Mat& ex3);
CV_EXPORTS void EstimateUncertainties(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints,
const IntrinsicParams& params, InputArray omc, InputArray Tc,
IntrinsicParams& errors, Vec2d& std_err, double thresh_cond, int check_cond, double& rms);
void dAB(cv::InputArray A, InputArray B, OutputArray dABdA, OutputArray dABdB);
void JRodriguesMatlab(const Mat& src, Mat& dst);
void compose_motion(InputArray _om1, InputArray _T1, InputArray _om2, InputArray _T2,
Mat& om3, Mat& T3, Mat& dom3dom1, Mat& dom3dT1, Mat& dom3dom2,
Mat& dom3dT2, Mat& dT3dom1, Mat& dT3dT1, Mat& dT3dom2, Mat& dT3dT2);
double median(const Mat& row);
Vec3d median3d(InputArray m);
}}
#endif

@ -0,0 +1,613 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#include <opencv2/ts/cuda_test.hpp>
#include "../src/fisheye.hpp"
class fisheyeTest : public ::testing::Test {
protected:
const static cv::Size imageSize;
const static cv::Matx33d K;
const static cv::Vec4d D;
const static cv::Matx33d R;
const static cv::Vec3d T;
std::string datasets_repository_path;
virtual void SetUp() {
datasets_repository_path = combine(cvtest::TS::ptr()->get_data_path(), "cv/cameracalibration/fisheye");
}
protected:
std::string combine(const std::string& _item1, const std::string& _item2);
cv::Mat mergeRectification(const cv::Mat& l, const cv::Mat& r);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// TESTS::
TEST_F(fisheyeTest, projectPoints)
{
double cols = this->imageSize.width,
rows = this->imageSize.height;
const int N = 20;
cv::Mat distorted0(1, N*N, CV_64FC2), undist1, undist2, distorted1, distorted2;
undist2.create(distorted0.size(), CV_MAKETYPE(distorted0.depth(), 3));
cv::Vec2d* pts = distorted0.ptr<cv::Vec2d>();
cv::Vec2d c(this->K(0, 2), this->K(1, 2));
for(int y = 0, k = 0; y < N; ++y)
for(int x = 0; x < N; ++x)
{
cv::Vec2d point(x*cols/(N-1.f), y*rows/(N-1.f));
pts[k++] = (point - c) * 0.85 + c;
}
cv::fisheye::undistortPoints(distorted0, undist1, this->K, this->D);
cv::Vec2d* u1 = undist1.ptr<cv::Vec2d>();
cv::Vec3d* u2 = undist2.ptr<cv::Vec3d>();
for(int i = 0; i < (int)distorted0.total(); ++i)
u2[i] = cv::Vec3d(u1[i][0], u1[i][1], 1.0);
cv::fisheye::distortPoints(undist1, distorted1, this->K, this->D);
cv::fisheye::projectPoints(undist2, distorted2, cv::Vec3d::all(0), cv::Vec3d::all(0), this->K, this->D);
EXPECT_MAT_NEAR(distorted0, distorted1, 1e-10);
EXPECT_MAT_NEAR(distorted0, distorted2, 1e-10);
}
TEST_F(fisheyeTest, DISABLED_undistortImage)
{
cv::Matx33d K = this->K;
cv::Mat D = cv::Mat(this->D);
std::string file = combine(datasets_repository_path, "/calib-3_stereo_from_JY/left/stereo_pair_014.jpg");
cv::Matx33d newK = K;
cv::Mat distorted = cv::imread(file), undistorted;
{
newK(0, 0) = 100;
newK(1, 1) = 100;
cv::fisheye::undistortImage(distorted, undistorted, K, D, newK);
cv::Mat correct = cv::imread(combine(datasets_repository_path, "new_f_100.png"));
if (correct.empty())
CV_Assert(cv::imwrite(combine(datasets_repository_path, "new_f_100.png"), undistorted));
else
EXPECT_MAT_NEAR(correct, undistorted, 1e-10);
}
{
double balance = 1.0;
cv::fisheye::estimateNewCameraMatrixForUndistortRectify(K, D, distorted.size(), cv::noArray(), newK, balance);
cv::fisheye::undistortImage(distorted, undistorted, K, D, newK);
cv::Mat correct = cv::imread(combine(datasets_repository_path, "balance_1.0.png"));
if (correct.empty())
CV_Assert(cv::imwrite(combine(datasets_repository_path, "balance_1.0.png"), undistorted));
else
EXPECT_MAT_NEAR(correct, undistorted, 1e-10);
}
{
double balance = 0.0;
cv::fisheye::estimateNewCameraMatrixForUndistortRectify(K, D, distorted.size(), cv::noArray(), newK, balance);
cv::fisheye::undistortImage(distorted, undistorted, K, D, newK);
cv::Mat correct = cv::imread(combine(datasets_repository_path, "balance_0.0.png"));
if (correct.empty())
CV_Assert(cv::imwrite(combine(datasets_repository_path, "balance_0.0.png"), undistorted));
else
EXPECT_MAT_NEAR(correct, undistorted, 1e-10);
}
}
TEST_F(fisheyeTest, jacobians)
{
int n = 10;
cv::Mat X(1, n, CV_64FC3);
cv::Mat om(3, 1, CV_64F), T(3, 1, CV_64F);
cv::Mat f(2, 1, CV_64F), c(2, 1, CV_64F);
cv::Mat k(4, 1, CV_64F);
double alpha;
cv::RNG r;
r.fill(X, cv::RNG::NORMAL, 2, 1);
X = cv::abs(X) * 10;
r.fill(om, cv::RNG::NORMAL, 0, 1);
om = cv::abs(om);
r.fill(T, cv::RNG::NORMAL, 0, 1);
T = cv::abs(T); T.at<double>(2) = 4; T *= 10;
r.fill(f, cv::RNG::NORMAL, 0, 1);
f = cv::abs(f) * 1000;
r.fill(c, cv::RNG::NORMAL, 0, 1);
c = cv::abs(c) * 1000;
r.fill(k, cv::RNG::NORMAL, 0, 1);
k*= 0.5;
alpha = 0.01*r.gaussian(1);
cv::Mat x1, x2, xpred;
cv::Matx33d K(f.at<double>(0), alpha * f.at<double>(0), c.at<double>(0),
0, f.at<double>(1), c.at<double>(1),
0, 0, 1);
cv::Mat jacobians;
cv::fisheye::projectPoints(X, x1, om, T, K, k, alpha, jacobians);
//test on T:
cv::Mat dT(3, 1, CV_64FC1);
r.fill(dT, cv::RNG::NORMAL, 0, 1);
dT *= 1e-9*cv::norm(T);
cv::Mat T2 = T + dT;
cv::fisheye::projectPoints(X, x2, om, T2, K, k, alpha, cv::noArray());
xpred = x1 + cv::Mat(jacobians.colRange(11,14) * dT).reshape(2, 1);
CV_Assert (cv::norm(x2 - xpred) < 1e-10);
//test on om:
cv::Mat dom(3, 1, CV_64FC1);
r.fill(dom, cv::RNG::NORMAL, 0, 1);
dom *= 1e-9*cv::norm(om);
cv::Mat om2 = om + dom;
cv::fisheye::projectPoints(X, x2, om2, T, K, k, alpha, cv::noArray());
xpred = x1 + cv::Mat(jacobians.colRange(8,11) * dom).reshape(2, 1);
CV_Assert (cv::norm(x2 - xpred) < 1e-10);
//test on f:
cv::Mat df(2, 1, CV_64FC1);
r.fill(df, cv::RNG::NORMAL, 0, 1);
df *= 1e-9*cv::norm(f);
cv::Matx33d K2 = K + cv::Matx33d(df.at<double>(0), df.at<double>(0) * alpha, 0, 0, df.at<double>(1), 0, 0, 0, 0);
cv::fisheye::projectPoints(X, x2, om, T, K2, k, alpha, cv::noArray());
xpred = x1 + cv::Mat(jacobians.colRange(0,2) * df).reshape(2, 1);
CV_Assert (cv::norm(x2 - xpred) < 1e-10);
//test on c:
cv::Mat dc(2, 1, CV_64FC1);
r.fill(dc, cv::RNG::NORMAL, 0, 1);
dc *= 1e-9*cv::norm(c);
K2 = K + cv::Matx33d(0, 0, dc.at<double>(0), 0, 0, dc.at<double>(1), 0, 0, 0);
cv::fisheye::projectPoints(X, x2, om, T, K2, k, alpha, cv::noArray());
xpred = x1 + cv::Mat(jacobians.colRange(2,4) * dc).reshape(2, 1);
CV_Assert (cv::norm(x2 - xpred) < 1e-10);
//test on k:
cv::Mat dk(4, 1, CV_64FC1);
r.fill(dk, cv::RNG::NORMAL, 0, 1);
dk *= 1e-9*cv::norm(k);
cv::Mat k2 = k + dk;
cv::fisheye::projectPoints(X, x2, om, T, K, k2, alpha, cv::noArray());
xpred = x1 + cv::Mat(jacobians.colRange(4,8) * dk).reshape(2, 1);
CV_Assert (cv::norm(x2 - xpred) < 1e-10);
//test on alpha:
cv::Mat dalpha(1, 1, CV_64FC1);
r.fill(dalpha, cv::RNG::NORMAL, 0, 1);
dalpha *= 1e-9*cv::norm(f);
double alpha2 = alpha + dalpha.at<double>(0);
K2 = K + cv::Matx33d(0, f.at<double>(0) * dalpha.at<double>(0), 0, 0, 0, 0, 0, 0, 0);
cv::fisheye::projectPoints(X, x2, om, T, K, k, alpha2, cv::noArray());
xpred = x1 + cv::Mat(jacobians.col(14) * dalpha).reshape(2, 1);
CV_Assert (cv::norm(x2 - xpred) < 1e-10);
}
TEST_F(fisheyeTest, Calibration)
{
const int n_images = 34;
std::vector<std::vector<cv::Point2d> > imagePoints(n_images);
std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ);
CV_Assert(fs_left.isOpened());
for(int i = 0; i < n_images; ++i)
fs_left[cv::format("image_%d", i )] >> imagePoints[i];
fs_left.release();
cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ);
CV_Assert(fs_object.isOpened());
for(int i = 0; i < n_images; ++i)
fs_object[cv::format("image_%d", i )] >> objectPoints[i];
fs_object.release();
int flag = 0;
flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
flag |= cv::fisheye::CALIB_CHECK_COND;
flag |= cv::fisheye::CALIB_FIX_SKEW;
cv::Matx33d K;
cv::Vec4d D;
cv::fisheye::calibrate(objectPoints, imagePoints, imageSize, K, D,
cv::noArray(), cv::noArray(), flag, cv::TermCriteria(3, 20, 1e-6));
EXPECT_MAT_NEAR(K, this->K, 1e-10);
EXPECT_MAT_NEAR(D, this->D, 1e-10);
}
TEST_F(fisheyeTest, Homography)
{
const int n_images = 1;
std::vector<std::vector<cv::Point2d> > imagePoints(n_images);
std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ);
CV_Assert(fs_left.isOpened());
for(int i = 0; i < n_images; ++i)
fs_left[cv::format("image_%d", i )] >> imagePoints[i];
fs_left.release();
cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ);
CV_Assert(fs_object.isOpened());
for(int i = 0; i < n_images; ++i)
fs_object[cv::format("image_%d", i )] >> objectPoints[i];
fs_object.release();
cv::internal::IntrinsicParams param;
param.Init(cv::Vec2d(cv::max(imageSize.width, imageSize.height) / CV_PI, cv::max(imageSize.width, imageSize.height) / CV_PI),
cv::Vec2d(imageSize.width / 2.0 - 0.5, imageSize.height / 2.0 - 0.5));
cv::Mat _imagePoints (imagePoints[0]);
cv::Mat _objectPoints(objectPoints[0]);
cv::Mat imagePointsNormalized = NormalizePixels(_imagePoints, param).reshape(1).t();
_objectPoints = _objectPoints.reshape(1).t();
cv::Mat objectPointsMean, covObjectPoints;
int Np = imagePointsNormalized.cols;
cv::calcCovarMatrix(_objectPoints, covObjectPoints, objectPointsMean, cv::COVAR_NORMAL | cv::COVAR_COLS);
cv::SVD svd(covObjectPoints);
cv::Mat R(svd.vt);
if (cv::norm(R(cv::Rect(2, 0, 1, 2))) < 1e-6)
R = cv::Mat::eye(3,3, CV_64FC1);
if (cv::determinant(R) < 0)
R = -R;
cv::Mat T = -R * objectPointsMean;
cv::Mat X_new = R * _objectPoints + T * cv::Mat::ones(1, Np, CV_64FC1);
cv::Mat H = cv::internal::ComputeHomography(imagePointsNormalized, X_new.rowRange(0, 2));
cv::Mat M = cv::Mat::ones(3, X_new.cols, CV_64FC1);
X_new.rowRange(0, 2).copyTo(M.rowRange(0, 2));
cv::Mat mrep = H * M;
cv::divide(mrep, cv::Mat::ones(3,1, CV_64FC1) * mrep.row(2).clone(), mrep);
cv::Mat merr = (mrep.rowRange(0, 2) - imagePointsNormalized).t();
cv::Vec2d std_err;
cv::meanStdDev(merr.reshape(2), cv::noArray(), std_err);
std_err *= sqrt((double)merr.reshape(2).total() / (merr.reshape(2).total() - 1));
cv::Vec2d correct_std_err(0.00516740156010384, 0.00644205331553901);
EXPECT_MAT_NEAR(std_err, correct_std_err, 1e-12);
}
TEST_F(fisheyeTest, EtimateUncertainties)
{
const int n_images = 34;
std::vector<std::vector<cv::Point2d> > imagePoints(n_images);
std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ);
CV_Assert(fs_left.isOpened());
for(int i = 0; i < n_images; ++i)
fs_left[cv::format("image_%d", i )] >> imagePoints[i];
fs_left.release();
cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ);
CV_Assert(fs_object.isOpened());
for(int i = 0; i < n_images; ++i)
fs_object[cv::format("image_%d", i )] >> objectPoints[i];
fs_object.release();
int flag = 0;
flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
flag |= cv::fisheye::CALIB_CHECK_COND;
flag |= cv::fisheye::CALIB_FIX_SKEW;
cv::Matx33d K;
cv::Vec4d D;
std::vector<cv::Vec3d> rvec;
std::vector<cv::Vec3d> tvec;
cv::fisheye::calibrate(objectPoints, imagePoints, imageSize, K, D,
rvec, tvec, flag, cv::TermCriteria(3, 20, 1e-6));
cv::internal::IntrinsicParams param, errors;
cv::Vec2d err_std;
double thresh_cond = 1e6;
int check_cond = 1;
param.Init(cv::Vec2d(K(0,0), K(1,1)), cv::Vec2d(K(0,2), K(1, 2)), D);
param.isEstimate = std::vector<int>(9, 1);
param.isEstimate[4] = 0;
errors.isEstimate = param.isEstimate;
double rms;
cv::internal::EstimateUncertainties(objectPoints, imagePoints, param, rvec, tvec,
errors, err_std, thresh_cond, check_cond, rms);
EXPECT_MAT_NEAR(errors.f, cv::Vec2d(1.29837104202046, 1.31565641071524), 1e-10);
EXPECT_MAT_NEAR(errors.c, cv::Vec2d(0.890439368129246, 0.816096854937896), 1e-10);
EXPECT_MAT_NEAR(errors.k, cv::Vec4d(0.00516248605191506, 0.0168181467500934, 0.0213118690274604, 0.00916010877545648), 1e-10);
EXPECT_MAT_NEAR(err_std, cv::Vec2d(0.187475975266883, 0.185678953263995), 1e-10);
CV_Assert(abs(rms - 0.263782587133546) < 1e-10);
CV_Assert(errors.alpha == 0);
}
TEST_F(fisheyeTest, rectify)
{
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
cv::Size calibration_size = this->imageSize, requested_size = calibration_size;
cv::Matx33d K1 = this->K, K2 = K1;
cv::Mat D1 = cv::Mat(this->D), D2 = D1;
cv::Vec3d T = this->T;
cv::Matx33d R = this->R;
double balance = 0.0, fov_scale = 1.1;
cv::Mat R1, R2, P1, P2, Q;
cv::fisheye::stereoRectify(K1, D1, K2, D2, calibration_size, R, T, R1, R2, P1, P2, Q,
cv::CALIB_ZERO_DISPARITY, requested_size, balance, fov_scale);
cv::Mat lmapx, lmapy, rmapx, rmapy;
//rewrite for fisheye
cv::fisheye::initUndistortRectifyMap(K1, D1, R1, P1, requested_size, CV_32F, lmapx, lmapy);
cv::fisheye::initUndistortRectifyMap(K2, D2, R2, P2, requested_size, CV_32F, rmapx, rmapy);
cv::Mat l, r, lundist, rundist;
cv::VideoCapture lcap(combine(folder, "left/stereo_pair_%03d.jpg")),
rcap(combine(folder, "right/stereo_pair_%03d.jpg"));
for(int i = 0;; ++i)
{
lcap >> l; rcap >> r;
if (l.empty() || r.empty())
break;
int ndisp = 128;
cv::rectangle(l, cv::Rect(255, 0, 829, l.rows-1), cv::Scalar(0, 0, 255));
cv::rectangle(r, cv::Rect(255, 0, 829, l.rows-1), cv::Scalar(0, 0, 255));
cv::rectangle(r, cv::Rect(255-ndisp, 0, 829+ndisp ,l.rows-1), cv::Scalar(0, 0, 255));
cv::remap(l, lundist, lmapx, lmapy, cv::INTER_LINEAR);
cv::remap(r, rundist, rmapx, rmapy, cv::INTER_LINEAR);
cv::Mat rectification = mergeRectification(lundist, rundist);
cv::Mat correct = cv::imread(combine(datasets_repository_path, cv::format("rectification_AB_%03d.png", i)));
if (correct.empty())
cv::imwrite(combine(datasets_repository_path, cv::format("rectification_AB_%03d.png", i)), rectification);
else
EXPECT_MAT_NEAR(correct, rectification, 1e-10);
}
}
TEST_F(fisheyeTest, stereoCalibrate)
{
const int n_images = 34;
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
std::vector<std::vector<cv::Point2d> > leftPoints(n_images);
std::vector<std::vector<cv::Point2d> > rightPoints(n_images);
std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ);
CV_Assert(fs_left.isOpened());
for(int i = 0; i < n_images; ++i)
fs_left[cv::format("image_%d", i )] >> leftPoints[i];
fs_left.release();
cv::FileStorage fs_right(combine(folder, "right.xml"), cv::FileStorage::READ);
CV_Assert(fs_right.isOpened());
for(int i = 0; i < n_images; ++i)
fs_right[cv::format("image_%d", i )] >> rightPoints[i];
fs_right.release();
cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ);
CV_Assert(fs_object.isOpened());
for(int i = 0; i < n_images; ++i)
fs_object[cv::format("image_%d", i )] >> objectPoints[i];
fs_object.release();
cv::Matx33d K1, K2, R;
cv::Vec3d T;
cv::Vec4d D1, D2;
int flag = 0;
flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
flag |= cv::fisheye::CALIB_CHECK_COND;
flag |= cv::fisheye::CALIB_FIX_SKEW;
// flag |= cv::fisheye::CALIB_FIX_INTRINSIC;
cv::fisheye::stereoCalibrate(objectPoints, leftPoints, rightPoints,
K1, D1, K2, D2, imageSize, R, T, flag,
cv::TermCriteria(3, 12, 0));
cv::Matx33d R_correct( 0.9975587205950972, 0.06953016383322372, 0.006492709911733523,
-0.06956823121068059, 0.9975601387249519, 0.005833595226966235,
-0.006071257768382089, -0.006271040135405457, 0.9999619062167968);
cv::Vec3d T_correct(-0.099402724724121, 0.00270812139265413, 0.00129330292472699);
cv::Matx33d K1_correct (561.195925927249, 0, 621.282400272412,
0, 562.849402029712, 380.555455380889,
0, 0, 1);
cv::Matx33d K2_correct (560.395452535348, 0, 678.971652040359,
0, 561.90171021422, 380.401340535339,
0, 0, 1);
cv::Vec4d D1_correct (-7.44253716539556e-05, -0.00702662033932424, 0.00737569823650885, -0.00342230256441771);
cv::Vec4d D2_correct (-0.0130785435677431, 0.0284434505383497, -0.0360333869900506, 0.0144724062347222);
EXPECT_MAT_NEAR(R, R_correct, 1e-10);
EXPECT_MAT_NEAR(T, T_correct, 1e-10);
EXPECT_MAT_NEAR(K1, K1_correct, 1e-10);
EXPECT_MAT_NEAR(K2, K2_correct, 1e-10);
EXPECT_MAT_NEAR(D1, D1_correct, 1e-10);
EXPECT_MAT_NEAR(D2, D2_correct, 1e-10);
}
TEST_F(fisheyeTest, stereoCalibrateFixIntrinsic)
{
const int n_images = 34;
const std::string folder =combine(datasets_repository_path, "calib-3_stereo_from_JY");
std::vector<std::vector<cv::Point2d> > leftPoints(n_images);
std::vector<std::vector<cv::Point2d> > rightPoints(n_images);
std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
cv::FileStorage fs_left(combine(folder, "left.xml"), cv::FileStorage::READ);
CV_Assert(fs_left.isOpened());
for(int i = 0; i < n_images; ++i)
fs_left[cv::format("image_%d", i )] >> leftPoints[i];
fs_left.release();
cv::FileStorage fs_right(combine(folder, "right.xml"), cv::FileStorage::READ);
CV_Assert(fs_right.isOpened());
for(int i = 0; i < n_images; ++i)
fs_right[cv::format("image_%d", i )] >> rightPoints[i];
fs_right.release();
cv::FileStorage fs_object(combine(folder, "object.xml"), cv::FileStorage::READ);
CV_Assert(fs_object.isOpened());
for(int i = 0; i < n_images; ++i)
fs_object[cv::format("image_%d", i )] >> objectPoints[i];
fs_object.release();
cv::Matx33d R;
cv::Vec3d T;
int flag = 0;
flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
flag |= cv::fisheye::CALIB_CHECK_COND;
flag |= cv::fisheye::CALIB_FIX_SKEW;
flag |= cv::fisheye::CALIB_FIX_INTRINSIC;
cv::Matx33d K1 (561.195925927249, 0, 621.282400272412,
0, 562.849402029712, 380.555455380889,
0, 0, 1);
cv::Matx33d K2 (560.395452535348, 0, 678.971652040359,
0, 561.90171021422, 380.401340535339,
0, 0, 1);
cv::Vec4d D1 (-7.44253716539556e-05, -0.00702662033932424, 0.00737569823650885, -0.00342230256441771);
cv::Vec4d D2 (-0.0130785435677431, 0.0284434505383497, -0.0360333869900506, 0.0144724062347222);
cv::fisheye::stereoCalibrate(objectPoints, leftPoints, rightPoints,
K1, D1, K2, D2, imageSize, R, T, flag,
cv::TermCriteria(3, 12, 0));
cv::Matx33d R_correct( 0.9975587205950972, 0.06953016383322372, 0.006492709911733523,
-0.06956823121068059, 0.9975601387249519, 0.005833595226966235,
-0.006071257768382089, -0.006271040135405457, 0.9999619062167968);
cv::Vec3d T_correct(-0.099402724724121, 0.00270812139265413, 0.00129330292472699);
EXPECT_MAT_NEAR(R, R_correct, 1e-10);
EXPECT_MAT_NEAR(T, T_correct, 1e-10);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// fisheyeTest::
const cv::Size fisheyeTest::imageSize(1280, 800);
const cv::Matx33d fisheyeTest::K(558.478087865323, 0, 620.458515360843,
0, 560.506767351568, 381.939424848348,
0, 0, 1);
const cv::Vec4d fisheyeTest::D(-0.0014613319981768, -0.00329861110580401, 0.00605760088590183, -0.00374209380722371);
const cv::Matx33d fisheyeTest::R ( 9.9756700084424932e-01, 6.9698277640183867e-02, 1.4929569991321144e-03,
-6.9711825162322980e-02, 9.9748249845531767e-01, 1.2997180766418455e-02,
-5.8331736398316541e-04,-1.3069635393884985e-02, 9.9991441852366736e-01);
const cv::Vec3d fisheyeTest::T(-9.9217369356044638e-02, 3.1741831972356663e-03, 1.8551007952921010e-04);
std::string fisheyeTest::combine(const std::string& _item1, const std::string& _item2)
{
std::string item1 = _item1, item2 = _item2;
std::replace(item1.begin(), item1.end(), '\\', '/');
std::replace(item2.begin(), item2.end(), '\\', '/');
if (item1.empty())
return item2;
if (item2.empty())
return item1;
char last = item1[item1.size()-1];
return item1 + (last != '/' ? "/" : "") + item2;
}
cv::Mat fisheyeTest::mergeRectification(const cv::Mat& l, const cv::Mat& r)
{
CV_Assert(l.type() == r.type() && l.size() == r.size());
cv::Mat merged(l.rows, l.cols * 2, l.type());
cv::Mat lpart = merged.colRange(0, l.cols);
cv::Mat rpart = merged.colRange(l.cols, merged.cols);
l.copyTo(lpart);
r.copyTo(rpart);
for(int i = 0; i < l.rows; i+=20)
cv::line(merged, cv::Point(0, i), cv::Point(merged.cols, i), cv::Scalar(0, 255, 0));
return merged;
}

@ -2325,6 +2325,69 @@ Returns the matrix iterator and sets it to the after-last matrix element.
The methods return the matrix read-only or read-write iterators, set to the point following the last matrix element.
Mat::forEach
------------
Invoke with arguments functor, and runs the functor over all matrix element.
.. ocv:function:: template<typename _Tp, typename Functor> void Mat::forEach(Functor operation)
.. ocv:function:: template<typename _Tp, typename Functor> void Mat::forEach(Functor operation) const
The methos runs operation in parallel. Operation is passed by arguments. Operation have to be a function pointer, a function object or a lambda(C++11).
All of below operation is equal. Put 0xFF to first channel of all matrix elements. ::
Mat image(1920, 1080, CV_8UC3);
typedef cv::Point3_<uint8_t> Pixel;
// first. raw pointer access.
for (int r = 0; r < image.rows; ++r) {
Pixel* ptr = image.ptr<Pixel>(0, r);
const Pixel* ptr_end = ptr + image.cols;
for (; ptr != ptr_end; ++ptr) {
ptr->x = 255;
}
}
// Using MatIterator. (Simple but there are a Iterator's overhead)
for (Pixel &p : cv::Mat_<Pixel>(image)) {
p.x = 255;
}
// Parallel execution with function object.
struct Operator {
void operator ()(Pixel &pixel, const int * position) {
pixel.x = 255;
}
};
image.forEach<Pixel>(Operator());
// Parallel execution using C++11 lambda.
image.forEach<Pixel>([](Pixel &p, const int * position) -> void {
p.x = 255;
});
position parameter is index of current pixel. ::
// Creating 3D matrix (255 x 255 x 255) typed uint8_t,
// and initialize all elements by the value which equals elements position.
// i.e. pixels (x,y,z) = (1,2,3) is (b,g,r) = (1,2,3).
int sizes[] = { 255, 255, 255 };
typedef cv::Point3_<uint8_t> Pixel;
Mat_<Pixel> image = Mat::zeros(3, sizes, CV_8UC3);
image.forEachWithPosition([&](Pixel& pixel, const int position[]) -> void{
pixel.x = position[0];
pixel.y = position[1];
pixel.z = position[2];
});
Mat\_
-----
.. ocv:class:: Mat_
@ -2987,13 +3050,13 @@ The class provides the following features for all derived classes:
Here is example of SIFT use in your application via Algorithm interface: ::
#include "opencv2/opencv.hpp"
#include "opencv2/nonfree.hpp"
#include "opencv2/xfeatures2d.hpp"
...
using namespace cv::xfeatures2d;
initModule_nonfree(); // to load SURF/SIFT etc.
...
Ptr<Feature2D> sift = Algorithm::create<Feature2D>("Feature2D.SIFT");
Ptr<Feature2D> sift = SIFT::create();
FileStorage fs("sift_params.xml", FileStorage::READ);
if( fs.isOpened() ) // if we have file with parameters, read them
@ -3003,7 +3066,7 @@ Here is example of SIFT use in your application via Algorithm interface: ::
}
else // else modify the parameters and store them; user can later edit the file to use different parameters
{
sift->set("contrastThreshold", 0.01f); // lower the contrast threshold, compared to the default value
sift->setContrastThreshold(0.01f); // lower the contrast threshold, compared to the default value
{
WriteStructContext ws(fs, "sift_params", CV_NODE_MAP);
@ -3013,7 +3076,7 @@ Here is example of SIFT use in your application via Algorithm interface: ::
Mat image = imread("myimage.png", 0), descriptors;
vector<KeyPoint> keypoints;
(*sift)(image, noArray(), keypoints, descriptors);
sift->detectAndCompute(image, noArray(), keypoints, descriptors);
Algorithm::name
---------------

@ -690,7 +690,61 @@ public:
Mat mean; //!< mean value subtracted before the projection and added after the back projection
};
// Linear Discriminant Analysis
class CV_EXPORTS LDA
{
public:
// Initializes a LDA with num_components (default 0) and specifies how
// samples are aligned (default dataAsRow=true).
explicit LDA(int num_components = 0);
// Initializes and performs a Discriminant Analysis with Fisher's
// Optimization Criterion on given data in src and corresponding labels
// in labels. If 0 (or less) number of components are given, they are
// automatically determined for given data in computation.
LDA(InputArrayOfArrays src, InputArray labels, int num_components = 0);
// Serializes this object to a given filename.
void save(const String& filename) const;
// Deserializes this object from a given filename.
void load(const String& filename);
// Serializes this object to a given cv::FileStorage.
void save(FileStorage& fs) const;
// Deserializes this object from a given cv::FileStorage.
void load(const FileStorage& node);
// Destructor.
~LDA();
//! Compute the discriminants for data in src and labels.
void compute(InputArrayOfArrays src, InputArray labels);
// Projects samples into the LDA subspace.
Mat project(InputArray src);
// Reconstructs projections from the LDA subspace.
Mat reconstruct(InputArray src);
// Returns the eigenvectors of this LDA.
Mat eigenvectors() const { return _eigenvectors; }
// Returns the eigenvalues of this LDA.
Mat eigenvalues() const { return _eigenvalues; }
static Mat subspaceProject(InputArray W, InputArray mean, InputArray src);
static Mat subspaceReconstruct(InputArray W, InputArray mean, InputArray src);
protected:
bool _dataAsRow;
int _num_components;
Mat _eigenvectors;
Mat _eigenvalues;
void lda(InputArrayOfArrays src, InputArray labels);
};
/*!
Singular Value Decomposition class

@ -1122,7 +1122,7 @@ CV_INLINE CvSetElem* cvSetNew( CvSet* set_header )
set_header->active_count++;
}
else
cvSetAdd( set_header, NULL, (CvSetElem**)&elem );
cvSetAdd( set_header, NULL, &elem );
return elem;
}

@ -261,8 +261,8 @@ public:
int* refcount;
//! helper fields used in locateROI and adjustROI
uchar* datastart;
uchar* dataend;
const uchar* datastart;
const uchar* dataend;
//! allocator
Allocator* allocator;
@ -349,8 +349,8 @@ public:
uchar* data;
int* refcount;
uchar* datastart;
uchar* dataend;
const uchar* datastart;
const uchar* dataend;
AllocType alloc_type;
};

@ -395,7 +395,7 @@ struct CV_EXPORTS UMatData
struct CV_EXPORTS UMatDataAutoLock
{
UMatDataAutoLock(UMatData* u);
explicit UMatDataAutoLock(UMatData* u);
~UMatDataAutoLock();
UMatData* u;
};
@ -403,7 +403,7 @@ struct CV_EXPORTS UMatDataAutoLock
struct CV_EXPORTS MatSize
{
MatSize(int* _p);
explicit MatSize(int* _p);
Size operator()() const;
const int& operator[](int i) const;
int& operator[](int i);
@ -417,7 +417,7 @@ struct CV_EXPORTS MatSize
struct CV_EXPORTS MatStep
{
MatStep();
MatStep(size_t s);
explicit MatStep(size_t s);
const size_t& operator[](int i) const;
size_t& operator[](int i);
operator size_t() const;
@ -900,6 +900,11 @@ public:
template<typename _Tp> MatConstIterator_<_Tp> begin() const;
template<typename _Tp> MatConstIterator_<_Tp> end() const;
//! template methods for for operation over all matrix elements.
// the operations take care of skipping gaps in the end of rows (if any)
template<typename _Tp, typename Functor> void forEach(const Functor& operation);
template<typename _Tp, typename Functor> void forEach(const Functor& operation) const;
enum { MAGIC_VAL = 0x42FF0000, AUTO_STEP = 0, CONTINUOUS_FLAG = CV_MAT_CONT_FLAG, SUBMATRIX_FLAG = CV_SUBMAT_FLAG };
enum { MAGIC_MASK = 0xFFFF0000, TYPE_MASK = 0x00000FFF, DEPTH_MASK = 7 };
@ -918,9 +923,9 @@ public:
uchar* data;
//! helper fields used in locateROI and adjustROI
uchar* datastart;
uchar* dataend;
uchar* datalimit;
const uchar* datastart;
const uchar* dataend;
const uchar* datalimit;
//! custom allocator
MatAllocator* allocator;
@ -934,6 +939,7 @@ public:
MatStep step;
protected:
template<typename _Tp, typename Functor> void forEach_impl(const Functor& operation);
};
@ -1043,6 +1049,11 @@ public:
const_iterator begin() const;
const_iterator end() const;
//! template methods for for operation over all matrix elements.
// the operations take care of skipping gaps in the end of rows (if any)
template<typename Functor> void forEach(const Functor& operation);
template<typename Functor> void forEach(const Functor& operation) const;
//! equivalent to Mat::create(_rows, _cols, DataType<_Tp>::type)
void create(int _rows, int _cols);
//! equivalent to Mat::create(_size, DataType<_Tp>::type)
@ -1804,9 +1815,9 @@ public:
//! copy operator
MatConstIterator& operator = (const MatConstIterator& it);
//! returns the current matrix element
uchar* operator *() const;
const uchar* operator *() const;
//! returns the i-th matrix element, relative to the current
uchar* operator [](ptrdiff_t i) const;
const uchar* operator [](ptrdiff_t i) const;
//! shifts the iterator forward by the specified number of elements
MatConstIterator& operator += (ptrdiff_t ofs);
@ -1831,9 +1842,9 @@ public:
const Mat* m;
size_t elemSize;
uchar* ptr;
uchar* sliceStart;
uchar* sliceEnd;
const uchar* ptr;
const uchar* sliceStart;
const uchar* sliceEnd;
};
@ -1917,9 +1928,9 @@ public:
//! constructor that sets the iterator to the specified element of the matrix
MatIterator_(Mat_<_Tp>* _m, int _row, int _col=0);
//! constructor that sets the iterator to the specified element of the matrix
MatIterator_(const Mat_<_Tp>* _m, Point _pt);
MatIterator_(Mat_<_Tp>* _m, Point _pt);
//! constructor that sets the iterator to the specified element of the matrix
MatIterator_(const Mat_<_Tp>* _m, const int* _idx);
MatIterator_(Mat_<_Tp>* _m, const int* _idx);
//! copy constructor
MatIterator_(const MatIterator_& it);
//! copy operator

@ -438,7 +438,7 @@ Mat::Mat(const std::vector<_Tp>& vec, bool copyData)
if( !copyData )
{
step[0] = step[1] = sizeof(_Tp);
data = datastart = (uchar*)&vec[0];
datastart = data = (uchar*)&vec[0];
datalimit = dataend = datastart + rows * step[0];
}
else
@ -453,7 +453,7 @@ Mat::Mat(const Vec<_Tp, n>& vec, bool copyData)
if( !copyData )
{
step[0] = step[1] = sizeof(_Tp);
data = datastart = (uchar*)vec.val;
datastart = data = (uchar*)vec.val;
datalimit = dataend = datastart + rows * step[0];
}
else
@ -470,7 +470,7 @@ Mat::Mat(const Matx<_Tp,m,n>& M, bool copyData)
{
step[0] = cols * sizeof(_Tp);
step[1] = sizeof(_Tp);
data = datastart = (uchar*)M.val;
datastart = data = (uchar*)M.val;
datalimit = dataend = datastart + rows * step[0];
}
else
@ -485,7 +485,7 @@ Mat::Mat(const Point_<_Tp>& pt, bool copyData)
if( !copyData )
{
step[0] = step[1] = sizeof(_Tp);
data = datastart = (uchar*)&pt.x;
datastart = data = (uchar*)&pt.x;
datalimit = dataend = datastart + rows * step[0];
}
else
@ -504,7 +504,7 @@ Mat::Mat(const Point3_<_Tp>& pt, bool copyData)
if( !copyData )
{
step[0] = step[1] = sizeof(_Tp);
data = datastart = (uchar*)&pt.x;
datastart = data = (uchar*)&pt.x;
datalimit = dataend = datastart + rows * step[0];
}
else
@ -642,8 +642,9 @@ inline void Mat::release()
if( u && CV_XADD(&u->refcount, -1) == 1 )
deallocate();
u = NULL;
data = datastart = dataend = datalimit = 0;
size.p[0] = 0;
datastart = dataend = datalimit = data = 0;
for(int i = 0; i < dims; i++)
size.p[i] = 0;
}
inline
@ -999,6 +1000,17 @@ MatIterator_<_Tp> Mat::end()
return it;
}
template<typename _Tp, typename Functor> inline
void Mat::forEach(const Functor& operation) {
this->forEach_impl<_Tp>(operation);
};
template<typename _Tp, typename Functor> inline
void Mat::forEach(const Functor& operation) const {
// call as not const
(const_cast<Mat*>(this))->forEach<const _Tp>(operation);
};
template<typename _Tp> inline
Mat::operator std::vector<_Tp>() const
{
@ -1044,7 +1056,7 @@ void Mat::push_back(const _Tp& elem)
}
CV_Assert(DataType<_Tp>::type == type() && cols == 1
/* && dims == 2 (cols == 1 implies dims == 2) */);
uchar* tmp = dataend + step[0];
const uchar* tmp = dataend + step[0];
if( !isSubmatrix() && isContinuous() && tmp <= datalimit )
{
*(_Tp*)(data + (size.p[0]++) * step.p[0]) = elem;
@ -1584,6 +1596,15 @@ MatIterator_<_Tp> Mat_<_Tp>::end()
return Mat::end<_Tp>();
}
template<typename _Tp> template<typename Functor> inline
void Mat_<_Tp>::forEach(const Functor& operation) {
Mat::forEach<_Tp, Functor>(operation);
}
template<typename _Tp> template<typename Functor> inline
void Mat_<_Tp>::forEach(const Functor& operation) const {
Mat::forEach<_Tp, Functor>(operation);
}
///////////////////////////// SparseMat /////////////////////////////
@ -2148,7 +2169,7 @@ MatConstIterator& MatConstIterator::operator = (const MatConstIterator& it )
}
inline
uchar* MatConstIterator::operator *() const
const uchar* MatConstIterator::operator *() const
{
return ptr;
}
@ -2281,7 +2302,7 @@ MatConstIterator operator - (const MatConstIterator& a, ptrdiff_t ofs)
inline
uchar* MatConstIterator::operator [](ptrdiff_t i) const
const uchar* MatConstIterator::operator [](ptrdiff_t i) const
{
return *(*this + i);
}
@ -2453,12 +2474,12 @@ MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m, int _row, int _col)
{}
template<typename _Tp> inline
MatIterator_<_Tp>::MatIterator_(const Mat_<_Tp>* _m, Point _pt)
MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m, Point _pt)
: MatConstIterator_<_Tp>(_m, _pt)
{}
template<typename _Tp> inline
MatIterator_<_Tp>::MatIterator_(const Mat_<_Tp>* _m, const int* _idx)
MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m, const int* _idx)
: MatConstIterator_<_Tp>(_m, _idx)
{}
@ -2592,7 +2613,7 @@ inline SparseMatConstIterator& SparseMatConstIterator::operator = (const SparseM
template<typename _Tp> inline
const _Tp& SparseMatConstIterator::value() const
{
return *(_Tp*)ptr;
return *(const _Tp*)ptr;
}
inline
@ -2733,7 +2754,7 @@ SparseMatConstIterator_<_Tp>& SparseMatConstIterator_<_Tp>::operator ++()
template<typename _Tp> inline
SparseMatConstIterator_<_Tp> SparseMatConstIterator_<_Tp>::operator ++(int)
{
SparseMatConstIterator it = *this;
SparseMatConstIterator_<_Tp> it = *this;
SparseMatConstIterator::operator ++();
return it;
}
@ -2785,7 +2806,7 @@ SparseMatIterator_<_Tp>& SparseMatIterator_<_Tp>::operator ++()
template<typename _Tp> inline
SparseMatIterator_<_Tp> SparseMatIterator_<_Tp>::operator ++(int)
{
SparseMatIterator it = *this;
SparseMatIterator_<_Tp> it = *this;
SparseMatConstIterator::operator ++();
return it;
}

@ -548,7 +548,7 @@ CV_INLINE void cvmSet( CvMat* mat, int row, int col, double value )
else
{
assert( type == CV_64FC1 );
((double*)(void*)(mat->data.ptr + (size_t)mat->step*row))[col] = (double)value;
((double*)(void*)(mat->data.ptr + (size_t)mat->step*row))[col] = value;
}
}

@ -274,6 +274,102 @@ public:
CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes=-1.);
/////////////////////////////// forEach method of cv::Mat ////////////////////////////
template<typename _Tp, typename Functor> inline
void Mat::forEach_impl(const Functor& operation) {
if (false) {
operation(*reinterpret_cast<_Tp*>(0), reinterpret_cast<int*>(NULL));
// If your compiler fail in this line.
// Please check that your functor signature is
// (_Tp&, const int*) <- multidimential
// or (_Tp&, void*) <- in case of you don't need current idx.
}
CV_Assert(this->total() / this->size[this->dims - 1] <= INT_MAX);
const int LINES = static_cast<int>(this->total() / this->size[this->dims - 1]);
class PixelOperationWrapper :public ParallelLoopBody
{
public:
PixelOperationWrapper(Mat_<_Tp>* const frame, const Functor& _operation)
: mat(frame), op(_operation) {};
virtual ~PixelOperationWrapper(){};
// ! Overloaded virtual operator
// convert range call to row call.
virtual void operator()(const Range &range) const {
const int DIMS = mat->dims;
const int COLS = mat->size[DIMS - 1];
if (DIMS <= 2) {
for (int row = range.start; row < range.end; ++row) {
this->rowCall2(row, COLS);
}
} else {
std::vector<int> idx(COLS); /// idx is modified in this->rowCall
idx[DIMS - 2] = range.start - 1;
for (int line_num = range.start; line_num < range.end; ++line_num) {
idx[DIMS - 2]++;
for (int i = DIMS - 2; i >= 0; --i) {
if (idx[i] >= mat->size[i]) {
idx[i - 1] += idx[i] / mat->size[i];
idx[i] %= mat->size[i];
continue; // carry-over;
}
else {
break;
}
}
this->rowCall(&idx[0], COLS, DIMS);
}
}
};
private:
Mat_<_Tp>* const mat;
const Functor op;
// ! Call operator for each elements in this row.
inline void rowCall(int* const idx, const int COLS, const int DIMS) const {
int &col = idx[DIMS - 1];
col = 0;
_Tp* pixel = &(mat->template at<_Tp>(idx));
while (col < COLS) {
op(*pixel, const_cast<const int*>(idx));
pixel++; col++;
}
col = 0;
}
// ! Call operator for each elements in this row. 2d mat special version.
inline void rowCall2(const int row, const int COLS) const {
union Index{
int body[2];
operator const int*() const {
return reinterpret_cast<const int*>(this);
}
int& operator[](const int i) {
return body[i];
}
} idx = {{row, 0}};
// Special union is needed to avoid
// "error: array subscript is above array bounds [-Werror=array-bounds]"
// when call the functor `op` such that access idx[3].
_Tp* pixel = &(mat->template at<_Tp>(idx));
const _Tp* const pixel_end = pixel + COLS;
while(pixel < pixel_end) {
op(*pixel++, static_cast<const int*>(idx));
idx[1]++;
}
};
PixelOperationWrapper& operator=(const PixelOperationWrapper &) {
CV_Assert(false);
// We can not remove this implementation because Visual Studio warning C4822.
return *this;
};
};
parallel_for_(cv::Range(0, LINES), PixelOperationWrapper(reinterpret_cast<Mat_<_Tp>*>(this), operation));
};
/////////////////////////// Synchronization Primitives ///////////////////////////////
class CV_EXPORTS Mutex

@ -2440,6 +2440,34 @@ addWeighted8u( const uchar* src1, size_t step1,
_mm_storel_epi64((__m128i*)(dst + x), u);
}
}
#elif CV_NEON
float32x4_t g = vdupq_n_f32 (gamma);
for( ; x <= size.width - 8; x += 8 )
{
uint8x8_t in1 = vld1_u8(src1+x);
uint16x8_t in1_16 = vmovl_u8(in1);
float32x4_t in1_f_l = vcvtq_f32_u32(vmovl_u16(vget_low_u16(in1_16)));
float32x4_t in1_f_h = vcvtq_f32_u32(vmovl_u16(vget_high_u16(in1_16)));
uint8x8_t in2 = vld1_u8(src2+x);
uint16x8_t in2_16 = vmovl_u8(in2);
float32x4_t in2_f_l = vcvtq_f32_u32(vmovl_u16(vget_low_u16(in2_16)));
float32x4_t in2_f_h = vcvtq_f32_u32(vmovl_u16(vget_high_u16(in2_16)));
float32x4_t out_f_l = vaddq_f32(vmulq_n_f32(in1_f_l, alpha), vmulq_n_f32(in2_f_l, beta));
float32x4_t out_f_h = vaddq_f32(vmulq_n_f32(in1_f_h, alpha), vmulq_n_f32(in2_f_h, beta));
out_f_l = vaddq_f32(out_f_l, g);
out_f_h = vaddq_f32(out_f_h, g);
uint16x4_t out_16_l = vqmovun_s32(vcvtq_s32_f32(out_f_l));
uint16x4_t out_16_h = vqmovun_s32(vcvtq_s32_f32(out_f_h));
uint16x8_t out_16 = vcombine_u16(out_16_l, out_16_h);
uint8x8_t out = vqmovn_u16(out_16);
vst1_u8(dst+x, out);
}
#endif
#if CV_ENABLE_UNROLLED
for( ; x <= size.width - 4; x += 4 )
@ -2650,6 +2678,14 @@ static void cmp8u(const uchar* src1, size_t step1, const uchar* src2, size_t ste
}
}
#elif CV_NEON
uint8x16_t mask = code == CMP_GT ? vdupq_n_u8(0) : vdupq_n_u8(255);
for( ; x <= size.width - 16; x += 16 )
{
vst1q_u8(dst+x, veorq_u8(vcgtq_u8(vld1q_u8(src1+x), vld1q_u8(src2+x)), mask));
}
#endif
for( ; x < size.width; x++ ){
@ -2674,6 +2710,13 @@ static void cmp8u(const uchar* src1, size_t step1, const uchar* src2, size_t ste
_mm_storeu_si128((__m128i*)(dst + x), r00);
}
}
#elif CV_NEON
uint8x16_t mask = code == CMP_EQ ? vdupq_n_u8(0) : vdupq_n_u8(255);
for( ; x <= size.width - 16; x += 16 )
{
vst1q_u8(dst+x, veorq_u8(vceqq_u8(vld1q_u8(src1+x), vld1q_u8(src2+x)), mask));
}
#endif
for( ; x < size.width; x++ )
dst[x] = (uchar)(-(src1[x] == src2[x]) ^ m);
@ -2759,6 +2802,22 @@ static void cmp16s(const short* src1, size_t step1, const short* src2, size_t st
x += 8;
}
}
#elif CV_NEON
uint8x16_t mask = code == CMP_GT ? vdupq_n_u8(0) : vdupq_n_u8(255);
for( ; x <= size.width - 16; x += 16 )
{
int16x8_t in1 = vld1q_s16(src1 + x);
int16x8_t in2 = vld1q_s16(src2 + x);
uint8x8_t t1 = vmovn_u16(vcgtq_s16(in1, in2));
in1 = vld1q_s16(src1 + x + 8);
in2 = vld1q_s16(src2 + x + 8);
uint8x8_t t2 = vmovn_u16(vcgtq_s16(in1, in2));
vst1q_u8(dst+x, veorq_u8(vcombine_u8(t1, t2), mask));
}
#endif
for( ; x < size.width; x++ ){
@ -2797,6 +2856,21 @@ static void cmp16s(const short* src1, size_t step1, const short* src2, size_t st
x += 8;
}
}
#elif CV_NEON
uint8x16_t mask = code == CMP_EQ ? vdupq_n_u8(0) : vdupq_n_u8(255);
for( ; x <= size.width - 16; x += 16 )
{
int16x8_t in1 = vld1q_s16(src1 + x);
int16x8_t in2 = vld1q_s16(src2 + x);
uint8x8_t t1 = vmovn_u16(vceqq_s16(in1, in2));
in1 = vld1q_s16(src1 + x + 8);
in2 = vld1q_s16(src2 + x + 8);
uint8x8_t t2 = vmovn_u16(vceqq_s16(in1, in2));
vst1q_u8(dst+x, veorq_u8(vcombine_u8(t1, t2), mask));
}
#endif
for( ; x < size.width; x++ )
dst[x] = (uchar)(-(src1[x] == src2[x]) ^ m);
@ -3085,7 +3159,7 @@ namespace cv
{
template <typename T>
struct InRange_SSE
struct InRange_SIMD
{
int operator () (const T *, const T *, const T *, uchar *, int) const
{
@ -3096,7 +3170,7 @@ struct InRange_SSE
#if CV_SSE2
template <>
struct InRange_SSE<uchar>
struct InRange_SIMD<uchar>
{
int operator () (const uchar * src1, const uchar * src2, const uchar * src3,
uchar * dst, int len) const
@ -3121,7 +3195,7 @@ struct InRange_SSE<uchar>
};
template <>
struct InRange_SSE<schar>
struct InRange_SIMD<schar>
{
int operator () (const schar * src1, const schar * src2, const schar * src3,
uchar * dst, int len) const
@ -3146,7 +3220,7 @@ struct InRange_SSE<schar>
};
template <>
struct InRange_SSE<ushort>
struct InRange_SIMD<ushort>
{
int operator () (const ushort * src1, const ushort * src2, const ushort * src3,
uchar * dst, int len) const
@ -3172,7 +3246,7 @@ struct InRange_SSE<ushort>
};
template <>
struct InRange_SSE<short>
struct InRange_SIMD<short>
{
int operator () (const short * src1, const short * src2, const short * src3,
uchar * dst, int len) const
@ -3198,7 +3272,7 @@ struct InRange_SSE<short>
};
template <>
struct InRange_SSE<int>
struct InRange_SIMD<int>
{
int operator () (const int * src1, const int * src2, const int * src3,
uchar * dst, int len) const
@ -3230,7 +3304,7 @@ struct InRange_SSE<int>
};
template <>
struct InRange_SSE<float>
struct InRange_SIMD<float>
{
int operator () (const float * src1, const float * src2, const float * src3,
uchar * dst, int len) const
@ -3261,6 +3335,160 @@ struct InRange_SSE<float>
}
};
#elif CV_NEON
template <>
struct InRange_SIMD<uchar>
{
int operator () (const uchar * src1, const uchar * src2, const uchar * src3,
uchar * dst, int len) const
{
int x = 0;
for ( ; x <= len - 16; x += 16 )
{
uint8x16_t values = vld1q_u8(src1 + x);
uint8x16_t low = vld1q_u8(src2 + x);
uint8x16_t high = vld1q_u8(src3 + x);
vst1q_u8(dst + x, vandq_u8(vcgeq_u8(values, low), vcgeq_u8(high, values)));
}
return x;
}
};
template <>
struct InRange_SIMD<schar>
{
int operator () (const schar * src1, const schar * src2, const schar * src3,
uchar * dst, int len) const
{
int x = 0;
for ( ; x <= len - 16; x += 16 )
{
int8x16_t values = vld1q_s8(src1 + x);
int8x16_t low = vld1q_s8(src2 + x);
int8x16_t high = vld1q_s8(src3 + x);
vst1q_u8(dst + x, vandq_u8(vcgeq_s8(values, low), vcgeq_s8(high, values)));
}
return x;
}
};
template <>
struct InRange_SIMD<ushort>
{
int operator () (const ushort * src1, const ushort * src2, const ushort * src3,
uchar * dst, int len) const
{
int x = 0;
for ( ; x <= len - 16; x += 16 )
{
uint16x8_t values = vld1q_u16((const uint16_t*)(src1 + x));
uint16x8_t low = vld1q_u16((const uint16_t*)(src2 + x));
uint16x8_t high = vld1q_u16((const uint16_t*)(src3 + x));
uint8x8_t r1 = vmovn_u16(vandq_u16(vcgeq_u16(values, low), vcgeq_u16(high, values)));
values = vld1q_u16((const uint16_t*)(src1 + x + 8));
low = vld1q_u16((const uint16_t*)(src2 + x + 8));
high = vld1q_u16((const uint16_t*)(src3 + x + 8));
uint8x8_t r2 = vmovn_u16(vandq_u16(vcgeq_u16(values, low), vcgeq_u16(high, values)));
vst1q_u8(dst + x, vcombine_u8(r1, r2));
}
return x;
}
};
template <>
struct InRange_SIMD<short>
{
int operator () (const short * src1, const short * src2, const short * src3,
uchar * dst, int len) const
{
int x = 0;
for ( ; x <= len - 16; x += 16 )
{
int16x8_t values = vld1q_s16((const int16_t*)(src1 + x));
int16x8_t low = vld1q_s16((const int16_t*)(src2 + x));
int16x8_t high = vld1q_s16((const int16_t*)(src3 + x));
uint8x8_t r1 = vmovn_u16(vandq_u16(vcgeq_s16(values, low), vcgeq_s16(high, values)));
values = vld1q_s16((const int16_t*)(src1 + x + 8));
low = vld1q_s16((const int16_t*)(src2 + x + 8));
high = vld1q_s16((const int16_t*)(src3 + x + 8));
uint8x8_t r2 = vmovn_u16(vandq_u16(vcgeq_s16(values, low), vcgeq_s16(high, values)));
vst1q_u8(dst + x, vcombine_u8(r1, r2));
}
return x;
}
};
template <>
struct InRange_SIMD<int>
{
int operator () (const int * src1, const int * src2, const int * src3,
uchar * dst, int len) const
{
int x = 0;
for ( ; x <= len - 8; x += 8 )
{
int32x4_t values = vld1q_s32((const int32_t*)(src1 + x));
int32x4_t low = vld1q_s32((const int32_t*)(src2 + x));
int32x4_t high = vld1q_s32((const int32_t*)(src3 + x));
uint16x4_t r1 = vmovn_u32(vandq_u32(vcgeq_s32(values, low), vcgeq_s32(high, values)));
values = vld1q_s32((const int32_t*)(src1 + x + 4));
low = vld1q_s32((const int32_t*)(src2 + x + 4));
high = vld1q_s32((const int32_t*)(src3 + x + 4));
uint16x4_t r2 = vmovn_u32(vandq_u32(vcgeq_s32(values, low), vcgeq_s32(high, values)));
uint16x8_t res_16 = vcombine_u16(r1, r2);
vst1_u8(dst + x, vmovn_u16(res_16));
}
return x;
}
};
template <>
struct InRange_SIMD<float>
{
int operator () (const float * src1, const float * src2, const float * src3,
uchar * dst, int len) const
{
int x = 0;
for ( ; x <= len - 8; x += 8 )
{
float32x4_t values = vld1q_f32((const float32_t*)(src1 + x));
float32x4_t low = vld1q_f32((const float32_t*)(src2 + x));
float32x4_t high = vld1q_f32((const float32_t*)(src3 + x));
uint16x4_t r1 = vmovn_u32(vandq_u32(vcgeq_f32(values, low), vcgeq_f32(high, values)));
values = vld1q_f32((const float32_t*)(src1 + x + 4));
low = vld1q_f32((const float32_t*)(src2 + x + 4));
high = vld1q_f32((const float32_t*)(src3 + x + 4));
uint16x4_t r2 = vmovn_u32(vandq_u32(vcgeq_f32(values, low), vcgeq_f32(high, values)));
uint16x8_t res_16 = vcombine_u16(r1, r2);
vst1_u8(dst + x, vmovn_u16(res_16));
}
return x;
}
};
#endif
template <typename T>
@ -3272,7 +3500,7 @@ static void inRange_(const T* src1, size_t step1, const T* src2, size_t step2,
step2 /= sizeof(src2[0]);
step3 /= sizeof(src3[0]);
InRange_SSE<T> vop;
InRange_SIMD<T> vop;
for( ; size.height--; src1 += step1, src2 += step2, src3 += step3, dst += step )
{

@ -1619,7 +1619,7 @@ DEF_CVT_FUNC_F(8u16s, uchar, short, 8u16s_C1R)
DEF_CVT_FUNC_F(8s16s, schar, short, 8s16s_C1R)
DEF_CVT_FUNC_F2(16u16s, ushort, short, 16u16s_C1RSfs)
DEF_CVT_FUNC_F2(32s16s, int, short, 32s16s_C1RSfs)
DEF_CVT_FUNC_F2(32f16s, float, short, 32f16s_C1RSfs)
DEF_CVT_FUNC(32f16s, float, short)
DEF_CVT_FUNC(64f16s, double, short)
DEF_CVT_FUNC_F(8u32s, uchar, int, 8u32s_C1R)
@ -1948,7 +1948,7 @@ static bool ocl_LUT(InputArray _src, InputArray _lut, OutputArray _dst)
UMat src = _src.getUMat(), lut = _lut.getUMat();
_dst.create(src.size(), CV_MAKETYPE(ddepth, dcn));
UMat dst = _dst.getUMat();
int kercn = lcn == 1 ? std::min(4, ocl::predictOptimalVectorWidth(_dst)) : dcn;
int kercn = lcn == 1 ? std::min(4, ocl::predictOptimalVectorWidth(_src, _dst)) : dcn;
ocl::Kernel k("LUT", ocl::core::lut_oclsrc,
format("-D dcn=%d -D lcn=%d -D srcT=%s -D dstT=%s", kercn, lcn,

@ -1801,11 +1801,11 @@ private:
UMat twiddles;
String buildOptions;
int thread_count;
bool status;
int dft_size;
bool status;
public:
OCL_FftPlan(int _size): dft_size(_size), status(true)
OCL_FftPlan(int _size) : dft_size(_size), status(true)
{
int min_radix;
std::vector<int> radixes, blocks;
@ -2635,8 +2635,8 @@ void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
for( i = 0; i < nonzero_rows; i++ )
{
uchar* sptr = src.data + i*src.step;
uchar* dptr0 = dst.data + i*dst.step;
const uchar* sptr = src.ptr(i);
uchar* dptr0 = dst.ptr(i);
uchar* dptr = dptr0;
if( tmp_buf )
@ -2649,7 +2649,7 @@ void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
for( ; i < count; i++ )
{
uchar* dptr0 = dst.data + i*dst.step;
uchar* dptr0 = dst.ptr(i);
memset( dptr0, 0, dst_full_len );
}
@ -2661,7 +2661,7 @@ void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
{
int a = 0, b = count;
uchar *buf0, *buf1, *dbuf0, *dbuf1;
uchar* sptr0 = src.data;
const uchar* sptr0 = src.data;
uchar* dptr0 = dst.data;
buf0 = ptr;
ptr += len*complex_elem_size;
@ -2800,7 +2800,7 @@ void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
int n = dst.cols;
if( elem_size == (int)sizeof(float) )
{
float* p0 = (float*)dst.data;
float* p0 = dst.ptr<float>();
size_t dstep = dst.step/sizeof(p0[0]);
for( i = 0; i < len; i++ )
{
@ -2816,7 +2816,7 @@ void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
}
else
{
double* p0 = (double*)dst.data;
double* p0 = dst.ptr<double>();
size_t dstep = dst.step/sizeof(p0[0]);
for( i = 0; i < len; i++ )
{

@ -955,10 +955,10 @@ double cv::invert( InputArray _src, OutputArray _dst, int method )
SVD::compute(src, w, u, vt);
SVD::backSubst(w, u, vt, Mat(), _dst);
return type == CV_32F ?
(((float*)w.data)[0] >= FLT_EPSILON ?
((float*)w.data)[n-1]/((float*)w.data)[0] : 0) :
(((double*)w.data)[0] >= DBL_EPSILON ?
((double*)w.data)[n-1]/((double*)w.data)[0] : 0);
(w.ptr<float>()[0] >= FLT_EPSILON ?
w.ptr<float>()[n-1]/w.ptr<float>()[0] : 0) :
(w.ptr<double>()[0] >= DBL_EPSILON ?
w.ptr<double>()[n-1]/w.ptr<double>()[0] : 0);
}
CV_Assert( m == n );
@ -975,10 +975,10 @@ double cv::invert( InputArray _src, OutputArray _dst, int method )
transpose(vt, u);
SVD::backSubst(w, u, vt, Mat(), _dst);
return type == CV_32F ?
(((float*)w.data)[0] >= FLT_EPSILON ?
((float*)w.data)[n-1]/((float*)w.data)[0] : 0) :
(((double*)w.data)[0] >= DBL_EPSILON ?
((double*)w.data)[n-1]/((double*)w.data)[0] : 0);
(w.ptr<float>()[0] >= FLT_EPSILON ?
w.ptr<float>()[n-1]/w.ptr<float>()[0] : 0) :
(w.ptr<double>()[0] >= DBL_EPSILON ?
w.ptr<double>()[n-1]/w.ptr<double>()[0] : 0);
}
CV_Assert( method == DECOMP_LU || method == DECOMP_CHOLESKY );
@ -988,7 +988,7 @@ double cv::invert( InputArray _src, OutputArray _dst, int method )
if( n <= 3 )
{
uchar* srcdata = src.data;
const uchar* srcdata = src.data;
uchar* dstdata = dst.data;
size_t srcstep = src.step;
size_t dststep = dst.step;
@ -1212,8 +1212,8 @@ bool cv::solve( InputArray _src, InputArray _src2arg, OutputArray _dst, int meth
#define bf(y) ((float*)(bdata + y*src2step))[0]
#define bd(y) ((double*)(bdata + y*src2step))[0]
uchar* srcdata = src.data;
uchar* bdata = _src2.data;
const uchar* srcdata = src.data;
const uchar* bdata = _src2.data;
uchar* dstdata = dst.data;
size_t srcstep = src.step;
size_t src2step = _src2.step;
@ -1709,7 +1709,7 @@ cvEigenVV( CvArr* srcarr, CvArr* evectsarr, CvArr* evalsarr, double,
eigen(src, evals, evects);
if( evects0.data != evects.data )
{
uchar* p = evects0.data;
const uchar* p = evects0.data;
evects.convertTo(evects0, evects0.type());
CV_Assert( p == evects0.data );
}
@ -1718,7 +1718,7 @@ cvEigenVV( CvArr* srcarr, CvArr* evectsarr, CvArr* evalsarr, double,
eigen(src, evals);
if( evals0.data != evals.data )
{
uchar* p = evals0.data;
const uchar* p = evals0.data;
if( evals0.size() == evals.size() )
evals.convertTo(evals0, evals0.type());
else if( evals0.type() == evals.type() )

File diff suppressed because it is too large Load Diff

@ -3295,7 +3295,6 @@ void cv::PCABackProject(InputArray data, InputArray mean,
pca.backProject(data, result);
}
/****************************************************************************************\
* Earlier API *
\****************************************************************************************/

@ -346,7 +346,7 @@ static void finalizeHdr(Mat& m)
if( d > 2 )
m.rows = m.cols = -1;
if(m.u)
m.data = m.datastart = m.u->data;
m.datastart = m.data = m.u->data;
if( m.data )
{
m.datalimit = m.datastart + m.size[0]*m.step[0];
@ -510,7 +510,7 @@ Mat::Mat(int _dims, const int* _sizes, int _type, void* _data, const size_t* _st
datalimit(0), allocator(0), u(0), size(&rows)
{
flags |= CV_MAT_TYPE(_type);
data = datastart = (uchar*)_data;
datastart = data = (uchar*)_data;
setSize(*this, _dims, _sizes, _steps, true);
finalizeHdr(*this);
}
@ -549,7 +549,7 @@ static Mat cvMatNDToMat(const CvMatND* m, bool copyData)
if( !m )
return thiz;
thiz.data = thiz.datastart = m->data.ptr;
thiz.datastart = thiz.data = m->data.ptr;
thiz.flags |= CV_MAT_TYPE(m->type);
int _sizes[CV_MAX_DIM];
size_t _steps[CV_MAX_DIM];
@ -587,7 +587,7 @@ static Mat cvMatToMat(const CvMat* m, bool copyData)
thiz.dims = 2;
thiz.rows = m->rows;
thiz.cols = m->cols;
thiz.data = thiz.datastart = m->data.ptr;
thiz.datastart = thiz.data = m->data.ptr;
size_t esz = CV_ELEM_SIZE(m->type), minstep = thiz.cols*esz, _step = m->step;
if( _step == 0 )
_step = minstep;
@ -597,7 +597,7 @@ static Mat cvMatToMat(const CvMat* m, bool copyData)
}
else
{
thiz.data = thiz.datastart = thiz.dataend = 0;
thiz.datastart = thiz.dataend = thiz.data = 0;
Mat(m->rows, m->cols, m->type, m->data.ptr, m->step).copyTo(thiz);
}
@ -636,7 +636,7 @@ static Mat iplImageToMat(const IplImage* img, bool copyData)
m.rows = img->roi->height;
m.cols = img->roi->width;
esz = CV_ELEM_SIZE(m.flags);
m.data = m.datastart = (uchar*)img->imageData +
m.datastart = m.data = (uchar*)img->imageData +
(selectedPlane ? (img->roi->coi - 1)*m.step*img->height : 0) +
img->roi->yOffset*m.step[0] + img->roi->xOffset*esz;
}
@ -2758,15 +2758,18 @@ namespace cv {
static bool ocl_setIdentity( InputOutputArray _m, const Scalar& s )
{
int type = _m.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type), kercn = cn;
if (cn == 1)
int type = _m.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type), kercn = cn, rowsPerWI = 1;
int sctype = CV_MAKE_TYPE(depth, cn == 3 ? 4 : cn);
if (ocl::Device::getDefault().isIntel())
{
kercn = std::min(ocl::predictOptimalVectorWidth(_m), 4);
if (kercn != 4)
kercn = 1;
rowsPerWI = 4;
if (cn == 1)
{
kercn = std::min(ocl::predictOptimalVectorWidth(_m), 4);
if (kercn != 4)
kercn = 1;
}
}
int sctype = CV_MAKE_TYPE(depth, cn == 3 ? 4 : cn),
rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1;
ocl::Kernel k("setIdentity", ocl::core::set_identity_oclsrc,
format("-D T=%s -D T1=%s -D cn=%d -D ST=%s -D kercn=%d -D rowsPerWI=%d",
@ -5529,14 +5532,14 @@ double norm( const SparseMat& src, int normType )
{
if( normType == NORM_INF )
for( i = 0; i < N; i++, ++it )
result = std::max(result, std::abs((double)*(const float*)it.ptr));
result = std::max(result, std::abs((double)it.value<float>()));
else if( normType == NORM_L1 )
for( i = 0; i < N; i++, ++it )
result += std::abs(*(const float*)it.ptr);
result += std::abs(it.value<float>());
else
for( i = 0; i < N; i++, ++it )
{
double v = *(const float*)it.ptr;
double v = it.value<float>();
result += v*v;
}
}
@ -5544,14 +5547,14 @@ double norm( const SparseMat& src, int normType )
{
if( normType == NORM_INF )
for( i = 0; i < N; i++, ++it )
result = std::max(result, std::abs(*(const double*)it.ptr));
result = std::max(result, std::abs(it.value<double>()));
else if( normType == NORM_L1 )
for( i = 0; i < N; i++, ++it )
result += std::abs(*(const double*)it.ptr);
result += std::abs(it.value<double>());
else
for( i = 0; i < N; i++, ++it )
{
double v = *(const double*)it.ptr;
double v = it.value<double>();
result += v*v;
}
}
@ -5575,7 +5578,7 @@ void minMaxLoc( const SparseMat& src, double* _minval, double* _maxval, int* _mi
float minval = FLT_MAX, maxval = -FLT_MAX;
for( i = 0; i < N; i++, ++it )
{
float v = *(const float*)it.ptr;
float v = it.value<float>();
if( v < minval )
{
minval = v;
@ -5597,7 +5600,7 @@ void minMaxLoc( const SparseMat& src, double* _minval, double* _maxval, int* _mi
double minval = DBL_MAX, maxval = -DBL_MAX;
for( i = 0; i < N; i++, ++it )
{
double v = *(const double*)it.ptr;
double v = it.value<double>();
if( v < minval )
{
minval = v;

@ -1324,6 +1324,9 @@ OCL_FUNC(cl_int, clReleaseEvent, (cl_event event), (event))
#endif
#ifdef _DEBUG
#define CV_OclDbgAssert CV_DbgAssert
#else
static bool isRaiseError()
{
static bool initialized = false;
@ -1335,10 +1338,6 @@ static bool isRaiseError()
}
return value;
}
#ifdef _DEBUG
#define CV_OclDbgAssert CV_DbgAssert
#else
#define CV_OclDbgAssert(expr) do { if (isRaiseError()) { CV_Assert(expr); } else { (void)(expr); } } while ((void)0, 0)
#endif

@ -424,7 +424,7 @@ void fft_radix3_B3(__local float2* smem, __global const float2* twiddles, const
const int x3 = x2 + t/3;
float2 a0, a1, a2, a3, a4, a5, a6, a7, a8;
if (x1 < t/2)
if (x1 < t/3)
{
a0 = smem[x1]; a1 = smem[x1+t]; a2 = smem[x1+2*t];
a3 = smem[x2]; a4 = smem[x2+t]; a5 = smem[x2+2*t];
@ -433,7 +433,7 @@ void fft_radix3_B3(__local float2* smem, __global const float2* twiddles, const
barrier(CLK_LOCAL_MEM_FENCE);
if (x1 < t/2)
if (x1 < t/3)
{
butterfly3(a0, a1, a2, smem, twiddles, x1, block_size);
butterfly3(a3, a4, a5, smem, twiddles, x2, block_size);

@ -185,7 +185,7 @@ __kernel void minmaxloc(__global const uchar * srcptr, int src_step, int src_off
#endif
{
#ifdef HAVE_SRC_CONT
src_index = mul24(id, srcTSIZE);
src_index = id * srcTSIZE;//mul24(id, srcTSIZE);
#else
src_index = mad24(id / cols, src_step, mul24(id % cols, srcTSIZE));
#endif

@ -782,7 +782,7 @@ cv::Scalar cv::mean( InputArray _src, InputArray _mask )
int type = src.type();
if( !mask.empty() )
{
typedef IppStatus (CV_STDCALL* ippiMaskMeanFuncC1)(const void *, int, void *, int, IppiSize, Ipp64f *);
typedef IppStatus (CV_STDCALL* ippiMaskMeanFuncC1)(const void *, int, const void *, int, IppiSize, Ipp64f *);
ippiMaskMeanFuncC1 ippFuncC1 =
type == CV_8UC1 ? (ippiMaskMeanFuncC1)ippiMean_8u_C1MR :
type == CV_16UC1 ? (ippiMaskMeanFuncC1)ippiMean_16u_C1MR :
@ -795,7 +795,7 @@ cv::Scalar cv::mean( InputArray _src, InputArray _mask )
return Scalar(res);
setIppErrorStatus();
}
typedef IppStatus (CV_STDCALL* ippiMaskMeanFuncC3)(const void *, int, void *, int, IppiSize, int, Ipp64f *);
typedef IppStatus (CV_STDCALL* ippiMaskMeanFuncC3)(const void *, int, const void *, int, IppiSize, int, Ipp64f *);
ippiMaskMeanFuncC3 ippFuncC3 =
type == CV_8UC3 ? (ippiMaskMeanFuncC3)ippiMean_8u_C3CMR :
type == CV_16UC3 ? (ippiMaskMeanFuncC3)ippiMean_16u_C3CMR :
@ -1071,7 +1071,7 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input
int type = src.type();
if( !mask.empty() )
{
typedef IppStatus (CV_STDCALL* ippiMaskMeanStdDevFuncC1)(const void *, int, void *, int, IppiSize, Ipp64f *, Ipp64f *);
typedef IppStatus (CV_STDCALL* ippiMaskMeanStdDevFuncC1)(const void *, int, const void *, int, IppiSize, Ipp64f *, Ipp64f *);
ippiMaskMeanStdDevFuncC1 ippFuncC1 =
type == CV_8UC1 ? (ippiMaskMeanStdDevFuncC1)ippiMean_StdDev_8u_C1MR :
type == CV_16UC1 ? (ippiMaskMeanStdDevFuncC1)ippiMean_StdDev_16u_C1MR :
@ -1083,7 +1083,7 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input
return;
setIppErrorStatus();
}
typedef IppStatus (CV_STDCALL* ippiMaskMeanStdDevFuncC3)(const void *, int, void *, int, IppiSize, int, Ipp64f *, Ipp64f *);
typedef IppStatus (CV_STDCALL* ippiMaskMeanStdDevFuncC3)(const void *, int, const void *, int, IppiSize, int, Ipp64f *, Ipp64f *);
ippiMaskMeanStdDevFuncC3 ippFuncC3 =
type == CV_8UC3 ? (ippiMaskMeanStdDevFuncC3)ippiMean_StdDev_8u_C3CMR :
type == CV_16UC3 ? (ippiMaskMeanStdDevFuncC3)ippiMean_StdDev_16u_C3CMR :
@ -1454,7 +1454,7 @@ static bool ocl_minMaxIdx( InputArray _src, double* minVal, double* maxVal, int*
CV_Assert(!haveSrc2 || _src2.type() == type);
if (depth == CV_32S || depth == CV_32F)
if (depth == CV_32S)
return false;
if ((depth == CV_64F || ddepth == CV_64F) && !doubleSupport)

@ -582,7 +582,7 @@ Mat UMat::getMat(int accessFlags) const
hdr.flags = flags;
hdr.u = u;
hdr.datastart = u->data;
hdr.data = hdr.datastart + offset;
hdr.data = u->data + offset;
hdr.datalimit = hdr.dataend = u->data + u->size;
CV_XADD(&hdr.u->refcount, 1);
return hdr;
@ -593,15 +593,16 @@ void* UMat::handle(int accessFlags) const
if( !u )
return 0;
if ((accessFlags & ACCESS_WRITE) != 0)
u->markHostCopyObsolete(true);
// check flags: if CPU copy is newer, copy it back to GPU.
if( u->deviceCopyObsolete() )
{
CV_Assert(u->refcount == 0);
u->currAllocator->unmap(u);
}
if ((accessFlags & ACCESS_WRITE) != 0)
u->markHostCopyObsolete(true);
return u->handle;
}

@ -108,7 +108,7 @@ OCL_TEST_P(Dft, Mat)
{
generateTestData();
int nonzero_rows = hint ? src.cols - randomInt(1, src.rows-1) : 0;
int nonzero_rows = hint ? src.rows - randomInt(1, src.rows-1) : 0;
OCL_OFF(cv::dft(src, dst, dft_flags, nonzero_rows));
OCL_ON(cv::dft(usrc, udst, dft_flags, nonzero_rows));
@ -175,7 +175,7 @@ OCL_TEST_P(MulSpectrums, Mat)
OCL_INSTANTIATE_TEST_CASE_P(OCL_ImgProc, MulSpectrums, testing::Combine(Bool(), Bool()));
OCL_INSTANTIATE_TEST_CASE_P(Core, Dft, Combine(Values(cv::Size(10, 10), cv::Size(36, 36), cv::Size(512, 1), cv::Size(1280, 768)),
OCL_INSTANTIATE_TEST_CASE_P(Core, Dft, Combine(Values(cv::Size(45, 72), cv::Size(36, 36), cv::Size(512, 1), cv::Size(1280, 768)),
Values((OCL_FFT_TYPE) R2C, (OCL_FFT_TYPE) C2C, (OCL_FFT_TYPE) R2R, (OCL_FFT_TYPE) C2R),
Bool(), // DFT_INVERSE
Bool(), // DFT_ROWS

@ -649,6 +649,16 @@ static void setValue(SparseMat& M, const int* idx, double value, RNG& rng)
CV_Error(CV_StsUnsupportedFormat, "");
}
template<typename Pixel>
struct InitializerFunctor{
/// Initializer for cv::Mat::forEach test
void operator()(Pixel & pixel, const int * idx) const {
pixel.x = idx[0];
pixel.y = idx[1];
pixel.z = idx[2];
}
};
void Core_ArrayOpTest::run( int /* start_from */)
{
int errcount = 0;
@ -686,6 +696,45 @@ void Core_ArrayOpTest::run( int /* start_from */)
errcount++;
}
}
// test cv::Mat::forEach
{
const int dims[3] = { 101, 107, 7 };
typedef cv::Point3i Pixel;
cv::Mat a = cv::Mat::zeros(3, dims, CV_32SC3);
InitializerFunctor<Pixel> initializer;
a.forEach<Pixel>(initializer);
uint64 total = 0;
bool error_reported = false;
for (int i0 = 0; i0 < dims[0]; ++i0) {
for (int i1 = 0; i1 < dims[1]; ++i1) {
for (int i2 = 0; i2 < dims[2]; ++i2) {
Pixel& pixel = a.at<Pixel>(i0, i1, i2);
if (pixel.x != i0 || pixel.y != i1 || pixel.z != i2) {
if (!error_reported) {
ts->printf(cvtest::TS::LOG, "forEach is not correct.\n"
"First error detected at (%d, %d, %d).\n", pixel.x, pixel.y, pixel.z);
error_reported = true;
}
errcount++;
}
total += pixel.x;
total += pixel.y;
total += pixel.z;
}
}
}
uint64 total2 = 0;
for (size_t i = 0; i < sizeof(dims) / sizeof(dims[0]); ++i) {
total2 += ((dims[i] - 1) * dims[i] / 2) * dims[0] * dims[1] * dims[2] / dims[i];
}
if (total != total2) {
ts->printf(cvtest::TS::LOG, "forEach is not correct because total is invalid.\n");
errcount++;
}
}
RNG rng;
const int MAX_DIM = 5, MAX_DIM_SZ = 10;

@ -745,6 +745,24 @@ TEST(UMat, Sync)
EXPECT_EQ(0, cvtest::norm(um.getMat(ACCESS_READ), cv::Mat(um.size(), um.type(), 19), NORM_INF));
}
TEST(UMat, CopyToIfDeviceCopyIsObsolete)
{
UMat um(7, 2, CV_8UC1);
Mat m(um.size(), um.type());
m.setTo(Scalar::all(0));
{
// make obsolete device copy of UMat
Mat temp = um.getMat(ACCESS_WRITE);
temp.setTo(Scalar::all(10));
}
m.copyTo(um);
um.setTo(Scalar::all(17));
EXPECT_EQ(0, cvtest::norm(um.getMat(ACCESS_READ), Mat(um.size(), um.type(), 17), NORM_INF));
}
TEST(UMat, setOpenCL)
{
// save the current state

@ -84,38 +84,5 @@ Creates a descriptor extractor by name.
The current implementation supports the following types of a descriptor extractor:
* ``"SIFT"`` -- :ocv:class:`SIFT`
* ``"SURF"`` -- :ocv:class:`SURF`
* ``"BRIEF"`` -- :ocv:class:`BriefDescriptorExtractor`
* ``"BRISK"`` -- :ocv:class:`BRISK`
* ``"ORB"`` -- :ocv:class:`ORB`
* ``"FREAK"`` -- :ocv:class:`FREAK`
A combined format is also supported: descriptor extractor adapter name ( ``"Opponent"`` --
:ocv:class:`OpponentColorDescriptorExtractor` ) + descriptor extractor name (see above),
for example: ``"OpponentSIFT"`` .
OpponentColorDescriptorExtractor
--------------------------------
.. ocv:class:: OpponentColorDescriptorExtractor : public DescriptorExtractor
Class adapting a descriptor extractor to compute descriptors in the Opponent Color Space
(refer to Van de Sande et al., CGIV 2008 *Color Descriptors for Object Category Recognition*).
Input RGB image is transformed in the Opponent Color Space. Then, an unadapted descriptor extractor
(set in the constructor) computes descriptors on each of three channels and concatenates
them into a single color descriptor. ::
class OpponentColorDescriptorExtractor : public DescriptorExtractor
{
public:
OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& dextractor );
virtual void read( const FileNode& );
virtual void write( FileStorage& ) const;
virtual int descriptorSize() const;
virtual int descriptorType() const;
virtual int defaultNorm() const;
protected:
...
};
* ``"ORB"`` -- :ocv:class:`ORB`

@ -72,22 +72,13 @@ Creates a feature detector by its name.
The following detector types are supported:
* ``"FAST"`` -- :ocv:class:`FastFeatureDetector`
* ``"STAR"`` -- :ocv:class:`StarFeatureDetector`
* ``"SIFT"`` -- :ocv:class:`SIFT` (nonfree module)
* ``"SURF"`` -- :ocv:class:`SURF` (nonfree module)
* ``"ORB"`` -- :ocv:class:`ORB`
* ``"BRISK"`` -- :ocv:class:`BRISK`
* ``"MSER"`` -- :ocv:class:`MSER`
* ``"GFTT"`` -- :ocv:class:`GoodFeaturesToTrackDetector`
* ``"HARRIS"`` -- :ocv:class:`GoodFeaturesToTrackDetector` with Harris detector enabled
* ``"Dense"`` -- :ocv:class:`DenseFeatureDetector`
* ``"SimpleBlob"`` -- :ocv:class:`SimpleBlobDetector`
Also a combined format is supported: feature detector adapter name ( ``"Grid"`` --
:ocv:class:`GridAdaptedFeatureDetector`, ``"Pyramid"`` --
:ocv:class:`PyramidAdaptedFeatureDetector` ) + feature detector name (see above),
for example: ``"GridFAST"``, ``"PyramidSTAR"`` .
FastFeatureDetector
-------------------
.. ocv:class:: FastFeatureDetector : public FeatureDetector
@ -164,55 +155,6 @@ Wrapping class for feature detection using the
...
};
StarFeatureDetector
-------------------
.. ocv:class:: StarFeatureDetector : public FeatureDetector
The class implements the keypoint detector introduced by [Agrawal08]_, synonym of ``StarDetector``. ::
class StarFeatureDetector : public FeatureDetector
{
public:
StarFeatureDetector( int maxSize=16, int responseThreshold=30,
int lineThresholdProjected = 10,
int lineThresholdBinarized=8, int suppressNonmaxSize=5 );
virtual void read( const FileNode& fn );
virtual void write( FileStorage& fs ) const;
protected:
...
};
.. [Agrawal08] Agrawal, M., Konolige, K., & Blas, M. R. (2008). Censure: Center surround extremas for realtime feature detection and matching. In Computer Vision–ECCV 2008 (pp. 102-115). Springer Berlin Heidelberg.
DenseFeatureDetector
--------------------
.. ocv:class:: DenseFeatureDetector : public FeatureDetector
Class for generation of image features which are distributed densely and regularly over the image. ::
class DenseFeatureDetector : public FeatureDetector
{
public:
DenseFeatureDetector( float initFeatureScale=1.f, int featureScaleLevels=1,
float featureScaleMul=0.1f,
int initXyStep=6, int initImgBound=0,
bool varyXyStepWithScale=true,
bool varyImgBoundWithScale=false );
protected:
...
};
The detector generates several levels (in the amount of ``featureScaleLevels``) of features. Features of each level are located in the nodes of a regular grid over the image (excluding the image boundary of given size). The level parameters (a feature scale, a node size, a size of boundary) are multiplied by ``featureScaleMul`` with level index growing depending on input flags, viz.:
* Feature scale is multiplied always.
* The grid node size is multiplied if ``varyXyStepWithScale`` is ``true``.
* Size of image boundary is multiplied if ``varyImgBoundWithScale`` is ``true``.
SimpleBlobDetector
-------------------
.. ocv:class:: SimpleBlobDetector : public FeatureDetector
@ -277,226 +219,3 @@ This class performs several filtrations of returned blobs. You should set ``filt
Default values of parameters are tuned to extract dark circular blobs.
GridAdaptedFeatureDetector
--------------------------
.. ocv:class:: GridAdaptedFeatureDetector : public FeatureDetector
Class adapting a detector to partition the source image into a grid and detect points in each cell. ::
class GridAdaptedFeatureDetector : public FeatureDetector
{
public:
/*
* detector Detector that will be adapted.
* maxTotalKeypoints Maximum count of keypoints detected on the image.
* Only the strongest keypoints will be kept.
* gridRows Grid row count.
* gridCols Grid column count.
*/
GridAdaptedFeatureDetector( const Ptr<FeatureDetector>& detector,
int maxTotalKeypoints, int gridRows=4,
int gridCols=4 );
virtual void read( const FileNode& fn );
virtual void write( FileStorage& fs ) const;
protected:
...
};
PyramidAdaptedFeatureDetector
-----------------------------
.. ocv:class:: PyramidAdaptedFeatureDetector : public FeatureDetector
Class adapting a detector to detect points over multiple levels of a Gaussian pyramid. Consider using this class for detectors that are not inherently scaled. ::
class PyramidAdaptedFeatureDetector : public FeatureDetector
{
public:
PyramidAdaptedFeatureDetector( const Ptr<FeatureDetector>& detector,
int levels=2 );
virtual void read( const FileNode& fn );
virtual void write( FileStorage& fs ) const;
protected:
...
};
DynamicAdaptedFeatureDetector
-----------------------------
.. ocv:class:: DynamicAdaptedFeatureDetector : public FeatureDetector
Adaptively adjusting detector that iteratively detects features until the desired number is found. ::
class DynamicAdaptedFeatureDetector: public FeatureDetector
{
public:
DynamicAdaptedFeatureDetector( const Ptr<AdjusterAdapter>& adjuster,
int min_features=400, int max_features=500, int max_iters=5 );
...
};
If the detector is persisted, it "remembers" the parameters
used for the last detection. In this case, the detector may be used for consistent numbers
of keypoints in a set of temporally related images, such as video streams or
panorama series.
``DynamicAdaptedFeatureDetector`` uses another detector, such as FAST or SURF, to do the dirty work,
with the help of ``AdjusterAdapter`` .
If the detected number of features is not large enough,
``AdjusterAdapter`` adjusts the detection parameters so that the next detection
results in a bigger or smaller number of features. This is repeated until either the number of desired features are found
or the parameters are maxed out.
Adapters can be easily implemented for any detector via the
``AdjusterAdapter`` interface.
Beware that this is not thread-safe since the adjustment of parameters requires modification of the feature detector class instance.
Example of creating ``DynamicAdaptedFeatureDetector`` : ::
//sample usage:
//will create a detector that attempts to find
//100 - 110 FAST Keypoints, and will at most run
//FAST feature detection 10 times until that
//number of keypoints are found
Ptr<FeatureDetector> detector(new DynamicAdaptedFeatureDetector (100, 110, 10,
new FastAdjuster(20,true)));
DynamicAdaptedFeatureDetector::DynamicAdaptedFeatureDetector
------------------------------------------------------------
The constructor
.. ocv:function:: DynamicAdaptedFeatureDetector::DynamicAdaptedFeatureDetector( const Ptr<AdjusterAdapter>& adjuster, int min_features=400, int max_features=500, int max_iters=5 )
:param adjuster: :ocv:class:`AdjusterAdapter` that detects features and adjusts parameters.
:param min_features: Minimum desired number of features.
:param max_features: Maximum desired number of features.
:param max_iters: Maximum number of times to try adjusting the feature detector parameters. For :ocv:class:`FastAdjuster` , this number can be high, but with ``Star`` or ``Surf`` many iterations can be time-consuming. At each iteration the detector is rerun.
AdjusterAdapter
---------------
.. ocv:class:: AdjusterAdapter : public FeatureDetector
Class providing an interface for adjusting parameters of a feature detector. This interface is used by :ocv:class:`DynamicAdaptedFeatureDetector` . It is a wrapper for :ocv:class:`FeatureDetector` that enables adjusting parameters after feature detection. ::
class AdjusterAdapter: public FeatureDetector
{
public:
virtual ~AdjusterAdapter() {}
virtual void tooFew(int min, int n_detected) = 0;
virtual void tooMany(int max, int n_detected) = 0;
virtual bool good() const = 0;
virtual Ptr<AdjusterAdapter> clone() const = 0;
static Ptr<AdjusterAdapter> create( const String& detectorType );
};
See
:ocv:class:`FastAdjuster`,
:ocv:class:`StarAdjuster`, and
:ocv:class:`SurfAdjuster` for concrete implementations.
AdjusterAdapter::tooFew
---------------------------
Adjusts the detector parameters to detect more features.
.. ocv:function:: void AdjusterAdapter::tooFew(int min, int n_detected)
:param min: Minimum desired number of features.
:param n_detected: Number of features detected during the latest run.
Example: ::
void FastAdjuster::tooFew(int min, int n_detected)
{
thresh_--;
}
AdjusterAdapter::tooMany
----------------------------
Adjusts the detector parameters to detect less features.
.. ocv:function:: void AdjusterAdapter::tooMany(int max, int n_detected)
:param max: Maximum desired number of features.
:param n_detected: Number of features detected during the latest run.
Example: ::
void FastAdjuster::tooMany(int min, int n_detected)
{
thresh_++;
}
AdjusterAdapter::good
---------------------
Returns false if the detector parameters cannot be adjusted any more.
.. ocv:function:: bool AdjusterAdapter::good() const
Example: ::
bool FastAdjuster::good() const
{
return (thresh_ > 1) && (thresh_ < 200);
}
AdjusterAdapter::create
-----------------------
Creates an adjuster adapter by name
.. ocv:function:: Ptr<AdjusterAdapter> AdjusterAdapter::create( const String& detectorType )
Creates an adjuster adapter by name ``detectorType``. The detector name is the same as in :ocv:func:`FeatureDetector::create`, but now supports ``"FAST"``, ``"STAR"``, and ``"SURF"`` only.
FastAdjuster
------------
.. ocv:class:: FastAdjuster : public AdjusterAdapter
:ocv:class:`AdjusterAdapter` for :ocv:class:`FastFeatureDetector`. This class decreases or increases the threshold value by 1. ::
class FastAdjuster FastAdjuster: public AdjusterAdapter
{
public:
FastAdjuster(int init_thresh = 20, bool nonmax = true);
...
};
StarAdjuster
------------
.. ocv:class:: StarAdjuster : public AdjusterAdapter
:ocv:class:`AdjusterAdapter` for :ocv:class:`StarFeatureDetector`. This class adjusts the ``responseThreshhold`` of ``StarFeatureDetector``. ::
class StarAdjuster: public AdjusterAdapter
{
StarAdjuster(double initial_thresh = 30.0);
...
};
SurfAdjuster
------------
.. ocv:class:: SurfAdjuster : public AdjusterAdapter
:ocv:class:`AdjusterAdapter` for ``SurfFeatureDetector``. ::
class CV_EXPORTS SurfAdjuster: public AdjusterAdapter
{
public:
SurfAdjuster( double initial_thresh=400.f, double min_thresh=2, double max_thresh=1000 );
virtual void tooFew(int minv, int n_detected);
virtual void tooMany(int maxv, int n_detected);
virtual bool good() const;
virtual Ptr<AdjusterAdapter> clone() const;
...
};

@ -1,276 +0,0 @@
Common Interfaces of Generic Descriptor Matchers
================================================
.. highlight:: cpp
Matchers of keypoint descriptors in OpenCV have wrappers with a common interface that enables you to easily switch
between different algorithms solving the same problem. This section is devoted to matching descriptors
that cannot be represented as vectors in a multidimensional space. ``GenericDescriptorMatcher`` is a more generic interface for descriptors. It does not make any assumptions about descriptor representation.
Every descriptor with the
:ocv:class:`DescriptorExtractor` interface has a wrapper with the ``GenericDescriptorMatcher`` interface (see
:ocv:class:`VectorDescriptorMatcher` ).
There are descriptors such as the One-way descriptor and Ferns that have the ``GenericDescriptorMatcher`` interface implemented but do not support ``DescriptorExtractor``.
.. note::
* An example explaining keypoint description can be found at opencv_source_code/samples/cpp/descriptor_extractor_matcher.cpp
* An example on descriptor matching evaluation can be found at opencv_source_code/samples/cpp/detector_descriptor_matcher_evaluation.cpp
* An example on one to many image matching can be found at opencv_source_code/samples/cpp/matching_to_many_images.cpp
GenericDescriptorMatcher
------------------------
.. ocv:class:: GenericDescriptorMatcher
Abstract interface for extracting and matching a keypoint descriptor. There are also :ocv:class:`DescriptorExtractor` and :ocv:class:`DescriptorMatcher` for these purposes but their interfaces are intended for descriptors represented as vectors in a multidimensional space. ``GenericDescriptorMatcher`` is a more generic interface for descriptors. ``DescriptorMatcher`` and ``GenericDescriptorMatcher`` have two groups of match methods: for matching keypoints of an image with another image or with an image set. ::
class GenericDescriptorMatcher
{
public:
GenericDescriptorMatcher();
virtual ~GenericDescriptorMatcher();
virtual void add( InputArrayOfArrays images,
vector<vector<KeyPoint> >& keypoints );
const vector<Mat>& getTrainImages() const;
const vector<vector<KeyPoint> >& getTrainKeypoints() const;
virtual void clear();
virtual void train() = 0;
virtual bool isMaskSupported() = 0;
void classify( InputArray queryImage,
vector<KeyPoint>& queryKeypoints,
InputArray trainImage,
vector<KeyPoint>& trainKeypoints ) const;
void classify( InputArray queryImage,
vector<KeyPoint>& queryKeypoints );
/*
* Group of methods to match keypoints from an image pair.
*/
void match( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
InputArray trainImage, vector<KeyPoint>& trainKeypoints,
vector<DMatch>& matches, InputArray mask=noArray() ) const;
void knnMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
InputArray trainImage, vector<KeyPoint>& trainKeypoints,
vector<vector<DMatch> >& matches, int k,
InputArray mask=noArray(), bool compactResult=false ) const;
void radiusMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
InputArray trainImage, vector<KeyPoint>& trainKeypoints,
vector<vector<DMatch> >& matches, float maxDistance,
InputArray mask=noArray(), bool compactResult=false ) const;
/*
* Group of methods to match keypoints from one image to an image set.
*/
void match( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
vector<DMatch>& matches, InputArrayOfArrays masks=noArray() );
void knnMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
vector<vector<DMatch> >& matches, int k,
InputArrayOfArrays masks=noArray(), bool compactResult=false );
void radiusMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints,
vector<vector<DMatch> >& matches, float maxDistance,
InputArrayOfArrays masks=noArray(), bool compactResult=false );
virtual void read( const FileNode& );
virtual void write( FileStorage& ) const;
virtual Ptr<GenericDescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
protected:
...
};
GenericDescriptorMatcher::add
---------------------------------
Adds images and their keypoints to the training collection stored in the class instance.
.. ocv:function:: void GenericDescriptorMatcher::add( InputArrayOfArrays images, vector<vector<KeyPoint> >& keypoints )
:param images: Image collection.
:param keypoints: Point collection. It is assumed that ``keypoints[i]`` are keypoints detected in the image ``images[i]`` .
GenericDescriptorMatcher::getTrainImages
--------------------------------------------
Returns a train image collection.
.. ocv:function:: const vector<Mat>& GenericDescriptorMatcher::getTrainImages() const
GenericDescriptorMatcher::getTrainKeypoints
-----------------------------------------------
Returns a train keypoints collection.
.. ocv:function:: const vector<vector<KeyPoint> >& GenericDescriptorMatcher::getTrainKeypoints() const
GenericDescriptorMatcher::clear
-----------------------------------
Clears a train collection (images and keypoints).
.. ocv:function:: void GenericDescriptorMatcher::clear()
GenericDescriptorMatcher::train
-----------------------------------
Trains descriptor matcher
.. ocv:function:: void GenericDescriptorMatcher::train()
Prepares descriptor matcher, for example, creates a tree-based structure, to extract descriptors or to optimize descriptors matching.
GenericDescriptorMatcher::isMaskSupported
---------------------------------------------
Returns ``true`` if a generic descriptor matcher supports masking permissible matches.
.. ocv:function:: bool GenericDescriptorMatcher::isMaskSupported()
GenericDescriptorMatcher::classify
--------------------------------------
Classifies keypoints from a query set.
.. ocv:function:: void GenericDescriptorMatcher::classify( InputArray queryImage, vector<KeyPoint>& queryKeypoints, InputArray trainImage, vector<KeyPoint>& trainKeypoints ) const
.. ocv:function:: void GenericDescriptorMatcher::classify( InputArray queryImage, vector<KeyPoint>& queryKeypoints )
:param queryImage: Query image.
:param queryKeypoints: Keypoints from a query image.
:param trainImage: Train image.
:param trainKeypoints: Keypoints from a train image.
The method classifies each keypoint from a query set. The first variant of the method takes a train image and its keypoints as an input argument. The second variant uses the internally stored training collection that can be built using the ``GenericDescriptorMatcher::add`` method.
The methods do the following:
#.
Call the ``GenericDescriptorMatcher::match`` method to find correspondence between the query set and the training set.
#.
Set the ``class_id`` field of each keypoint from the query set to ``class_id`` of the corresponding keypoint from the training set.
GenericDescriptorMatcher::match
-----------------------------------
Finds the best match in the training set for each keypoint from the query set.
.. ocv:function:: void GenericDescriptorMatcher::match(InputArray queryImage, vector<KeyPoint>& queryKeypoints, InputArray trainImage, vector<KeyPoint>& trainKeypoints, vector<DMatch>& matches, InputArray mask=noArray() ) const
.. ocv:function:: void GenericDescriptorMatcher::match( InputArray queryImage, vector<KeyPoint>& queryKeypoints, vector<DMatch>& matches, InputArrayOfArrays masks=noArray() )
:param queryImage: Query image.
:param queryKeypoints: Keypoints detected in ``queryImage`` .
:param trainImage: Train image. It is not added to a train image collection stored in the class object.
:param trainKeypoints: Keypoints detected in ``trainImage`` . They are not added to a train points collection stored in the class object.
:param matches: Matches. If a query descriptor (keypoint) is masked out in ``mask`` , match is added for this descriptor. So, ``matches`` size may be smaller than the query keypoints count.
:param mask: Mask specifying permissible matches between an input query and train keypoints.
:param masks: Set of masks. Each ``masks[i]`` specifies permissible matches between input query keypoints and stored train keypoints from the i-th image.
The methods find the best match for each query keypoint. In the first variant of the method, a train image and its keypoints are the input arguments. In the second variant, query keypoints are matched to the internally stored training collection that can be built using the ``GenericDescriptorMatcher::add`` method. Optional mask (or masks) can be passed to specify which query and training descriptors can be matched. Namely, ``queryKeypoints[i]`` can be matched with ``trainKeypoints[j]`` only if ``mask.at<uchar>(i,j)`` is non-zero.
GenericDescriptorMatcher::knnMatch
--------------------------------------
Finds the ``k`` best matches for each query keypoint.
.. ocv:function:: void GenericDescriptorMatcher::knnMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints, InputArray trainImage, vector<KeyPoint>& trainKeypoints, vector<vector<DMatch> >& matches, int k, InputArray mask=noArray(), bool compactResult=false ) const
.. ocv:function:: void GenericDescriptorMatcher::knnMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints, vector<vector<DMatch> >& matches, int k, InputArrayOfArrays masks=noArray(), bool compactResult=false )
The methods are extended variants of ``GenericDescriptorMatch::match``. The parameters are similar, and the semantics is similar to ``DescriptorMatcher::knnMatch``. But this class does not require explicitly computed keypoint descriptors.
GenericDescriptorMatcher::radiusMatch
-----------------------------------------
For each query keypoint, finds the training keypoints not farther than the specified distance.
.. ocv:function:: void GenericDescriptorMatcher::radiusMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints, InputArray trainImage, vector<KeyPoint>& trainKeypoints, vector<vector<DMatch> >& matches, float maxDistance, InputArray mask=noArray(), bool compactResult=false ) const
.. ocv:function:: void GenericDescriptorMatcher::radiusMatch( InputArray queryImage, vector<KeyPoint>& queryKeypoints, vector<vector<DMatch> >& matches, float maxDistance, InputArrayOfArrays masks=noArray(), bool compactResult=false )
The methods are similar to ``DescriptorMatcher::radius``. But this class does not require explicitly computed keypoint descriptors.
GenericDescriptorMatcher::read
----------------------------------
Reads a matcher object from a file node.
.. ocv:function:: void GenericDescriptorMatcher::read( const FileNode& fn )
GenericDescriptorMatcher::write
-----------------------------------
Writes a match object to a file storage.
.. ocv:function:: void GenericDescriptorMatcher::write( FileStorage& fs ) const
GenericDescriptorMatcher::clone
-----------------------------------
Clones the matcher.
.. ocv:function:: Ptr<GenericDescriptorMatcher> GenericDescriptorMatcher::clone( bool emptyTrainData=false ) const
:param emptyTrainData: If ``emptyTrainData`` is false, the method creates a deep copy of the object, that is, copies
both parameters and train data. If ``emptyTrainData`` is true, the method creates an object copy with the current parameters
but with empty train data.
VectorDescriptorMatcher
-----------------------
.. ocv:class:: VectorDescriptorMatcher : public GenericDescriptorMatcher
Class used for matching descriptors that can be described as vectors in a finite-dimensional space. ::
class CV_EXPORTS VectorDescriptorMatcher : public GenericDescriptorMatcher
{
public:
VectorDescriptorMatcher( const Ptr<DescriptorExtractor>& extractor, const Ptr<DescriptorMatcher>& matcher );
virtual ~VectorDescriptorMatcher();
virtual void add( InputArrayOfArrays imgCollection,
vector<vector<KeyPoint> >& pointCollection );
virtual void clear();
virtual void train();
virtual bool isMaskSupported();
virtual void read( const FileNode& fn );
virtual void write( FileStorage& fs ) const;
virtual Ptr<GenericDescriptorMatcher> clone( bool emptyTrainData=false ) const;
protected:
...
};
Example: ::
VectorDescriptorMatcher matcher( new SurfDescriptorExtractor,
new BruteForceMatcher<L2<float> > );

@ -36,38 +36,6 @@ Detects corners using the FAST algorithm by [Rosten06]_.
.. [Rosten06] E. Rosten. Machine Learning for High-speed Corner Detection, 2006.
BriefDescriptorExtractor
------------------------
.. ocv:class:: BriefDescriptorExtractor : public DescriptorExtractor
Class for computing BRIEF descriptors described in a paper of Calonder M., Lepetit V.,
Strecha C., Fua P. *BRIEF: Binary Robust Independent Elementary Features* ,
11th European Conference on Computer Vision (ECCV), Heraklion, Crete. LNCS Springer, September 2010. ::
class BriefDescriptorExtractor : public DescriptorExtractor
{
public:
static const int PATCH_SIZE = 48;
static const int KERNEL_SIZE = 9;
// bytes is a length of descriptor in bytes. It can be equal 16, 32 or 64 bytes.
BriefDescriptorExtractor( int bytes = 32 );
virtual void read( const FileNode& );
virtual void write( FileStorage& ) const;
virtual int descriptorSize() const;
virtual int descriptorType() const;
virtual int defaultNorm() const;
protected:
...
};
.. note::
* A complete BRIEF extractor sample can be found at opencv_source_code/samples/cpp/brief_match_test.cpp
MSER
----
.. ocv:class:: MSER : public FeatureDetector
@ -213,43 +181,6 @@ Finds keypoints in an image and computes their descriptors
:param useProvidedKeypoints: If it is true, then the method will use the provided vector of keypoints instead of detecting them.
FREAK
-----
.. ocv:class:: FREAK : public DescriptorExtractor
Class implementing the FREAK (*Fast Retina Keypoint*) keypoint descriptor, described in [AOV12]_. The algorithm propose a novel keypoint descriptor inspired by the human visual system and more precisely the retina, coined Fast Retina Key- point (FREAK). A cascade of binary strings is computed by efficiently comparing image intensities over a retinal sampling pattern. FREAKs are in general faster to compute with lower memory load and also more robust than SIFT, SURF or BRISK. They are competitive alternatives to existing keypoints in particular for embedded applications.
.. [AOV12] A. Alahi, R. Ortiz, and P. Vandergheynst. FREAK: Fast Retina Keypoint. In IEEE Conference on Computer Vision and Pattern Recognition, 2012. CVPR 2012 Open Source Award Winner.
.. note::
* An example on how to use the FREAK descriptor can be found at opencv_source_code/samples/cpp/freak_demo.cpp
FREAK::FREAK
------------
The FREAK constructor
.. ocv:function:: FREAK::FREAK( bool orientationNormalized=true, bool scaleNormalized=true, float patternScale=22.0f, int nOctaves=4, const vector<int>& selectedPairs=vector<int>() )
:param orientationNormalized: Enable orientation normalization.
:param scaleNormalized: Enable scale normalization.
:param patternScale: Scaling of the description pattern.
:param nOctaves: Number of octaves covered by the detected keypoints.
:param selectedPairs: (Optional) user defined selected pairs indexes,
FREAK::selectPairs
------------------
Select the 512 best description pair indexes from an input (grayscale) image set. FREAK is available with a set of pairs learned off-line. Researchers can run a training process to learn their own set of pair. For more details read section 4.2 in: A. Alahi, R. Ortiz, and P. Vandergheynst. FREAK: Fast Retina Keypoint. In IEEE Conference on Computer Vision and Pattern Recognition, 2012.
We notice that for keypoint matching applications, image content has little effect on the selected pairs unless very specific what does matter is the detector type (blobs, corners,...) and the options used (scale/rotation invariance,...). Reduce corrThresh if not enough pairs are selected (43 points --> 903 possible pairs)
.. ocv:function:: vector<int> FREAK::selectPairs(const vector<Mat>& images, vector<vector<KeyPoint> >& keypoints, const double corrThresh = 0.7, bool verbose = true)
:param images: Grayscale image input set.
:param keypoints: Set of detected keypoints
:param corrThresh: Correlation threshold.
:param verbose: Prints pair selection informations.
KAZE
----
.. ocv:class:: KAZE : public Feature2D
@ -312,3 +243,10 @@ The AKAZE constructor
:param octaves: Maximum octave evolution of the image
:param sublevels: Default number of sublevels per scale level
:param diffusivity: Diffusivity type. DIFF_PM_G1, DIFF_PM_G2, DIFF_WEICKERT or DIFF_CHARBONNIER
SIFT
----
.. ocv:class:: SIFT : public Feature2D
The SIFT algorithm has been moved to opencv_contrib/xfeatures2d module.

@ -11,6 +11,5 @@ features2d. 2D Features Framework
common_interfaces_of_feature_detectors
common_interfaces_of_descriptor_extractors
common_interfaces_of_descriptor_matchers
common_interfaces_of_generic_descriptor_matchers
drawing_function_of_keypoints_and_matches
object_categorization

@ -49,7 +49,7 @@
namespace cv
{
CV_EXPORTS bool initModule_features2d();
CV_EXPORTS bool initModule_features2d(void);
// //! writes vector of keypoints to the file storage
// CV_EXPORTS void write(FileStorage& fs, const String& name, const std::vector<KeyPoint>& keypoints);
@ -353,107 +353,6 @@ protected:
typedef ORB OrbFeatureDetector;
typedef ORB OrbDescriptorExtractor;
/*!
FREAK implementation
*/
class CV_EXPORTS FREAK : public DescriptorExtractor
{
public:
/** Constructor
* @param orientationNormalized enable orientation normalization
* @param scaleNormalized enable scale normalization
* @param patternScale scaling of the description pattern
* @param nbOctave number of octaves covered by the detected keypoints
* @param selectedPairs (optional) user defined selected pairs
*/
explicit FREAK( bool orientationNormalized = true,
bool scaleNormalized = true,
float patternScale = 22.0f,
int nOctaves = 4,
const std::vector<int>& selectedPairs = std::vector<int>());
FREAK( const FREAK& rhs );
FREAK& operator=( const FREAK& );
virtual ~FREAK();
/** returns the descriptor length in bytes */
virtual int descriptorSize() const;
/** returns the descriptor type */
virtual int descriptorType() const;
/** returns the default norm type */
virtual int defaultNorm() const;
/** select the 512 "best description pairs"
* @param images grayscale images set
* @param keypoints set of detected keypoints
* @param corrThresh correlation threshold
* @param verbose print construction information
* @return list of best pair indexes
*/
std::vector<int> selectPairs( const std::vector<Mat>& images, std::vector<std::vector<KeyPoint> >& keypoints,
const double corrThresh = 0.7, bool verbose = true );
AlgorithmInfo* info() const;
enum
{
NB_SCALES = 64, NB_PAIRS = 512, NB_ORIENPAIRS = 45
};
protected:
virtual void computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
void buildPattern();
template <typename imgType, typename iiType>
imgType meanIntensity( InputArray image, InputArray integral, const float kp_x, const float kp_y,
const unsigned int scale, const unsigned int rot, const unsigned int point ) const;
template <typename srcMatType, typename iiMatType>
void computeDescriptors( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
template <typename srcMatType>
void extractDescriptor(srcMatType *pointsValue, void ** ptr) const;
bool orientationNormalized; //true if the orientation is normalized, false otherwise
bool scaleNormalized; //true if the scale is normalized, false otherwise
double patternScale; //scaling of the pattern
int nOctaves; //number of octaves
bool extAll; // true if all pairs need to be extracted for pairs selection
double patternScale0;
int nOctaves0;
std::vector<int> selectedPairs0;
struct PatternPoint
{
float x; // x coordinate relative to center
float y; // x coordinate relative to center
float sigma; // Gaussian smoothing sigma
};
struct DescriptionPair
{
uchar i; // index of the first point
uchar j; // index of the second point
};
struct OrientationPair
{
uchar i; // index of the first point
uchar j; // index of the second point
int weight_dx; // dx/(norm_sq))*4096
int weight_dy; // dy/(norm_sq))*4096
};
std::vector<PatternPoint> patternLookup; // look-up table for the pattern points (position+sigma of all points at all scales and orientation)
int patternSizes[NB_SCALES]; // size of the pattern at a specific scale (used to check if a point is within image boundaries)
DescriptionPair descriptionPairs[NB_PAIRS];
OrientationPair orientationPairs[NB_ORIENPAIRS];
};
/*!
Maximal Stable Extremal Regions class.
@ -493,36 +392,6 @@ protected:
typedef MSER MserFeatureDetector;
/*!
The "Star" Detector.
The class implements the keypoint detector introduced by K. Konolige.
*/
class CV_EXPORTS_W StarDetector : public FeatureDetector
{
public:
//! the full constructor
CV_WRAP StarDetector(int _maxSize=45, int _responseThreshold=30,
int _lineThresholdProjected=10,
int _lineThresholdBinarized=8,
int _suppressNonmaxSize=5);
//! finds the keypoints in the image
CV_WRAP_AS(detect) void operator()(const Mat& image,
CV_OUT std::vector<KeyPoint>& keypoints) const;
AlgorithmInfo* info() const;
protected:
void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
int maxSize;
int responseThreshold;
int lineThresholdProjected;
int lineThresholdBinarized;
int suppressNonmaxSize;
};
//! detects corners using FAST algorithm by E. Rosten
CV_EXPORTS void FAST( InputArray image, CV_OUT std::vector<KeyPoint>& keypoints,
int threshold, bool nonmaxSuppression=true );
@ -570,7 +439,6 @@ protected:
};
typedef GFTTDetector GoodFeaturesToTrackDetector;
typedef StarDetector StarFeatureDetector;
class CV_EXPORTS_W SimpleBlobDetector : public FeatureDetector
{
@ -624,277 +492,6 @@ protected:
};
class CV_EXPORTS_W DenseFeatureDetector : public FeatureDetector
{
public:
CV_WRAP explicit DenseFeatureDetector( float initFeatureScale=1.f, int featureScaleLevels=1,
float featureScaleMul=0.1f,
int initXyStep=6, int initImgBound=0,
bool varyXyStepWithScale=true,
bool varyImgBoundWithScale=false );
AlgorithmInfo* info() const;
protected:
virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
double initFeatureScale;
int featureScaleLevels;
double featureScaleMul;
int initXyStep;
int initImgBound;
bool varyXyStepWithScale;
bool varyImgBoundWithScale;
};
/*
* Adapts a detector to partition the source image into a grid and detect
* points in each cell.
*/
class CV_EXPORTS_W GridAdaptedFeatureDetector : public FeatureDetector
{
public:
/*
* detector Detector that will be adapted.
* maxTotalKeypoints Maximum count of keypoints detected on the image. Only the strongest keypoints
* will be keeped.
* gridRows Grid rows count.
* gridCols Grid column count.
*/
CV_WRAP GridAdaptedFeatureDetector( const Ptr<FeatureDetector>& detector=Ptr<FeatureDetector>(),
int maxTotalKeypoints=1000,
int gridRows=4, int gridCols=4 );
// TODO implement read/write
virtual bool empty() const;
AlgorithmInfo* info() const;
protected:
virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
Ptr<FeatureDetector> detector;
int maxTotalKeypoints;
int gridRows;
int gridCols;
};
/*
* Adapts a detector to detect points over multiple levels of a Gaussian
* pyramid. Useful for detectors that are not inherently scaled.
*/
class CV_EXPORTS_W PyramidAdaptedFeatureDetector : public FeatureDetector
{
public:
// maxLevel - The 0-based index of the last pyramid layer
CV_WRAP PyramidAdaptedFeatureDetector( const Ptr<FeatureDetector>& detector, int maxLevel=2 );
// TODO implement read/write
virtual bool empty() const;
protected:
virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
Ptr<FeatureDetector> detector;
int maxLevel;
};
/** \brief A feature detector parameter adjuster, this is used by the DynamicAdaptedFeatureDetector
* and is a wrapper for FeatureDetector that allow them to be adjusted after a detection
*/
class CV_EXPORTS AdjusterAdapter: public FeatureDetector
{
public:
/** pure virtual interface
*/
virtual ~AdjusterAdapter() {}
/** too few features were detected so, adjust the detector params accordingly
* \param min the minimum number of desired features
* \param n_detected the number previously detected
*/
virtual void tooFew(int min, int n_detected) = 0;
/** too many features were detected so, adjust the detector params accordingly
* \param max the maximum number of desired features
* \param n_detected the number previously detected
*/
virtual void tooMany(int max, int n_detected) = 0;
/** are params maxed out or still valid?
* \return false if the parameters can't be adjusted any more
*/
virtual bool good() const = 0;
virtual Ptr<AdjusterAdapter> clone() const = 0;
static Ptr<AdjusterAdapter> create( const String& detectorType );
};
/** \brief an adaptively adjusting detector that iteratively detects until the desired number
* of features are detected.
* Beware that this is not thread safe - as the adjustment of parameters breaks the const
* of the detection routine...
* /TODO Make this const correct and thread safe
*
* sample usage:
//will create a detector that attempts to find 100 - 110 FAST Keypoints, and will at most run
//FAST feature detection 10 times until that number of keypoints are found
Ptr<FeatureDetector> detector(new DynamicAdaptedFeatureDetector(new FastAdjuster(20,true),100, 110, 10));
*/
class CV_EXPORTS DynamicAdaptedFeatureDetector: public FeatureDetector
{
public:
/** \param adjuster an AdjusterAdapter that will do the detection and parameter adjustment
* \param max_features the maximum desired number of features
* \param max_iters the maximum number of times to try to adjust the feature detector params
* for the FastAdjuster this can be high, but with Star or Surf this can get time consuming
* \param min_features the minimum desired features
*/
DynamicAdaptedFeatureDetector( const Ptr<AdjusterAdapter>& adjuster, int min_features=400, int max_features=500, int max_iters=5 );
virtual bool empty() const;
protected:
virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
private:
DynamicAdaptedFeatureDetector& operator=(const DynamicAdaptedFeatureDetector&);
DynamicAdaptedFeatureDetector(const DynamicAdaptedFeatureDetector&);
int escape_iters_;
int min_features_, max_features_;
const Ptr<AdjusterAdapter> adjuster_;
};
/**\brief an adjust for the FAST detector. This will basically decrement or increment the
* threshold by 1
*/
class CV_EXPORTS FastAdjuster: public AdjusterAdapter
{
public:
/**\param init_thresh the initial threshold to start with, default = 20
* \param nonmax whether to use non max or not for fast feature detection
*/
FastAdjuster(int init_thresh=20, bool nonmax=true, int min_thresh=1, int max_thresh=200);
virtual void tooFew(int minv, int n_detected);
virtual void tooMany(int maxv, int n_detected);
virtual bool good() const;
virtual Ptr<AdjusterAdapter> clone() const;
protected:
virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
int thresh_;
bool nonmax_;
int init_thresh_, min_thresh_, max_thresh_;
};
/** An adjuster for StarFeatureDetector, this one adjusts the responseThreshold for now
* TODO find a faster way to converge the parameters for Star - use CvStarDetectorParams
*/
class CV_EXPORTS StarAdjuster: public AdjusterAdapter
{
public:
StarAdjuster(double initial_thresh=30.0, double min_thresh=2., double max_thresh=200.);
virtual void tooFew(int minv, int n_detected);
virtual void tooMany(int maxv, int n_detected);
virtual bool good() const;
virtual Ptr<AdjusterAdapter> clone() const;
protected:
virtual void detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
double thresh_, init_thresh_, min_thresh_, max_thresh_;
};
class CV_EXPORTS SurfAdjuster: public AdjusterAdapter
{
public:
SurfAdjuster( double initial_thresh=400.f, double min_thresh=2, double max_thresh=1000 );
virtual void tooFew(int minv, int n_detected);
virtual void tooMany(int maxv, int n_detected);
virtual bool good() const;
virtual Ptr<AdjusterAdapter> clone() const;
protected:
virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
double thresh_, init_thresh_, min_thresh_, max_thresh_;
};
CV_EXPORTS Mat windowedMatchingMask( const std::vector<KeyPoint>& keypoints1, const std::vector<KeyPoint>& keypoints2,
float maxDeltaX, float maxDeltaY );
/*
* OpponentColorDescriptorExtractor
*
* Adapts a descriptor extractor to compute descriptors in Opponent Color Space
* (refer to van de Sande et al., CGIV 2008 "Color Descriptors for Object Category Recognition").
* Input RGB image is transformed in Opponent Color Space. Then unadapted descriptor extractor
* (set in constructor) computes descriptors on each of the three channel and concatenate
* them into a single color descriptor.
*/
class CV_EXPORTS OpponentColorDescriptorExtractor : public DescriptorExtractor
{
public:
OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& descriptorExtractor );
virtual void read( const FileNode& );
virtual void write( FileStorage& ) const;
virtual int descriptorSize() const;
virtual int descriptorType() const;
virtual int defaultNorm() const;
virtual bool empty() const;
protected:
virtual void computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
Ptr<DescriptorExtractor> descriptorExtractor;
};
/*
* BRIEF Descriptor
*/
class CV_EXPORTS BriefDescriptorExtractor : public DescriptorExtractor
{
public:
static const int PATCH_SIZE = 48;
static const int KERNEL_SIZE = 9;
// bytes is a length of descriptor in bytes. It can be equal 16, 32 or 64 bytes.
BriefDescriptorExtractor( int bytes = 32 );
virtual void read( const FileNode& );
virtual void write( FileStorage& ) const;
virtual int descriptorSize() const;
virtual int descriptorType() const;
virtual int defaultNorm() const;
/// @todo read and write for brief
AlgorithmInfo* info() const;
protected:
virtual void computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const;
typedef void(*PixelTestFn)(InputArray, const std::vector<KeyPoint>&, OutputArray);
int bytes_;
PixelTestFn test_fn_;
};
// KAZE/AKAZE diffusivity
enum {
DIFF_PM_G1 = 0,
@ -1293,208 +890,6 @@ protected:
int addedDescCount;
};
/****************************************************************************************\
* GenericDescriptorMatcher *
\****************************************************************************************/
/*
* Abstract interface for a keypoint descriptor and matcher
*/
class GenericDescriptorMatcher;
typedef GenericDescriptorMatcher GenericDescriptorMatch;
class CV_EXPORTS GenericDescriptorMatcher
{
public:
GenericDescriptorMatcher();
virtual ~GenericDescriptorMatcher();
/*
* Add train collection: images and keypoints from them.
* images A set of train images.
* ketpoints Keypoint collection that have been detected on train images.
*
* Keypoints for which a descriptor cannot be computed are removed. Such keypoints
* must be filtered in this method befor adding keypoints to train collection "trainPointCollection".
* If inheritor class need perform such prefiltering the method add() must be overloaded.
* In the other class methods programmer has access to the train keypoints by a constant link.
*/
virtual void add( InputArrayOfArrays images,
std::vector<std::vector<KeyPoint> >& keypoints );
const std::vector<Mat>& getTrainImages() const;
const std::vector<std::vector<KeyPoint> >& getTrainKeypoints() const;
/*
* Clear images and keypoints storing in train collection.
*/
virtual void clear();
/*
* Returns true if matcher supports mask to match descriptors.
*/
virtual bool isMaskSupported() = 0;
/*
* Train some inner structures (e.g. flann index or decision trees).
* train() methods is run every time in matching methods. So the method implementation
* should has a check whether these inner structures need be trained/retrained or not.
*/
virtual void train();
/*
* Classifies query keypoints.
* queryImage The query image
* queryKeypoints Keypoints from the query image
* trainImage The train image
* trainKeypoints Keypoints from the train image
*/
// Classify keypoints from query image under one train image.
void classify( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
InputArray trainImage, std::vector<KeyPoint>& trainKeypoints ) const;
// Classify keypoints from query image under train image collection.
void classify( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints );
/*
* Group of methods to match keypoints from image pair.
* Keypoints for which a descriptor cannot be computed are removed.
* train() method is called here.
*/
// Find one best match for each query descriptor (if mask is empty).
void match( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
InputArray trainImage, std::vector<KeyPoint>& trainKeypoints,
std::vector<DMatch>& matches, InputArray mask=noArray() ) const;
// Find k best matches for each query keypoint (in increasing order of distances).
// compactResult is used when mask is not empty. If compactResult is false matches
// vector will have the same size as queryDescriptors rows.
// If compactResult is true matches vector will not contain matches for fully masked out query descriptors.
void knnMatch( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
InputArray trainImage, std::vector<KeyPoint>& trainKeypoints,
std::vector<std::vector<DMatch> >& matches, int k,
InputArray mask=noArray(), bool compactResult=false ) const;
// Find best matches for each query descriptor which have distance less than maxDistance (in increasing order of distances).
void radiusMatch( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
InputArray trainImage, std::vector<KeyPoint>& trainKeypoints,
std::vector<std::vector<DMatch> >& matches, float maxDistance,
InputArray mask=noArray(), bool compactResult=false ) const;
/*
* Group of methods to match keypoints from one image to image set.
* See description of similar methods for matching image pair above.
*/
void match( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<DMatch>& matches, InputArrayOfArrays masks=noArray() );
void knnMatch( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, int k,
InputArrayOfArrays masks=noArray(), bool compactResult=false );
void radiusMatch(InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, float maxDistance,
InputArrayOfArrays masks=noArray(), bool compactResult=false );
// Reads matcher object from a file node
virtual void read( const FileNode& fn );
// Writes matcher object to a file storage
virtual void write( FileStorage& fs ) const;
// Return true if matching object is empty (e.g. feature detector or descriptor matcher are empty)
virtual bool empty() const;
// Clone the matcher. If emptyTrainData is false the method create deep copy of the object, i.e. copies
// both parameters and train data. If emptyTrainData is true the method create object copy with current parameters
// but with empty train data.
virtual Ptr<GenericDescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
static Ptr<GenericDescriptorMatcher> create( const String& genericDescritptorMatcherType,
const String &paramsFilename=String() );
protected:
// In fact the matching is implemented only by the following two methods. These methods suppose
// that the class object has been trained already. Public match methods call these methods
// after calling train().
virtual void knnMatchImpl( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, int k,
InputArrayOfArrays masks, bool compactResult ) = 0;
virtual void radiusMatchImpl( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, float maxDistance,
InputArrayOfArrays masks, bool compactResult ) = 0;
/*
* A storage for sets of keypoints together with corresponding images and class IDs
*/
class CV_EXPORTS KeyPointCollection
{
public:
KeyPointCollection();
KeyPointCollection( const KeyPointCollection& collection );
void add( const std::vector<Mat>& images, const std::vector<std::vector<KeyPoint> >& keypoints );
void clear();
// Returns the total number of keypoints in the collection
size_t keypointCount() const;
size_t imageCount() const;
const std::vector<std::vector<KeyPoint> >& getKeypoints() const;
const std::vector<KeyPoint>& getKeypoints( int imgIdx ) const;
const KeyPoint& getKeyPoint( int imgIdx, int localPointIdx ) const;
const KeyPoint& getKeyPoint( int globalPointIdx ) const;
void getLocalIdx( int globalPointIdx, int& imgIdx, int& localPointIdx ) const;
const std::vector<Mat>& getImages() const;
const Mat& getImage( int imgIdx ) const;
protected:
int pointCount;
std::vector<Mat> images;
std::vector<std::vector<KeyPoint> > keypoints;
// global indices of the first points in each image, startIndices.size() = keypoints.size()
std::vector<int> startIndices;
private:
static Mat clone_op( Mat m ) { return m.clone(); }
};
KeyPointCollection trainPointCollection;
};
/****************************************************************************************\
* VectorDescriptorMatcher *
\****************************************************************************************/
/*
* A class used for matching descriptors that can be described as vectors in a finite-dimensional space
*/
class VectorDescriptorMatcher;
typedef VectorDescriptorMatcher VectorDescriptorMatch;
class CV_EXPORTS VectorDescriptorMatcher : public GenericDescriptorMatcher
{
public:
VectorDescriptorMatcher( const Ptr<DescriptorExtractor>& extractor, const Ptr<DescriptorMatcher>& matcher );
virtual ~VectorDescriptorMatcher();
virtual void add( InputArrayOfArrays imgCollection,
std::vector<std::vector<KeyPoint> >& pointCollection );
virtual void clear();
virtual void train();
virtual bool isMaskSupported();
virtual void read( const FileNode& fn );
virtual void write( FileStorage& fs ) const;
virtual bool empty() const;
virtual Ptr<GenericDescriptorMatcher> clone( bool emptyTrainData=false ) const;
protected:
virtual void knnMatchImpl( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, int k,
InputArrayOfArrays masks, bool compactResult );
virtual void radiusMatchImpl( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, float maxDistance,
InputArrayOfArrays masks, bool compactResult );
Ptr<DescriptorExtractor> extractor;
Ptr<DescriptorMatcher> matcher;
};
/****************************************************************************************\
* Drawing functions *
@ -1547,30 +942,23 @@ CV_EXPORTS void computeRecallPrecisionCurve( const std::vector<std::vector<DMatc
CV_EXPORTS float getRecall( const std::vector<Point2f>& recallPrecisionCurve, float l_precision );
CV_EXPORTS int getNearestPoint( const std::vector<Point2f>& recallPrecisionCurve, float l_precision );
CV_EXPORTS void evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, const Mat& H1to2,
std::vector<KeyPoint>& keypoints1, std::vector<KeyPoint>& keypoints2,
std::vector<std::vector<DMatch> >* matches1to2, std::vector<std::vector<uchar> >* correctMatches1to2Mask,
std::vector<Point2f>& recallPrecisionCurve,
const Ptr<GenericDescriptorMatcher>& dmatch=Ptr<GenericDescriptorMatcher>() );
/****************************************************************************************\
* Bag of visual words *
\****************************************************************************************/
/*
* Abstract base class for training of a 'bag of visual words' vocabulary from a set of descriptors
*/
class CV_EXPORTS BOWTrainer
class CV_EXPORTS_W BOWTrainer
{
public:
BOWTrainer();
virtual ~BOWTrainer();
void add( const Mat& descriptors );
const std::vector<Mat>& getDescriptors() const;
int descriptorsCount() const;
CV_WRAP void add( const Mat& descriptors );
CV_WRAP const std::vector<Mat>& getDescriptors() const;
CV_WRAP int descriptorsCount() const;
virtual void clear();
CV_WRAP virtual void clear();
/*
* Train visual words vocabulary, that is cluster training descriptors and
@ -1579,8 +967,8 @@ public:
*
* descriptors Training descriptors computed on images keypoints.
*/
virtual Mat cluster() const = 0;
virtual Mat cluster( const Mat& descriptors ) const = 0;
CV_WRAP virtual Mat cluster() const = 0;
CV_WRAP virtual Mat cluster( const Mat& descriptors ) const = 0;
protected:
std::vector<Mat> descriptors;
@ -1590,16 +978,16 @@ protected:
/*
* This is BOWTrainer using cv::kmeans to get vocabulary.
*/
class CV_EXPORTS BOWKMeansTrainer : public BOWTrainer
class CV_EXPORTS_W BOWKMeansTrainer : public BOWTrainer
{
public:
BOWKMeansTrainer( int clusterCount, const TermCriteria& termcrit=TermCriteria(),
CV_WRAP BOWKMeansTrainer( int clusterCount, const TermCriteria& termcrit=TermCriteria(),
int attempts=3, int flags=KMEANS_PP_CENTERS );
virtual ~BOWKMeansTrainer();
// Returns trained vocabulary (i.e. cluster centers).
virtual Mat cluster() const;
virtual Mat cluster( const Mat& descriptors ) const;
CV_WRAP virtual Mat cluster() const;
CV_WRAP virtual Mat cluster( const Mat& descriptors ) const;
protected:
@ -1612,24 +1000,27 @@ protected:
/*
* Class to compute image descriptor using bag of visual words.
*/
class CV_EXPORTS BOWImgDescriptorExtractor
class CV_EXPORTS_W BOWImgDescriptorExtractor
{
public:
BOWImgDescriptorExtractor( const Ptr<DescriptorExtractor>& dextractor,
CV_WRAP BOWImgDescriptorExtractor( const Ptr<DescriptorExtractor>& dextractor,
const Ptr<DescriptorMatcher>& dmatcher );
BOWImgDescriptorExtractor( const Ptr<DescriptorMatcher>& dmatcher );
virtual ~BOWImgDescriptorExtractor();
void setVocabulary( const Mat& vocabulary );
const Mat& getVocabulary() const;
CV_WRAP void setVocabulary( const Mat& vocabulary );
CV_WRAP const Mat& getVocabulary() const;
void compute( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray imgDescriptor,
std::vector<std::vector<int> >* pointIdxsOfClusters=0, Mat* descriptors=0 );
void compute( InputArray keypointDescriptors, OutputArray imgDescriptor,
std::vector<std::vector<int> >* pointIdxsOfClusters=0 );
// compute() is not constant because DescriptorMatcher::match is not constant
int descriptorSize() const;
int descriptorType() const;
CV_WRAP_AS(compute) void compute2( const Mat& image, std::vector<KeyPoint>& keypoints, CV_OUT Mat& imgDescriptor )
{ compute(image,keypoints,imgDescriptor); }
CV_WRAP int descriptorSize() const;
CV_WRAP int descriptorType() const;
protected:
Mat vocabulary;

@ -1,184 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2010, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
#include <algorithm>
#include <vector>
#include <iostream>
#include <iomanip>
using namespace cv;
inline int smoothedSum(const Mat& sum, const KeyPoint& pt, int y, int x)
{
static const int HALF_KERNEL = BriefDescriptorExtractor::KERNEL_SIZE / 2;
int img_y = (int)(pt.pt.y + 0.5) + y;
int img_x = (int)(pt.pt.x + 0.5) + x;
return sum.at<int>(img_y + HALF_KERNEL + 1, img_x + HALF_KERNEL + 1)
- sum.at<int>(img_y + HALF_KERNEL + 1, img_x - HALF_KERNEL)
- sum.at<int>(img_y - HALF_KERNEL, img_x + HALF_KERNEL + 1)
+ sum.at<int>(img_y - HALF_KERNEL, img_x - HALF_KERNEL);
}
static void pixelTests16(InputArray _sum, const std::vector<KeyPoint>& keypoints, OutputArray _descriptors)
{
Mat sum = _sum.getMat(), descriptors = _descriptors.getMat();
for (int i = 0; i < (int)keypoints.size(); ++i)
{
uchar* desc = descriptors.ptr(i);
const KeyPoint& pt = keypoints[i];
#include "generated_16.i"
}
}
static void pixelTests32(InputArray _sum, const std::vector<KeyPoint>& keypoints, OutputArray _descriptors)
{
Mat sum = _sum.getMat(), descriptors = _descriptors.getMat();
for (int i = 0; i < (int)keypoints.size(); ++i)
{
uchar* desc = descriptors.ptr(i);
const KeyPoint& pt = keypoints[i];
#include "generated_32.i"
}
}
static void pixelTests64(InputArray _sum, const std::vector<KeyPoint>& keypoints, OutputArray _descriptors)
{
Mat sum = _sum.getMat(), descriptors = _descriptors.getMat();
for (int i = 0; i < (int)keypoints.size(); ++i)
{
uchar* desc = descriptors.ptr(i);
const KeyPoint& pt = keypoints[i];
#include "generated_64.i"
}
}
namespace cv
{
BriefDescriptorExtractor::BriefDescriptorExtractor(int bytes) :
bytes_(bytes), test_fn_(NULL)
{
switch (bytes)
{
case 16:
test_fn_ = pixelTests16;
break;
case 32:
test_fn_ = pixelTests32;
break;
case 64:
test_fn_ = pixelTests64;
break;
default:
CV_Error(Error::StsBadArg, "bytes must be 16, 32, or 64");
}
}
int BriefDescriptorExtractor::descriptorSize() const
{
return bytes_;
}
int BriefDescriptorExtractor::descriptorType() const
{
return CV_8UC1;
}
int BriefDescriptorExtractor::defaultNorm() const
{
return NORM_HAMMING;
}
void BriefDescriptorExtractor::read( const FileNode& fn)
{
int dSize = fn["descriptorSize"];
switch (dSize)
{
case 16:
test_fn_ = pixelTests16;
break;
case 32:
test_fn_ = pixelTests32;
break;
case 64:
test_fn_ = pixelTests64;
break;
default:
CV_Error(Error::StsBadArg, "descriptorSize must be 16, 32, or 64");
}
bytes_ = dSize;
}
void BriefDescriptorExtractor::write( FileStorage& fs) const
{
fs << "descriptorSize" << bytes_;
}
void BriefDescriptorExtractor::computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const
{
// Construct integral image for fast smoothing (box filter)
Mat sum;
Mat grayImage = image.getMat();
if( image.type() != CV_8U ) cvtColor( image, grayImage, COLOR_BGR2GRAY );
///TODO allow the user to pass in a precomputed integral image
//if(image.type() == CV_32S)
// sum = image;
//else
integral( grayImage, sum, CV_32S);
//Remove keypoints very close to the border
KeyPointsFilter::runByImageBorder(keypoints, image.size(), PATCH_SIZE/2 + KERNEL_SIZE/2);
descriptors.create((int)keypoints.size(), bytes_, CV_8U);
descriptors.setTo(Scalar::all(0));
test_fn_(sum, keypoints, descriptors);
}
} // namespace cv

@ -427,7 +427,7 @@ BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const fl
if (dx + dy > 2)
{
// now the calculation:
uchar* ptr = image.data + x_left + imagecols * y_top;
const uchar* ptr = image.data + x_left + imagecols * y_top;
// first the corners:
ret_val = A * int(*ptr);
ptr += dx + 1;
@ -475,7 +475,7 @@ BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const fl
}
// now the calculation:
uchar* ptr = image.data + x_left + imagecols * y_top;
const uchar* ptr = image.data + x_left + imagecols * y_top;
// first row:
ret_val = A * int(*ptr);
ptr++;
@ -487,7 +487,7 @@ BRISK::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const fl
ret_val += B * int(*ptr);
// middle ones:
ptr += imagecols - dx - 1;
uchar* end_j = ptr + dy * imagecols;
const uchar* end_j = ptr + dy * imagecols;
for (; ptr < end_j; ptr += imagecols - dx - 1)
{
ret_val += r_x_1_i * int(*ptr);
@ -607,7 +607,7 @@ BRISK::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, s
int t2;
// the feature orientation
uchar* ptr = descriptors.data;
const uchar* ptr = descriptors.data;
for (size_t k = 0; k < ksize; k++)
{
cv::KeyPoint& kp = keypoints[k];
@ -1070,7 +1070,7 @@ BriskScaleSpace::isMax2D(const int layer, const int x_layer, const int y_layer)
{
const cv::Mat& scores = pyramid_[layer].scores();
const int scorescols = scores.cols;
uchar* data = scores.data + y_layer * scorescols + x_layer;
const uchar* data = scores.data + y_layer * scorescols + x_layer;
// decision tree:
const uchar center = (*data);
data--;
@ -2140,7 +2140,7 @@ BriskLayer::value(const cv::Mat& mat, float xf, float yf, float scale_in) const
const int r_y = (int)((yf - y) * 1024);
const int r_x_1 = (1024 - r_x);
const int r_y_1 = (1024 - r_y);
uchar* ptr = image.data + x + y * imagecols;
const uchar* ptr = image.data + x + y * imagecols;
// just interpolate:
ret_val = (r_x_1 * r_y_1 * int(*ptr));
ptr++;
@ -2186,7 +2186,7 @@ BriskLayer::value(const cv::Mat& mat, float xf, float yf, float scale_in) const
const int r_y1_i = (int)(r_y1 * scaling);
// now the calculation:
uchar* ptr = image.data + x_left + imagecols * y_top;
const uchar* ptr = image.data + x_left + imagecols * y_top;
// first row:
ret_val = A * int(*ptr);
ptr++;
@ -2198,7 +2198,7 @@ BriskLayer::value(const cv::Mat& mat, float xf, float yf, float scale_in) const
ret_val += B * int(*ptr);
// middle ones:
ptr += imagecols - dx - 1;
uchar* end_j = ptr + dy * imagecols;
const uchar* end_j = ptr + dy * imagecols;
for (; ptr < end_j; ptr += imagecols - dx - 1)
{
ret_val += r_x_1_i * int(*ptr);

@ -98,13 +98,6 @@ void DescriptorExtractor::removeBorderKeypoints( std::vector<KeyPoint>& keypoint
Ptr<DescriptorExtractor> DescriptorExtractor::create(const String& descriptorExtractorType)
{
if( descriptorExtractorType.find("Opponent") == 0 )
{
size_t pos = String("Opponent").size();
String type = descriptorExtractorType.substr(pos);
return makePtr<OpponentColorDescriptorExtractor>(DescriptorExtractor::create(type));
}
return Algorithm::create<DescriptorExtractor>("Feature2D." + descriptorExtractorType);
}
@ -114,151 +107,4 @@ CV_WRAP void Feature2D::compute( InputArray image, CV_OUT CV_IN_OUT std::vector<
DescriptorExtractor::compute(image, keypoints, descriptors);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/****************************************************************************************\
* OpponentColorDescriptorExtractor *
\****************************************************************************************/
OpponentColorDescriptorExtractor::OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& _descriptorExtractor ) :
descriptorExtractor(_descriptorExtractor)
{
CV_Assert( descriptorExtractor );
}
static void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, std::vector<Mat>& opponentChannels )
{
if( bgrImage.type() != CV_8UC3 )
CV_Error( Error::StsBadArg, "input image must be an BGR image of type CV_8UC3" );
// Prepare opponent color space storage matrices.
opponentChannels.resize( 3 );
opponentChannels[0] = cv::Mat(bgrImage.size(), CV_8UC1); // R-G RED-GREEN
opponentChannels[1] = cv::Mat(bgrImage.size(), CV_8UC1); // R+G-2B YELLOW-BLUE
opponentChannels[2] = cv::Mat(bgrImage.size(), CV_8UC1); // R+G+B
for(int y = 0; y < bgrImage.rows; ++y)
for(int x = 0; x < bgrImage.cols; ++x)
{
Vec3b v = bgrImage.at<Vec3b>(y, x);
uchar& b = v[0];
uchar& g = v[1];
uchar& r = v[2];
opponentChannels[0].at<uchar>(y, x) = saturate_cast<uchar>(0.5f * (255 + g - r)); // (R - G)/sqrt(2), but converted to the destination data type
opponentChannels[1].at<uchar>(y, x) = saturate_cast<uchar>(0.25f * (510 + r + g - 2*b)); // (R + G - 2B)/sqrt(6), but converted to the destination data type
opponentChannels[2].at<uchar>(y, x) = saturate_cast<uchar>(1.f/3.f * (r + g + b)); // (R + G + B)/sqrt(3), but converted to the destination data type
}
}
struct KP_LessThan
{
KP_LessThan(const std::vector<KeyPoint>& _kp) : kp(&_kp) {}
bool operator()(int i, int j) const
{
return (*kp)[i].class_id < (*kp)[j].class_id;
}
const std::vector<KeyPoint>* kp;
};
void OpponentColorDescriptorExtractor::computeImpl( InputArray _bgrImage, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const
{
Mat bgrImage = _bgrImage.getMat();
std::vector<Mat> opponentChannels;
convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels );
const int N = 3; // channels count
std::vector<KeyPoint> channelKeypoints[N];
Mat channelDescriptors[N];
std::vector<int> idxs[N];
// Compute descriptors three times, once for each Opponent channel to concatenate into a single color descriptor
int maxKeypointsCount = 0;
for( int ci = 0; ci < N; ci++ )
{
channelKeypoints[ci].insert( channelKeypoints[ci].begin(), keypoints.begin(), keypoints.end() );
// Use class_id member to get indices into initial keypoints vector
for( size_t ki = 0; ki < channelKeypoints[ci].size(); ki++ )
channelKeypoints[ci][ki].class_id = (int)ki;
descriptorExtractor->compute( opponentChannels[ci], channelKeypoints[ci], channelDescriptors[ci] );
idxs[ci].resize( channelKeypoints[ci].size() );
for( size_t ki = 0; ki < channelKeypoints[ci].size(); ki++ )
{
idxs[ci][ki] = (int)ki;
}
std::sort( idxs[ci].begin(), idxs[ci].end(), KP_LessThan(channelKeypoints[ci]) );
maxKeypointsCount = std::max( maxKeypointsCount, (int)channelKeypoints[ci].size());
}
std::vector<KeyPoint> outKeypoints;
outKeypoints.reserve( keypoints.size() );
int dSize = descriptorExtractor->descriptorSize();
Mat mergedDescriptors( maxKeypointsCount, 3*dSize, descriptorExtractor->descriptorType() );
int mergedCount = 0;
// cp - current channel position
size_t cp[] = {0, 0, 0};
while( cp[0] < channelKeypoints[0].size() &&
cp[1] < channelKeypoints[1].size() &&
cp[2] < channelKeypoints[2].size() )
{
const int maxInitIdx = std::max( 0, std::max( channelKeypoints[0][idxs[0][cp[0]]].class_id,
std::max( channelKeypoints[1][idxs[1][cp[1]]].class_id,
channelKeypoints[2][idxs[2][cp[2]]].class_id ) ) );
while( channelKeypoints[0][idxs[0][cp[0]]].class_id < maxInitIdx && cp[0] < channelKeypoints[0].size() ) { cp[0]++; }
while( channelKeypoints[1][idxs[1][cp[1]]].class_id < maxInitIdx && cp[1] < channelKeypoints[1].size() ) { cp[1]++; }
while( channelKeypoints[2][idxs[2][cp[2]]].class_id < maxInitIdx && cp[2] < channelKeypoints[2].size() ) { cp[2]++; }
if( cp[0] >= channelKeypoints[0].size() || cp[1] >= channelKeypoints[1].size() || cp[2] >= channelKeypoints[2].size() )
break;
if( channelKeypoints[0][idxs[0][cp[0]]].class_id == maxInitIdx &&
channelKeypoints[1][idxs[1][cp[1]]].class_id == maxInitIdx &&
channelKeypoints[2][idxs[2][cp[2]]].class_id == maxInitIdx )
{
outKeypoints.push_back( keypoints[maxInitIdx] );
// merge descriptors
for( int ci = 0; ci < N; ci++ )
{
Mat dst = mergedDescriptors(Range(mergedCount, mergedCount+1), Range(ci*dSize, (ci+1)*dSize));
channelDescriptors[ci].row( idxs[ci][cp[ci]] ).copyTo( dst );
cp[ci]++;
}
mergedCount++;
}
}
mergedDescriptors.rowRange(0, mergedCount).copyTo( descriptors );
std::swap( outKeypoints, keypoints );
}
void OpponentColorDescriptorExtractor::read( const FileNode& fn )
{
descriptorExtractor->read(fn);
}
void OpponentColorDescriptorExtractor::write( FileStorage& fs ) const
{
descriptorExtractor->write(fs);
}
int OpponentColorDescriptorExtractor::descriptorSize() const
{
return 3*descriptorExtractor->descriptorSize();
}
int OpponentColorDescriptorExtractor::descriptorType() const
{
return descriptorExtractor->descriptorType();
}
int OpponentColorDescriptorExtractor::defaultNorm() const
{
return descriptorExtractor->defaultNorm();
}
bool OpponentColorDescriptorExtractor::empty() const
{
return !descriptorExtractor || descriptorExtractor->empty();
}
}

@ -106,24 +106,6 @@ void FeatureDetector::removeInvalidPoints( const Mat& mask, std::vector<KeyPoint
Ptr<FeatureDetector> FeatureDetector::create( const String& detectorType )
{
if( detectorType.find("Grid") == 0 )
{
return makePtr<GridAdaptedFeatureDetector>(FeatureDetector::create(
detectorType.substr(strlen("Grid"))));
}
if( detectorType.find("Pyramid") == 0 )
{
return makePtr<PyramidAdaptedFeatureDetector>(FeatureDetector::create(
detectorType.substr(strlen("Pyramid"))));
}
if( detectorType.find("Dynamic") == 0 )
{
return makePtr<DynamicAdaptedFeatureDetector>(AdjusterAdapter::create(
detectorType.substr(strlen("Dynamic"))));
}
if( detectorType.compare( "HARRIS" ) == 0 )
{
Ptr<FeatureDetector> fd = FeatureDetector::create("GFTT");
@ -176,212 +158,4 @@ void GFTTDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoin
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* DenseFeatureDetector
*/
DenseFeatureDetector::DenseFeatureDetector( float _initFeatureScale, int _featureScaleLevels,
float _featureScaleMul, int _initXyStep,
int _initImgBound, bool _varyXyStepWithScale,
bool _varyImgBoundWithScale ) :
initFeatureScale(_initFeatureScale), featureScaleLevels(_featureScaleLevels),
featureScaleMul(_featureScaleMul), initXyStep(_initXyStep), initImgBound(_initImgBound),
varyXyStepWithScale(_varyXyStepWithScale), varyImgBoundWithScale(_varyImgBoundWithScale)
{}
void DenseFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
{
Mat image = _image.getMat(), mask = _mask.getMat();
float curScale = static_cast<float>(initFeatureScale);
int curStep = initXyStep;
int curBound = initImgBound;
for( int curLevel = 0; curLevel < featureScaleLevels; curLevel++ )
{
for( int x = curBound; x < image.cols - curBound; x += curStep )
{
for( int y = curBound; y < image.rows - curBound; y += curStep )
{
keypoints.push_back( KeyPoint(static_cast<float>(x), static_cast<float>(y), curScale) );
}
}
curScale = static_cast<float>(curScale * featureScaleMul);
if( varyXyStepWithScale ) curStep = static_cast<int>( curStep * featureScaleMul + 0.5f );
if( varyImgBoundWithScale ) curBound = static_cast<int>( curBound * featureScaleMul + 0.5f );
}
KeyPointsFilter::runByPixelsMask( keypoints, mask );
}
/*
* GridAdaptedFeatureDetector
*/
GridAdaptedFeatureDetector::GridAdaptedFeatureDetector( const Ptr<FeatureDetector>& _detector,
int _maxTotalKeypoints, int _gridRows, int _gridCols )
: detector(_detector), maxTotalKeypoints(_maxTotalKeypoints), gridRows(_gridRows), gridCols(_gridCols)
{}
bool GridAdaptedFeatureDetector::empty() const
{
return !detector || detector->empty();
}
struct ResponseComparator
{
bool operator() (const KeyPoint& a, const KeyPoint& b)
{
return std::abs(a.response) > std::abs(b.response);
}
};
static void keepStrongest( int N, std::vector<KeyPoint>& keypoints )
{
if( (int)keypoints.size() > N )
{
std::vector<KeyPoint>::iterator nth = keypoints.begin() + N;
std::nth_element( keypoints.begin(), nth, keypoints.end(), ResponseComparator() );
keypoints.erase( nth, keypoints.end() );
}
}
namespace {
class GridAdaptedFeatureDetectorInvoker : public ParallelLoopBody
{
private:
int gridRows_, gridCols_;
int maxPerCell_;
std::vector<KeyPoint>& keypoints_;
const Mat& image_;
const Mat& mask_;
const Ptr<FeatureDetector>& detector_;
Mutex* kptLock_;
GridAdaptedFeatureDetectorInvoker& operator=(const GridAdaptedFeatureDetectorInvoker&); // to quiet MSVC
public:
GridAdaptedFeatureDetectorInvoker(const Ptr<FeatureDetector>& detector, const Mat& image, const Mat& mask,
std::vector<KeyPoint>& keypoints, int maxPerCell, int gridRows, int gridCols,
cv::Mutex* kptLock)
: gridRows_(gridRows), gridCols_(gridCols), maxPerCell_(maxPerCell),
keypoints_(keypoints), image_(image), mask_(mask), detector_(detector),
kptLock_(kptLock)
{
}
void operator() (const Range& range) const
{
for (int i = range.start; i < range.end; ++i)
{
int celly = i / gridCols_;
int cellx = i - celly * gridCols_;
Range row_range((celly*image_.rows)/gridRows_, ((celly+1)*image_.rows)/gridRows_);
Range col_range((cellx*image_.cols)/gridCols_, ((cellx+1)*image_.cols)/gridCols_);
Mat sub_image = image_(row_range, col_range);
Mat sub_mask;
if (!mask_.empty()) sub_mask = mask_(row_range, col_range);
std::vector<KeyPoint> sub_keypoints;
sub_keypoints.reserve(maxPerCell_);
detector_->detect( sub_image, sub_keypoints, sub_mask );
keepStrongest( maxPerCell_, sub_keypoints );
std::vector<cv::KeyPoint>::iterator it = sub_keypoints.begin(),
end = sub_keypoints.end();
for( ; it != end; ++it )
{
it->pt.x += col_range.start;
it->pt.y += row_range.start;
}
cv::AutoLock join_keypoints(*kptLock_);
keypoints_.insert( keypoints_.end(), sub_keypoints.begin(), sub_keypoints.end() );
}
}
};
} // namepace
void GridAdaptedFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
{
if (_image.empty() || maxTotalKeypoints < gridRows * gridCols)
{
keypoints.clear();
return;
}
keypoints.reserve(maxTotalKeypoints);
int maxPerCell = maxTotalKeypoints / (gridRows * gridCols);
Mat image = _image.getMat(), mask = _mask.getMat();
cv::Mutex kptLock;
cv::parallel_for_(cv::Range(0, gridRows * gridCols),
GridAdaptedFeatureDetectorInvoker(detector, image, mask, keypoints, maxPerCell, gridRows, gridCols, &kptLock));
}
/*
* PyramidAdaptedFeatureDetector
*/
PyramidAdaptedFeatureDetector::PyramidAdaptedFeatureDetector( const Ptr<FeatureDetector>& _detector, int _maxLevel )
: detector(_detector), maxLevel(_maxLevel)
{}
bool PyramidAdaptedFeatureDetector::empty() const
{
return !detector || detector->empty();
}
void PyramidAdaptedFeatureDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
{
Mat image = _image.getMat(), mask = _mask.getMat();
Mat src = image;
Mat src_mask = mask;
Mat dilated_mask;
if( !mask.empty() )
{
dilate( mask, dilated_mask, Mat() );
Mat mask255( mask.size(), CV_8UC1, Scalar(0) );
mask255.setTo( Scalar(255), dilated_mask != 0 );
dilated_mask = mask255;
}
for( int l = 0, multiplier = 1; l <= maxLevel; ++l, multiplier *= 2 )
{
// Detect on current level of the pyramid
std::vector<KeyPoint> new_pts;
detector->detect( src, new_pts, src_mask );
std::vector<KeyPoint>::iterator it = new_pts.begin(),
end = new_pts.end();
for( ; it != end; ++it)
{
it->pt.x *= multiplier;
it->pt.y *= multiplier;
it->size *= multiplier;
it->octave = l;
}
keypoints.insert( keypoints.end(), new_pts.begin(), new_pts.end() );
// Downsample
if( l < maxLevel )
{
Mat dst;
pyrDown( src, dst );
src = dst;
if( !mask.empty() )
resize( dilated_mask, src_mask, src.size(), 0, 0, INTER_AREA );
}
}
if( !mask.empty() )
KeyPointsFilter::runByPixelsMask( keypoints, mask );
}
}

@ -44,181 +44,4 @@
namespace cv
{
DynamicAdaptedFeatureDetector::DynamicAdaptedFeatureDetector(const Ptr<AdjusterAdapter>& a,
int min_features, int max_features, int max_iters ) :
escape_iters_(max_iters), min_features_(min_features), max_features_(max_features), adjuster_(a)
{}
bool DynamicAdaptedFeatureDetector::empty() const
{
return !adjuster_ || adjuster_->empty();
}
void DynamicAdaptedFeatureDetector::detectImpl(InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask) const
{
Mat image = _image.getMat(), mask = _mask.getMat();
//for oscillation testing
bool down = false;
bool up = false;
//flag for whether the correct threshhold has been reached
bool thresh_good = false;
Ptr<AdjusterAdapter> adjuster = adjuster_->clone();
//break if the desired number hasn't been reached.
int iter_count = escape_iters_;
while( iter_count > 0 && !(down && up) && !thresh_good && adjuster->good() )
{
keypoints.clear();
//the adjuster takes care of calling the detector with updated parameters
adjuster->detect(image, keypoints,mask);
if( int(keypoints.size()) < min_features_ )
{
down = true;
adjuster->tooFew(min_features_, (int)keypoints.size());
}
else if( int(keypoints.size()) > max_features_ )
{
up = true;
adjuster->tooMany(max_features_, (int)keypoints.size());
}
else
thresh_good = true;
iter_count--;
}
}
FastAdjuster::FastAdjuster( int init_thresh, bool nonmax, int min_thresh, int max_thresh ) :
thresh_(init_thresh), nonmax_(nonmax), init_thresh_(init_thresh),
min_thresh_(min_thresh), max_thresh_(max_thresh)
{}
void FastAdjuster::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
{
FastFeatureDetector(thresh_, nonmax_).detect(image, keypoints, mask);
}
void FastAdjuster::tooFew(int, int)
{
//fast is easy to adjust
thresh_--;
}
void FastAdjuster::tooMany(int, int)
{
//fast is easy to adjust
thresh_++;
}
//return whether or not the threshhold is beyond
//a useful point
bool FastAdjuster::good() const
{
return (thresh_ > min_thresh_) && (thresh_ < max_thresh_);
}
Ptr<AdjusterAdapter> FastAdjuster::clone() const
{
Ptr<AdjusterAdapter> cloned_obj(new FastAdjuster( init_thresh_, nonmax_, min_thresh_, max_thresh_ ));
return cloned_obj;
}
StarAdjuster::StarAdjuster(double initial_thresh, double min_thresh, double max_thresh) :
thresh_(initial_thresh), init_thresh_(initial_thresh),
min_thresh_(min_thresh), max_thresh_(max_thresh)
{}
void StarAdjuster::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
{
StarFeatureDetector detector_tmp(16, cvRound(thresh_), 10, 8, 3);
detector_tmp.detect(image, keypoints, mask);
}
void StarAdjuster::tooFew(int, int)
{
thresh_ *= 0.9;
if (thresh_ < 1.1)
thresh_ = 1.1;
}
void StarAdjuster::tooMany(int, int)
{
thresh_ *= 1.1;
}
bool StarAdjuster::good() const
{
return (thresh_ > min_thresh_) && (thresh_ < max_thresh_);
}
Ptr<AdjusterAdapter> StarAdjuster::clone() const
{
Ptr<AdjusterAdapter> cloned_obj(new StarAdjuster( init_thresh_, min_thresh_, max_thresh_ ));
return cloned_obj;
}
SurfAdjuster::SurfAdjuster( double initial_thresh, double min_thresh, double max_thresh ) :
thresh_(initial_thresh), init_thresh_(initial_thresh),
min_thresh_(min_thresh), max_thresh_(max_thresh)
{}
void SurfAdjuster::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const
{
Ptr<FeatureDetector> surf = FeatureDetector::create("SURF");
surf->set("hessianThreshold", thresh_);
surf->detect(image, keypoints, mask);
}
void SurfAdjuster::tooFew(int, int)
{
thresh_ *= 0.9;
if (thresh_ < 1.1)
thresh_ = 1.1;
}
void SurfAdjuster::tooMany(int, int)
{
thresh_ *= 1.1;
}
//return whether or not the threshhold is beyond
//a useful point
bool SurfAdjuster::good() const
{
return (thresh_ > min_thresh_) && (thresh_ < max_thresh_);
}
Ptr<AdjusterAdapter> SurfAdjuster::clone() const
{
Ptr<AdjusterAdapter> cloned_obj(new SurfAdjuster( init_thresh_, min_thresh_, max_thresh_ ));
return cloned_obj;
}
Ptr<AdjusterAdapter> AdjusterAdapter::create( const String& detectorType )
{
Ptr<AdjusterAdapter> adapter;
if( !detectorType.compare( "FAST" ) )
{
adapter = makePtr<FastAdjuster>();
}
else if( !detectorType.compare( "STAR" ) )
{
adapter = makePtr<StarAdjuster>();
}
else if( !detectorType.compare( "SURF" ) )
{
adapter = makePtr<SurfAdjuster>();
}
return adapter;
}
}

@ -556,56 +556,3 @@ int cv::getNearestPoint( const std::vector<Point2f>& recallPrecisionCurve, float
return nearestPointIndex;
}
void cv::evaluateGenericDescriptorMatcher( const Mat& img1, const Mat& img2, const Mat& H1to2,
std::vector<KeyPoint>& keypoints1, std::vector<KeyPoint>& keypoints2,
std::vector<std::vector<DMatch> >* _matches1to2, std::vector<std::vector<uchar> >* _correctMatches1to2Mask,
std::vector<Point2f>& recallPrecisionCurve,
const Ptr<GenericDescriptorMatcher>& _dmatcher )
{
Ptr<GenericDescriptorMatcher> dmatcher = _dmatcher;
dmatcher->clear();
std::vector<std::vector<DMatch> > *matches1to2, buf1;
matches1to2 = _matches1to2 != 0 ? _matches1to2 : &buf1;
std::vector<std::vector<uchar> > *correctMatches1to2Mask, buf2;
correctMatches1to2Mask = _correctMatches1to2Mask != 0 ? _correctMatches1to2Mask : &buf2;
if( keypoints1.empty() )
CV_Error( Error::StsBadArg, "keypoints1 must not be empty" );
if( matches1to2->empty() && !dmatcher )
CV_Error( Error::StsBadArg, "dmatch must not be empty when matches1to2 is empty" );
bool computeKeypoints2ByPrj = keypoints2.empty();
if( computeKeypoints2ByPrj )
{
CV_Error(Error::StsNotImplemented, "");
// TODO: add computing keypoints2 from keypoints1 using H1to2
}
if( matches1to2->empty() || computeKeypoints2ByPrj )
{
dmatcher->clear();
dmatcher->radiusMatch( img1, keypoints1, img2, keypoints2, *matches1to2, std::numeric_limits<float>::max() );
}
float repeatability;
int correspCount;
Mat thresholdedOverlapMask; // thresholded allOverlapErrors
calculateRepeatability( img1, img2, H1to2, keypoints1, keypoints2, repeatability, correspCount, &thresholdedOverlapMask );
correctMatches1to2Mask->resize(matches1to2->size());
for( size_t i = 0; i < matches1to2->size(); i++ )
{
(*correctMatches1to2Mask)[i].resize((*matches1to2)[i].size());
for( size_t j = 0;j < (*matches1to2)[i].size(); j++ )
{
int indexQuery = (*matches1to2)[i][j].queryIdx;
int indexTrain = (*matches1to2)[i][j].trainIdx;
(*correctMatches1to2Mask)[i][j] = thresholdedOverlapMask.at<uchar>( indexQuery, indexTrain );
}
}
computeRecallPrecisionCurve( *matches1to2, *correctMatches1to2Mask, recallPrecisionCurve );
}

@ -62,24 +62,11 @@ CV_INIT_ALGORITHM(BRISK, "Feature2D.BRISK",
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(BriefDescriptorExtractor, "Feature2D.BRIEF",
obj.info()->addParam(obj, "bytes", obj.bytes_))
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(FastFeatureDetector, "Feature2D.FAST",
obj.info()->addParam(obj, "threshold", obj.threshold);
obj.info()->addParam(obj, "nonmaxSuppression", obj.nonmaxSuppression);
obj.info()->addParam(obj, "type", obj.type))
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(StarDetector, "Feature2D.STAR",
obj.info()->addParam(obj, "maxSize", obj.maxSize);
obj.info()->addParam(obj, "responseThreshold", obj.responseThreshold);
obj.info()->addParam(obj, "lineThresholdProjected", obj.lineThresholdProjected);
obj.info()->addParam(obj, "lineThresholdBinarized", obj.lineThresholdBinarized);
obj.info()->addParam(obj, "suppressNonmaxSize", obj.suppressNonmaxSize))
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -108,14 +95,6 @@ CV_INIT_ALGORITHM(ORB, "Feature2D.ORB",
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(FREAK, "Feature2D.FREAK",
obj.info()->addParam(obj, "orientationNormalized", obj.orientationNormalized);
obj.info()->addParam(obj, "scaleNormalized", obj.scaleNormalized);
obj.info()->addParam(obj, "patternScale", obj.patternScale);
obj.info()->addParam(obj, "nbOctave", obj.nOctaves))
///////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(GFTTDetector, "Feature2D.GFTT",
obj.info()->addParam(obj, "nfeatures", obj.nfeatures);
obj.info()->addParam(obj, "qualityLevel", obj.qualityLevel);
@ -181,23 +160,6 @@ CV_INIT_ALGORITHM(HarrisDetector, "Feature2D.HARRIS",
////////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(DenseFeatureDetector, "Feature2D.Dense",
obj.info()->addParam(obj, "initFeatureScale", obj.initFeatureScale);
obj.info()->addParam(obj, "featureScaleLevels", obj.featureScaleLevels);
obj.info()->addParam(obj, "featureScaleMul", obj.featureScaleMul);
obj.info()->addParam(obj, "initXyStep", obj.initXyStep);
obj.info()->addParam(obj, "initImgBound", obj.initImgBound);
obj.info()->addParam(obj, "varyXyStepWithScale", obj.varyXyStepWithScale);
obj.info()->addParam(obj, "varyImgBoundWithScale", obj.varyImgBoundWithScale))
CV_INIT_ALGORITHM(GridAdaptedFeatureDetector, "Feature2D.Grid",
obj.info()->addParam<FeatureDetector>(obj, "detector", obj.detector, false, 0, 0); // Extra params added to avoid VS2013 fatal error in opencv2/core.hpp (decl. of addParam)
obj.info()->addParam(obj, "maxTotalKeypoints", obj.maxTotalKeypoints);
obj.info()->addParam(obj, "gridRows", obj.gridRows);
obj.info()->addParam(obj, "gridCols", obj.gridCols))
////////////////////////////////////////////////////////////////////////////////////////////////////////////
CV_INIT_ALGORITHM(BFMatcher, "DescriptorMatcher.BFMatcher",
obj.info()->addParam(obj, "normType", obj.normType);
obj.info()->addParam(obj, "crossCheck", obj.crossCheck))
@ -209,19 +171,14 @@ CV_INIT_ALGORITHM(FlannBasedMatcher, "DescriptorMatcher.FlannBasedMatcher",)
bool cv::initModule_features2d(void)
{
bool all = true;
all &= !BriefDescriptorExtractor_info_auto.name().empty();
all &= !BRISK_info_auto.name().empty();
all &= !FastFeatureDetector_info_auto.name().empty();
all &= !StarDetector_info_auto.name().empty();
all &= !MSER_info_auto.name().empty();
all &= !FREAK_info_auto.name().empty();
all &= !ORB_info_auto.name().empty();
all &= !GFTTDetector_info_auto.name().empty();
all &= !KAZE_info_auto.name().empty();
all &= !AKAZE_info_auto.name().empty();
all &= !HarrisDetector_info_auto.name().empty();
all &= !DenseFeatureDetector_info_auto.name().empty();
all &= !GridAdaptedFeatureDetector_info_auto.name().empty();
all &= !HarrisDetector_info_auto.name().empty();
all &= !BFMatcher_info_auto.name().empty();
all &= !FlannBasedMatcher_info_auto.name().empty();

@ -1,734 +0,0 @@
// freak.cpp
//
// Copyright (C) 2011-2012 Signal processing laboratory 2, EPFL,
// Kirell Benzi (kirell.benzi@epfl.ch),
// Raphael Ortiz (raphael.ortiz@a3.epfl.ch)
// Alexandre Alahi (alexandre.alahi@epfl.ch)
// and Pierre Vandergheynst (pierre.vandergheynst@epfl.ch)
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
#include "precomp.hpp"
#include <fstream>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <bitset>
#include <sstream>
#include <algorithm>
#include <iomanip>
#include <string.h>
namespace cv
{
static const double FREAK_SQRT2 = 1.4142135623731;
static const double FREAK_INV_SQRT2 = 1.0 / FREAK_SQRT2;
static const double FREAK_LOG2 = 0.693147180559945;
static const int FREAK_NB_ORIENTATION = 256;
static const int FREAK_NB_POINTS = 43;
static const int FREAK_SMALLEST_KP_SIZE = 7; // smallest size of keypoints
static const int FREAK_NB_SCALES = FREAK::NB_SCALES;
static const int FREAK_NB_PAIRS = FREAK::NB_PAIRS;
static const int FREAK_NB_ORIENPAIRS = FREAK::NB_ORIENPAIRS;
// default pairs
static const int FREAK_DEF_PAIRS[FREAK::NB_PAIRS] =
{
404,431,818,511,181,52,311,874,774,543,719,230,417,205,11,
560,149,265,39,306,165,857,250,8,61,15,55,717,44,412,
592,134,761,695,660,782,625,487,549,516,271,665,762,392,178,
796,773,31,672,845,548,794,677,654,241,831,225,238,849,83,
691,484,826,707,122,517,583,731,328,339,571,475,394,472,580,
381,137,93,380,327,619,729,808,218,213,459,141,806,341,95,
382,568,124,750,193,749,706,843,79,199,317,329,768,198,100,
466,613,78,562,783,689,136,838,94,142,164,679,219,419,366,
418,423,77,89,523,259,683,312,555,20,470,684,123,458,453,833,
72,113,253,108,313,25,153,648,411,607,618,128,305,232,301,84,
56,264,371,46,407,360,38,99,176,710,114,578,66,372,653,
129,359,424,159,821,10,323,393,5,340,891,9,790,47,0,175,346,
236,26,172,147,574,561,32,294,429,724,755,398,787,288,299,
769,565,767,722,757,224,465,723,498,467,235,127,802,446,233,
544,482,800,318,16,532,801,441,554,173,60,530,713,469,30,
212,630,899,170,266,799,88,49,512,399,23,500,107,524,90,
194,143,135,192,206,345,148,71,119,101,563,870,158,254,214,
276,464,332,725,188,385,24,476,40,231,620,171,258,67,109,
844,244,187,388,701,690,50,7,850,479,48,522,22,154,12,659,
736,655,577,737,830,811,174,21,237,335,353,234,53,270,62,
182,45,177,245,812,673,355,556,612,166,204,54,248,365,226,
242,452,700,685,573,14,842,481,468,781,564,416,179,405,35,
819,608,624,367,98,643,448,2,460,676,440,240,130,146,184,
185,430,65,807,377,82,121,708,239,310,138,596,730,575,477,
851,797,247,27,85,586,307,779,326,494,856,324,827,96,748,
13,397,125,688,702,92,293,716,277,140,112,4,80,855,839,1,
413,347,584,493,289,696,19,751,379,76,73,115,6,590,183,734,
197,483,217,344,330,400,186,243,587,220,780,200,793,246,824,
41,735,579,81,703,322,760,720,139,480,490,91,814,813,163,
152,488,763,263,425,410,576,120,319,668,150,160,302,491,515,
260,145,428,97,251,395,272,252,18,106,358,854,485,144,550,
131,133,378,68,102,104,58,361,275,209,697,582,338,742,589,
325,408,229,28,304,191,189,110,126,486,211,547,533,70,215,
670,249,36,581,389,605,331,518,442,822
};
// used to sort pairs during pairs selection
struct PairStat
{
double mean;
int idx;
};
struct sortMean
{
bool operator()( const PairStat& a, const PairStat& b ) const
{
return a.mean < b.mean;
}
};
void FREAK::buildPattern()
{
if( patternScale == patternScale0 && nOctaves == nOctaves0 && !patternLookup.empty() )
return;
nOctaves0 = nOctaves;
patternScale0 = patternScale;
patternLookup.resize(FREAK_NB_SCALES*FREAK_NB_ORIENTATION*FREAK_NB_POINTS);
double scaleStep = std::pow(2.0, (double)(nOctaves)/FREAK_NB_SCALES ); // 2 ^ ( (nOctaves-1) /nbScales)
double scalingFactor, alpha, beta, theta = 0;
// pattern definition, radius normalized to 1.0 (outer point position+sigma=1.0)
const int n[8] = {6,6,6,6,6,6,6,1}; // number of points on each concentric circle (from outer to inner)
const double bigR(2.0/3.0); // bigger radius
const double smallR(2.0/24.0); // smaller radius
const double unitSpace( (bigR-smallR)/21.0 ); // define spaces between concentric circles (from center to outer: 1,2,3,4,5,6)
// radii of the concentric cirles (from outer to inner)
const double radius[8] = {bigR, bigR-6*unitSpace, bigR-11*unitSpace, bigR-15*unitSpace, bigR-18*unitSpace, bigR-20*unitSpace, smallR, 0.0};
// sigma of pattern points (each group of 6 points on a concentric cirle has the same sigma)
const double sigma[8] = {radius[0]/2.0, radius[1]/2.0, radius[2]/2.0,
radius[3]/2.0, radius[4]/2.0, radius[5]/2.0,
radius[6]/2.0, radius[6]/2.0
};
// fill the lookup table
for( int scaleIdx=0; scaleIdx < FREAK_NB_SCALES; ++scaleIdx )
{
patternSizes[scaleIdx] = 0; // proper initialization
scalingFactor = std::pow(scaleStep,scaleIdx); //scale of the pattern, scaleStep ^ scaleIdx
for( int orientationIdx = 0; orientationIdx < FREAK_NB_ORIENTATION; ++orientationIdx )
{
theta = double(orientationIdx)* 2*CV_PI/double(FREAK_NB_ORIENTATION); // orientation of the pattern
int pointIdx = 0;
PatternPoint* patternLookupPtr = &patternLookup[0];
for( size_t i = 0; i < 8; ++i )
{
for( int k = 0 ; k < n[i]; ++k )
{
beta = CV_PI/n[i] * (i%2); // orientation offset so that groups of points on each circles are staggered
alpha = double(k)* 2*CV_PI/double(n[i])+beta+theta;
// add the point to the look-up table
PatternPoint& point = patternLookupPtr[ scaleIdx*FREAK_NB_ORIENTATION*FREAK_NB_POINTS+orientationIdx*FREAK_NB_POINTS+pointIdx ];
point.x = static_cast<float>(radius[i] * cos(alpha) * scalingFactor * patternScale);
point.y = static_cast<float>(radius[i] * sin(alpha) * scalingFactor * patternScale);
point.sigma = static_cast<float>(sigma[i] * scalingFactor * patternScale);
// adapt the sizeList if necessary
const int sizeMax = static_cast<int>(ceil((radius[i]+sigma[i])*scalingFactor*patternScale)) + 1;
if( patternSizes[scaleIdx] < sizeMax )
patternSizes[scaleIdx] = sizeMax;
++pointIdx;
}
}
}
}
// build the list of orientation pairs
orientationPairs[0].i=0; orientationPairs[0].j=3; orientationPairs[1].i=1; orientationPairs[1].j=4; orientationPairs[2].i=2; orientationPairs[2].j=5;
orientationPairs[3].i=0; orientationPairs[3].j=2; orientationPairs[4].i=1; orientationPairs[4].j=3; orientationPairs[5].i=2; orientationPairs[5].j=4;
orientationPairs[6].i=3; orientationPairs[6].j=5; orientationPairs[7].i=4; orientationPairs[7].j=0; orientationPairs[8].i=5; orientationPairs[8].j=1;
orientationPairs[9].i=6; orientationPairs[9].j=9; orientationPairs[10].i=7; orientationPairs[10].j=10; orientationPairs[11].i=8; orientationPairs[11].j=11;
orientationPairs[12].i=6; orientationPairs[12].j=8; orientationPairs[13].i=7; orientationPairs[13].j=9; orientationPairs[14].i=8; orientationPairs[14].j=10;
orientationPairs[15].i=9; orientationPairs[15].j=11; orientationPairs[16].i=10; orientationPairs[16].j=6; orientationPairs[17].i=11; orientationPairs[17].j=7;
orientationPairs[18].i=12; orientationPairs[18].j=15; orientationPairs[19].i=13; orientationPairs[19].j=16; orientationPairs[20].i=14; orientationPairs[20].j=17;
orientationPairs[21].i=12; orientationPairs[21].j=14; orientationPairs[22].i=13; orientationPairs[22].j=15; orientationPairs[23].i=14; orientationPairs[23].j=16;
orientationPairs[24].i=15; orientationPairs[24].j=17; orientationPairs[25].i=16; orientationPairs[25].j=12; orientationPairs[26].i=17; orientationPairs[26].j=13;
orientationPairs[27].i=18; orientationPairs[27].j=21; orientationPairs[28].i=19; orientationPairs[28].j=22; orientationPairs[29].i=20; orientationPairs[29].j=23;
orientationPairs[30].i=18; orientationPairs[30].j=20; orientationPairs[31].i=19; orientationPairs[31].j=21; orientationPairs[32].i=20; orientationPairs[32].j=22;
orientationPairs[33].i=21; orientationPairs[33].j=23; orientationPairs[34].i=22; orientationPairs[34].j=18; orientationPairs[35].i=23; orientationPairs[35].j=19;
orientationPairs[36].i=24; orientationPairs[36].j=27; orientationPairs[37].i=25; orientationPairs[37].j=28; orientationPairs[38].i=26; orientationPairs[38].j=29;
orientationPairs[39].i=30; orientationPairs[39].j=33; orientationPairs[40].i=31; orientationPairs[40].j=34; orientationPairs[41].i=32; orientationPairs[41].j=35;
orientationPairs[42].i=36; orientationPairs[42].j=39; orientationPairs[43].i=37; orientationPairs[43].j=40; orientationPairs[44].i=38; orientationPairs[44].j=41;
for( unsigned m = FREAK_NB_ORIENPAIRS; m--; )
{
const float dx = patternLookup[orientationPairs[m].i].x-patternLookup[orientationPairs[m].j].x;
const float dy = patternLookup[orientationPairs[m].i].y-patternLookup[orientationPairs[m].j].y;
const float norm_sq = (dx*dx+dy*dy);
orientationPairs[m].weight_dx = int((dx/(norm_sq))*4096.0+0.5);
orientationPairs[m].weight_dy = int((dy/(norm_sq))*4096.0+0.5);
}
// build the list of description pairs
std::vector<DescriptionPair> allPairs;
for( unsigned int i = 1; i < (unsigned int)FREAK_NB_POINTS; ++i )
{
// (generate all the pairs)
for( unsigned int j = 0; (unsigned int)j < i; ++j )
{
DescriptionPair pair = {(uchar)i,(uchar)j};
allPairs.push_back(pair);
}
}
// Input vector provided
if( !selectedPairs0.empty() )
{
if( (int)selectedPairs0.size() == FREAK_NB_PAIRS )
{
for( int i = 0; i < FREAK_NB_PAIRS; ++i )
descriptionPairs[i] = allPairs[selectedPairs0.at(i)];
}
else
{
CV_Error(Error::StsVecLengthErr, "Input vector does not match the required size");
}
}
else // default selected pairs
{
for( int i = 0; i < FREAK_NB_PAIRS; ++i )
descriptionPairs[i] = allPairs[FREAK_DEF_PAIRS[i]];
}
}
void FREAK::computeImpl( InputArray _image, std::vector<KeyPoint>& keypoints, OutputArray _descriptors ) const
{
Mat image = _image.getMat();
if( image.empty() )
return;
if( keypoints.empty() )
return;
((FREAK*)this)->buildPattern();
// Convert to gray if not already
Mat grayImage = image;
// if( image.channels() > 1 )
// cvtColor( image, grayImage, COLOR_BGR2GRAY );
// Use 32-bit integers if we won't overflow in the integral image
if ((image.depth() == CV_8U || image.depth() == CV_8S) &&
(image.rows * image.cols) < 8388608 ) // 8388608 = 2 ^ (32 - 8(bit depth) - 1(sign bit))
{
// Create the integral image appropriate for our type & usage
if (image.depth() == CV_8U)
computeDescriptors<uchar, int>(grayImage, keypoints, _descriptors);
else if (image.depth() == CV_8S)
computeDescriptors<char, int>(grayImage, keypoints, _descriptors);
else
CV_Error( Error::StsUnsupportedFormat, "" );
} else {
// Create the integral image appropriate for our type & usage
if ( image.depth() == CV_8U )
computeDescriptors<uchar, double>(grayImage, keypoints, _descriptors);
else if ( image.depth() == CV_8S )
computeDescriptors<char, double>(grayImage, keypoints, _descriptors);
else if ( image.depth() == CV_16U )
computeDescriptors<ushort, double>(grayImage, keypoints, _descriptors);
else if ( image.depth() == CV_16S )
computeDescriptors<short, double>(grayImage, keypoints, _descriptors);
else
CV_Error( Error::StsUnsupportedFormat, "" );
}
}
template <typename srcMatType>
void FREAK::extractDescriptor(srcMatType *pointsValue, void ** ptr) const
{
std::bitset<FREAK_NB_PAIRS>** ptrScalar = (std::bitset<FREAK_NB_PAIRS>**) ptr;
// extracting descriptor preserving the order of SSE version
int cnt = 0;
for( int n = 7; n < FREAK_NB_PAIRS; n += 128)
{
for( int m = 8; m--; )
{
int nm = n-m;
for(int kk = nm+15*8; kk >= nm; kk-=8, ++cnt)
{
(*ptrScalar)->set(kk, pointsValue[descriptionPairs[cnt].i] >= pointsValue[descriptionPairs[cnt].j]);
}
}
}
--(*ptrScalar);
}
#if CV_SSE2
template <>
void FREAK::extractDescriptor(uchar *pointsValue, void ** ptr) const
{
__m128i** ptrSSE = (__m128i**) ptr;
// note that comparisons order is modified in each block (but first 128 comparisons remain globally the same-->does not affect the 128,384 bits segmanted matching strategy)
int cnt = 0;
for( int n = FREAK_NB_PAIRS/128; n-- ; )
{
__m128i result128 = _mm_setzero_si128();
for( int m = 128/16; m--; cnt += 16 )
{
__m128i operand1 = _mm_set_epi8(pointsValue[descriptionPairs[cnt+0].i],
pointsValue[descriptionPairs[cnt+1].i],
pointsValue[descriptionPairs[cnt+2].i],
pointsValue[descriptionPairs[cnt+3].i],
pointsValue[descriptionPairs[cnt+4].i],
pointsValue[descriptionPairs[cnt+5].i],
pointsValue[descriptionPairs[cnt+6].i],
pointsValue[descriptionPairs[cnt+7].i],
pointsValue[descriptionPairs[cnt+8].i],
pointsValue[descriptionPairs[cnt+9].i],
pointsValue[descriptionPairs[cnt+10].i],
pointsValue[descriptionPairs[cnt+11].i],
pointsValue[descriptionPairs[cnt+12].i],
pointsValue[descriptionPairs[cnt+13].i],
pointsValue[descriptionPairs[cnt+14].i],
pointsValue[descriptionPairs[cnt+15].i]);
__m128i operand2 = _mm_set_epi8(pointsValue[descriptionPairs[cnt+0].j],
pointsValue[descriptionPairs[cnt+1].j],
pointsValue[descriptionPairs[cnt+2].j],
pointsValue[descriptionPairs[cnt+3].j],
pointsValue[descriptionPairs[cnt+4].j],
pointsValue[descriptionPairs[cnt+5].j],
pointsValue[descriptionPairs[cnt+6].j],
pointsValue[descriptionPairs[cnt+7].j],
pointsValue[descriptionPairs[cnt+8].j],
pointsValue[descriptionPairs[cnt+9].j],
pointsValue[descriptionPairs[cnt+10].j],
pointsValue[descriptionPairs[cnt+11].j],
pointsValue[descriptionPairs[cnt+12].j],
pointsValue[descriptionPairs[cnt+13].j],
pointsValue[descriptionPairs[cnt+14].j],
pointsValue[descriptionPairs[cnt+15].j]);
__m128i workReg = _mm_min_epu8(operand1, operand2); // emulated "not less than" for 8-bit UNSIGNED integers
workReg = _mm_cmpeq_epi8(workReg, operand2); // emulated "not less than" for 8-bit UNSIGNED integers
workReg = _mm_and_si128(_mm_set1_epi16(short(0x8080 >> m)), workReg); // merge the last 16 bits with the 128bits std::vector until full
result128 = _mm_or_si128(result128, workReg);
}
(**ptrSSE) = result128;
++(*ptrSSE);
}
(*ptrSSE) -= 8;
}
#endif
template <typename srcMatType, typename iiMatType>
void FREAK::computeDescriptors( InputArray _image, std::vector<KeyPoint>& keypoints, OutputArray _descriptors ) const {
Mat image = _image.getMat();
Mat imgIntegral;
integral(image, imgIntegral, DataType<iiMatType>::type);
std::vector<int> kpScaleIdx(keypoints.size()); // used to save pattern scale index corresponding to each keypoints
const std::vector<int>::iterator ScaleIdxBegin = kpScaleIdx.begin(); // used in std::vector erase function
const std::vector<cv::KeyPoint>::iterator kpBegin = keypoints.begin(); // used in std::vector erase function
const float sizeCst = static_cast<float>(FREAK_NB_SCALES/(FREAK_LOG2* nOctaves));
srcMatType pointsValue[FREAK_NB_POINTS];
int thetaIdx = 0;
int direction0;
int direction1;
// compute the scale index corresponding to the keypoint size and remove keypoints close to the border
if( scaleNormalized )
{
for( size_t k = keypoints.size(); k--; )
{
//Is k non-zero? If so, decrement it and continue"
kpScaleIdx[k] = std::max( (int)(std::log(keypoints[k].size/FREAK_SMALLEST_KP_SIZE)*sizeCst+0.5) ,0);
if( kpScaleIdx[k] >= FREAK_NB_SCALES )
kpScaleIdx[k] = FREAK_NB_SCALES-1;
if( keypoints[k].pt.x <= patternSizes[kpScaleIdx[k]] || //check if the description at this specific position and scale fits inside the image
keypoints[k].pt.y <= patternSizes[kpScaleIdx[k]] ||
keypoints[k].pt.x >= image.cols-patternSizes[kpScaleIdx[k]] ||
keypoints[k].pt.y >= image.rows-patternSizes[kpScaleIdx[k]]
)
{
keypoints.erase(kpBegin+k);
kpScaleIdx.erase(ScaleIdxBegin+k);
}
}
}
else
{
const int scIdx = std::max( (int)(1.0986122886681*sizeCst+0.5) ,0);
for( size_t k = keypoints.size(); k--; )
{
kpScaleIdx[k] = scIdx; // equivalent to the formule when the scale is normalized with a constant size of keypoints[k].size=3*SMALLEST_KP_SIZE
if( kpScaleIdx[k] >= FREAK_NB_SCALES )
{
kpScaleIdx[k] = FREAK_NB_SCALES-1;
}
if( keypoints[k].pt.x <= patternSizes[kpScaleIdx[k]] ||
keypoints[k].pt.y <= patternSizes[kpScaleIdx[k]] ||
keypoints[k].pt.x >= image.cols-patternSizes[kpScaleIdx[k]] ||
keypoints[k].pt.y >= image.rows-patternSizes[kpScaleIdx[k]]
)
{
keypoints.erase(kpBegin+k);
kpScaleIdx.erase(ScaleIdxBegin+k);
}
}
}
// allocate descriptor memory, estimate orientations, extract descriptors
if( !extAll )
{
// extract the best comparisons only
_descriptors.create((int)keypoints.size(), FREAK_NB_PAIRS/8, CV_8U);
_descriptors.setTo(Scalar::all(0));
Mat descriptors = _descriptors.getMat();
void *ptr = descriptors.data+(keypoints.size()-1)*descriptors.step[0];
for( size_t k = keypoints.size(); k--; ) {
// estimate orientation (gradient)
if( !orientationNormalized )
{
thetaIdx = 0; // assign 0° to all keypoints
keypoints[k].angle = 0.0;
}
else
{
// get the points intensity value in the un-rotated pattern
for( int i = FREAK_NB_POINTS; i--; ) {
pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
keypoints[k].pt.x, keypoints[k].pt.y,
kpScaleIdx[k], 0, i);
}
direction0 = 0;
direction1 = 0;
for( int m = 45; m--; )
{
//iterate through the orientation pairs
const int delta = (pointsValue[ orientationPairs[m].i ]-pointsValue[ orientationPairs[m].j ]);
direction0 += delta*(orientationPairs[m].weight_dx)/2048;
direction1 += delta*(orientationPairs[m].weight_dy)/2048;
}
keypoints[k].angle = static_cast<float>(atan2((float)direction1,(float)direction0)*(180.0/CV_PI));//estimate orientation
thetaIdx = int(FREAK_NB_ORIENTATION*keypoints[k].angle*(1/360.0)+0.5);
if( thetaIdx < 0 )
thetaIdx += FREAK_NB_ORIENTATION;
if( thetaIdx >= FREAK_NB_ORIENTATION )
thetaIdx -= FREAK_NB_ORIENTATION;
}
// extract descriptor at the computed orientation
for( int i = FREAK_NB_POINTS; i--; ) {
pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
keypoints[k].pt.x, keypoints[k].pt.y,
kpScaleIdx[k], thetaIdx, i);
}
// Extract descriptor
extractDescriptor<srcMatType>(pointsValue, &ptr);
}
}
else // extract all possible comparisons for selection
{
_descriptors.create((int)keypoints.size(), 128, CV_8U);
_descriptors.setTo(Scalar::all(0));
Mat descriptors = _descriptors.getMat();
std::bitset<1024>* ptr = (std::bitset<1024>*) (descriptors.data+(keypoints.size()-1)*descriptors.step[0]);
for( size_t k = keypoints.size(); k--; )
{
//estimate orientation (gradient)
if( !orientationNormalized )
{
thetaIdx = 0;//assign 0° to all keypoints
keypoints[k].angle = 0.0;
}
else
{
//get the points intensity value in the un-rotated pattern
for( int i = FREAK_NB_POINTS;i--; )
pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
keypoints[k].pt.x,keypoints[k].pt.y,
kpScaleIdx[k], 0, i);
direction0 = 0;
direction1 = 0;
for( int m = 45; m--; )
{
//iterate through the orientation pairs
const int delta = (pointsValue[ orientationPairs[m].i ]-pointsValue[ orientationPairs[m].j ]);
direction0 += delta*(orientationPairs[m].weight_dx)/2048;
direction1 += delta*(orientationPairs[m].weight_dy)/2048;
}
keypoints[k].angle = static_cast<float>(atan2((float)direction1,(float)direction0)*(180.0/CV_PI)); //estimate orientation
thetaIdx = int(FREAK_NB_ORIENTATION*keypoints[k].angle*(1/360.0)+0.5);
if( thetaIdx < 0 )
thetaIdx += FREAK_NB_ORIENTATION;
if( thetaIdx >= FREAK_NB_ORIENTATION )
thetaIdx -= FREAK_NB_ORIENTATION;
}
// get the points intensity value in the rotated pattern
for( int i = FREAK_NB_POINTS; i--; ) {
pointsValue[i] = meanIntensity<srcMatType, iiMatType>(image, imgIntegral,
keypoints[k].pt.x, keypoints[k].pt.y,
kpScaleIdx[k], thetaIdx, i);
}
int cnt(0);
for( int i = 1; i < FREAK_NB_POINTS; ++i )
{
//(generate all the pairs)
for( int j = 0; j < i; ++j )
{
ptr->set(cnt, pointsValue[i] >= pointsValue[j] );
++cnt;
}
}
--ptr;
}
}
}
// simply take average on a square patch, not even gaussian approx
template <typename imgType, typename iiType>
imgType FREAK::meanIntensity( InputArray _image, InputArray _integral,
const float kp_x,
const float kp_y,
const unsigned int scale,
const unsigned int rot,
const unsigned int point) const {
Mat image = _image.getMat(), integral = _integral.getMat();
// get point position in image
const PatternPoint& FreakPoint = patternLookup[scale*FREAK_NB_ORIENTATION*FREAK_NB_POINTS + rot*FREAK_NB_POINTS + point];
const float xf = FreakPoint.x+kp_x;
const float yf = FreakPoint.y+kp_y;
const int x = int(xf);
const int y = int(yf);
// get the sigma:
const float radius = FreakPoint.sigma;
// calculate output:
if( radius < 0.5 )
{
// interpolation multipliers:
const int r_x = static_cast<int>((xf-x)*1024);
const int r_y = static_cast<int>((yf-y)*1024);
const int r_x_1 = (1024-r_x);
const int r_y_1 = (1024-r_y);
unsigned int ret_val;
// linear interpolation:
ret_val = r_x_1*r_y_1*int(image.at<imgType>(y , x ))
+ r_x *r_y_1*int(image.at<imgType>(y , x+1))
+ r_x_1*r_y *int(image.at<imgType>(y+1, x ))
+ r_x *r_y *int(image.at<imgType>(y+1, x+1));
//return the rounded mean
ret_val += 2 * 1024 * 1024;
return static_cast<imgType>(ret_val / (4 * 1024 * 1024));
}
// expected case:
// calculate borders
const int x_left = int(xf-radius+0.5);
const int y_top = int(yf-radius+0.5);
const int x_right = int(xf+radius+1.5);//integral image is 1px wider
const int y_bottom = int(yf+radius+1.5);//integral image is 1px higher
iiType ret_val;
ret_val = integral.at<iiType>(y_bottom,x_right);//bottom right corner
ret_val -= integral.at<iiType>(y_bottom,x_left);
ret_val += integral.at<iiType>(y_top,x_left);
ret_val -= integral.at<iiType>(y_top,x_right);
ret_val = ret_val/( (x_right-x_left)* (y_bottom-y_top) );
//~ std::cout<<integral.step[1]<<std::endl;
return static_cast<imgType>(ret_val);
}
// pair selection algorithm from a set of training images and corresponding keypoints
std::vector<int> FREAK::selectPairs(const std::vector<Mat>& images
, std::vector<std::vector<KeyPoint> >& keypoints
, const double corrTresh
, bool verbose )
{
extAll = true;
// compute descriptors with all pairs
Mat descriptors;
if( verbose )
std::cout << "Number of images: " << images.size() << std::endl;
for( size_t i = 0;i < images.size(); ++i )
{
Mat descriptorsTmp;
computeImpl(images[i],keypoints[i],descriptorsTmp);
descriptors.push_back(descriptorsTmp);
}
if( verbose )
std::cout << "number of keypoints: " << descriptors.rows << std::endl;
//descriptor in floating point format (each bit is a float)
Mat descriptorsFloat = Mat::zeros(descriptors.rows, 903, CV_32F);
std::bitset<1024>* ptr = (std::bitset<1024>*) (descriptors.data+(descriptors.rows-1)*descriptors.step[0]);
for( int m = descriptors.rows; m--; )
{
for( int n = 903; n--; )
{
if( ptr->test(n) == true )
descriptorsFloat.at<float>(m,n)=1.0f;
}
--ptr;
}
std::vector<PairStat> pairStat;
for( int n = 903; n--; )
{
// the higher the variance, the better --> mean = 0.5
PairStat tmp = { fabs( mean(descriptorsFloat.col(n))[0]-0.5 ) ,n};
pairStat.push_back(tmp);
}
std::sort( pairStat.begin(),pairStat.end(), sortMean() );
std::vector<PairStat> bestPairs;
for( int m = 0; m < 903; ++m )
{
if( verbose )
std::cout << m << ":" << bestPairs.size() << " " << std::flush;
double corrMax(0);
for( size_t n = 0; n < bestPairs.size(); ++n )
{
int idxA = bestPairs[n].idx;
int idxB = pairStat[m].idx;
double corr(0);
// compute correlation between 2 pairs
corr = fabs(compareHist(descriptorsFloat.col(idxA), descriptorsFloat.col(idxB), HISTCMP_CORREL));
if( corr > corrMax )
{
corrMax = corr;
if( corrMax >= corrTresh )
break;
}
}
if( corrMax < corrTresh/*0.7*/ )
bestPairs.push_back(pairStat[m]);
if( bestPairs.size() >= 512 )
{
if( verbose )
std::cout << m << std::endl;
break;
}
}
std::vector<int> idxBestPairs;
if( (int)bestPairs.size() >= FREAK_NB_PAIRS )
{
for( int i = 0; i < FREAK_NB_PAIRS; ++i )
idxBestPairs.push_back(bestPairs[i].idx);
}
else
{
if( verbose )
std::cout << "correlation threshold too small (restrictive)" << std::endl;
CV_Error(Error::StsError, "correlation threshold too small (restrictive)");
}
extAll = false;
return idxBestPairs;
}
/*
// create an image showing the brisk pattern
void FREAKImpl::drawPattern()
{
Mat pattern = Mat::zeros(1000, 1000, CV_8UC3) + Scalar(255,255,255);
int sFac = 500 / patternScale;
for( int n = 0; n < kNB_POINTS; ++n )
{
PatternPoint& pt = patternLookup[n];
circle(pattern, Point( pt.x*sFac,pt.y*sFac)+Point(500,500), pt.sigma*sFac, Scalar(0,0,255),2);
// rectangle(pattern, Point( (pt.x-pt.sigma)*sFac,(pt.y-pt.sigma)*sFac)+Point(500,500), Point( (pt.x+pt.sigma)*sFac,(pt.y+pt.sigma)*sFac)+Point(500,500), Scalar(0,0,255),2);
circle(pattern, Point( pt.x*sFac,pt.y*sFac)+Point(500,500), 1, Scalar(0,0,0),3);
std::ostringstream oss;
oss << n;
putText( pattern, oss.str(), Point( pt.x*sFac,pt.y*sFac)+Point(500,500), FONT_HERSHEY_SIMPLEX,0.5, Scalar(0,0,0), 1);
}
imshow( "FreakDescriptorExtractor pattern", pattern );
waitKey(0);
}
*/
// -------------------------------------------------
/* FREAK interface implementation */
FREAK::FREAK( bool _orientationNormalized, bool _scaleNormalized
, float _patternScale, int _nOctaves, const std::vector<int>& _selectedPairs )
: orientationNormalized(_orientationNormalized), scaleNormalized(_scaleNormalized),
patternScale(_patternScale), nOctaves(_nOctaves), extAll(false), nOctaves0(0), selectedPairs0(_selectedPairs)
{
}
FREAK::~FREAK()
{
}
int FREAK::descriptorSize() const
{
return FREAK_NB_PAIRS / 8; // descriptor length in bytes
}
int FREAK::descriptorType() const
{
return CV_8U;
}
int FREAK::defaultNorm() const
{
return NORM_HAMMING;
}
} // END NAMESPACE CV

@ -1,19 +0,0 @@
// Code generated with '$ scripts/generate_code.py src/test_pairs.txt 16'
#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x)
desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0));
desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0));
desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0));
desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0));
desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0));
desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0));
desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0));
desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0));
desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0));
desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0));
desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0));
desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0));
desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0));
desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0));
desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0));
desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0));
#undef SMOOTHED

@ -1,35 +0,0 @@
// Code generated with '$ scripts/generate_code.py src/test_pairs.txt 32'
#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x)
desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0));
desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0));
desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0));
desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0));
desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0));
desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0));
desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0));
desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0));
desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0));
desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0));
desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0));
desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0));
desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0));
desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0));
desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0));
desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0));
desc[16] = (uchar)(((SMOOTHED(-9, 1) < SMOOTHED(-18, 0)) << 7) + ((SMOOTHED(4, 0) < SMOOTHED(1, 12)) << 6) + ((SMOOTHED(0, 9) < SMOOTHED(-14, -10)) << 5) + ((SMOOTHED(-13, -9) < SMOOTHED(-2, 6)) << 4) + ((SMOOTHED(1, 5) < SMOOTHED(10, 10)) << 3) + ((SMOOTHED(-3, -6) < SMOOTHED(-16, -5)) << 2) + ((SMOOTHED(11, 6) < SMOOTHED(-5, 0)) << 1) + ((SMOOTHED(-23, 10) < SMOOTHED(1, 2)) << 0));
desc[17] = (uchar)(((SMOOTHED(13, -5) < SMOOTHED(-3, 9)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-13, -5)) << 6) + ((SMOOTHED(10, 13) < SMOOTHED(-11, 8)) << 5) + ((SMOOTHED(19, 20) < SMOOTHED(-9, 2)) << 4) + ((SMOOTHED(4, -8) < SMOOTHED(0, -9)) << 3) + ((SMOOTHED(-14, 10) < SMOOTHED(15, 19)) << 2) + ((SMOOTHED(-14, -12) < SMOOTHED(-10, -3)) << 1) + ((SMOOTHED(-23, -3) < SMOOTHED(17, -2)) << 0));
desc[18] = (uchar)(((SMOOTHED(-3, -11) < SMOOTHED(6, -14)) << 7) + ((SMOOTHED(19, -2) < SMOOTHED(-4, 2)) << 6) + ((SMOOTHED(-5, 5) < SMOOTHED(3, -13)) << 5) + ((SMOOTHED(2, -2) < SMOOTHED(-5, 4)) << 4) + ((SMOOTHED(17, 4) < SMOOTHED(17, -11)) << 3) + ((SMOOTHED(-7, -2) < SMOOTHED(1, 23)) << 2) + ((SMOOTHED(8, 13) < SMOOTHED(1, -16)) << 1) + ((SMOOTHED(-13, -5) < SMOOTHED(1, -17)) << 0));
desc[19] = (uchar)(((SMOOTHED(4, 6) < SMOOTHED(-8, -3)) << 7) + ((SMOOTHED(-5, -9) < SMOOTHED(-2, -10)) << 6) + ((SMOOTHED(-9, 0) < SMOOTHED(-7, -2)) << 5) + ((SMOOTHED(5, 0) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-4, -16) < SMOOTHED(6, 3)) << 3) + ((SMOOTHED(2, -15) < SMOOTHED(-2, 12)) << 2) + ((SMOOTHED(4, -1) < SMOOTHED(6, 2)) << 1) + ((SMOOTHED(1, 1) < SMOOTHED(-2, -8)) << 0));
desc[20] = (uchar)(((SMOOTHED(-2, 12) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, 8) < SMOOTHED(-9, 9)) << 6) + ((SMOOTHED(2, -10) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-4, 10) < SMOOTHED(-9, 4)) << 4) + ((SMOOTHED(6, 12) < SMOOTHED(2, 5)) << 3) + ((SMOOTHED(-3, -8) < SMOOTHED(0, 5)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-7, 2)) << 1) + ((SMOOTHED(-1, -10) < SMOOTHED(7, -18)) << 0));
desc[21] = (uchar)(((SMOOTHED(-1, 8) < SMOOTHED(-9, -10)) << 7) + ((SMOOTHED(-23, -1) < SMOOTHED(6, 2)) << 6) + ((SMOOTHED(-5, -3) < SMOOTHED(3, 2)) << 5) + ((SMOOTHED(0, 11) < SMOOTHED(-4, -7)) << 4) + ((SMOOTHED(15, 2) < SMOOTHED(-10, -3)) << 3) + ((SMOOTHED(-20, -8) < SMOOTHED(-13, 3)) << 2) + ((SMOOTHED(-19, -12) < SMOOTHED(5, -11)) << 1) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 0));
desc[22] = (uchar)(((SMOOTHED(7, 4) < SMOOTHED(-12, 0)) << 7) + ((SMOOTHED(5, -1) < SMOOTHED(-14, -6)) << 6) + ((SMOOTHED(-4, 11) < SMOOTHED(0, -4)) << 5) + ((SMOOTHED(3, 10) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(13, 21) < SMOOTHED(-11, 6)) << 3) + ((SMOOTHED(-12, 24) < SMOOTHED(-7, -4)) << 2) + ((SMOOTHED(4, 16) < SMOOTHED(3, -14)) << 1) + ((SMOOTHED(-3, 5) < SMOOTHED(-7, -12)) << 0));
desc[23] = (uchar)(((SMOOTHED(0, -4) < SMOOTHED(7, -5)) << 7) + ((SMOOTHED(-17, -9) < SMOOTHED(13, -7)) << 6) + ((SMOOTHED(22, -6) < SMOOTHED(-11, 5)) << 5) + ((SMOOTHED(2, -8) < SMOOTHED(23, -11)) << 4) + ((SMOOTHED(7, -10) < SMOOTHED(-1, 14)) << 3) + ((SMOOTHED(-3, -10) < SMOOTHED(8, 3)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-6, 0)) << 1) + ((SMOOTHED(-7, -21) < SMOOTHED(6, -14)) << 0));
desc[24] = (uchar)(((SMOOTHED(18, 19) < SMOOTHED(-4, -6)) << 7) + ((SMOOTHED(10, 7) < SMOOTHED(-1, -4)) << 6) + ((SMOOTHED(-1, 21) < SMOOTHED(1, -5)) << 5) + ((SMOOTHED(-10, 6) < SMOOTHED(-11, -2)) << 4) + ((SMOOTHED(18, -3) < SMOOTHED(-1, 7)) << 3) + ((SMOOTHED(-3, -9) < SMOOTHED(-5, 10)) << 2) + ((SMOOTHED(-13, 14) < SMOOTHED(17, -3)) << 1) + ((SMOOTHED(11, -19) < SMOOTHED(-1, -18)) << 0));
desc[25] = (uchar)(((SMOOTHED(8, -2) < SMOOTHED(-18, -23)) << 7) + ((SMOOTHED(0, -5) < SMOOTHED(-2, -9)) << 6) + ((SMOOTHED(-4, -11) < SMOOTHED(2, -8)) << 5) + ((SMOOTHED(14, 6) < SMOOTHED(-3, -6)) << 4) + ((SMOOTHED(-3, 0) < SMOOTHED(-15, 0)) << 3) + ((SMOOTHED(-9, 4) < SMOOTHED(-15, -9)) << 2) + ((SMOOTHED(-1, 11) < SMOOTHED(3, 11)) << 1) + ((SMOOTHED(-10, -16) < SMOOTHED(-7, 7)) << 0));
desc[26] = (uchar)(((SMOOTHED(-2, -10) < SMOOTHED(-10, -2)) << 7) + ((SMOOTHED(-5, -3) < SMOOTHED(5, -23)) << 6) + ((SMOOTHED(13, -8) < SMOOTHED(-15, -11)) << 5) + ((SMOOTHED(-15, 11) < SMOOTHED(6, -6)) << 4) + ((SMOOTHED(-16, -3) < SMOOTHED(-2, 2)) << 3) + ((SMOOTHED(6, 12) < SMOOTHED(-16, 24)) << 2) + ((SMOOTHED(-10, 0) < SMOOTHED(8, 11)) << 1) + ((SMOOTHED(-7, 7) < SMOOTHED(-19, -7)) << 0));
desc[27] = (uchar)(((SMOOTHED(5, 16) < SMOOTHED(9, -3)) << 7) + ((SMOOTHED(9, 7) < SMOOTHED(-7, -16)) << 6) + ((SMOOTHED(3, 2) < SMOOTHED(-10, 9)) << 5) + ((SMOOTHED(21, 1) < SMOOTHED(8, 7)) << 4) + ((SMOOTHED(7, 0) < SMOOTHED(1, 17)) << 3) + ((SMOOTHED(-8, 12) < SMOOTHED(9, 6)) << 2) + ((SMOOTHED(11, -7) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(19, 0) < SMOOTHED(9, 3)) << 0));
desc[28] = (uchar)(((SMOOTHED(1, -7) < SMOOTHED(-5, -11)) << 7) + ((SMOOTHED(0, 8) < SMOOTHED(-2, 14)) << 6) + ((SMOOTHED(12, -2) < SMOOTHED(-15, -6)) << 5) + ((SMOOTHED(4, 12) < SMOOTHED(0, -21)) << 4) + ((SMOOTHED(17, -4) < SMOOTHED(-6, -7)) << 3) + ((SMOOTHED(-10, -9) < SMOOTHED(-14, -7)) << 2) + ((SMOOTHED(-15, -10) < SMOOTHED(-15, -14)) << 1) + ((SMOOTHED(-7, -5) < SMOOTHED(5, -12)) << 0));
desc[29] = (uchar)(((SMOOTHED(-4, 0) < SMOOTHED(15, -4)) << 7) + ((SMOOTHED(5, 2) < SMOOTHED(-6, -23)) << 6) + ((SMOOTHED(-4, -21) < SMOOTHED(-6, 4)) << 5) + ((SMOOTHED(-10, 5) < SMOOTHED(-15, 6)) << 4) + ((SMOOTHED(4, -3) < SMOOTHED(-1, 5)) << 3) + ((SMOOTHED(-4, 19) < SMOOTHED(-23, -4)) << 2) + ((SMOOTHED(-4, 17) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(1, 12) < SMOOTHED(4, -14)) << 0));
desc[30] = (uchar)(((SMOOTHED(-11, -6) < SMOOTHED(-20, 10)) << 7) + ((SMOOTHED(4, 5) < SMOOTHED(3, 20)) << 6) + ((SMOOTHED(-8, -20) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-19, 9) < SMOOTHED(9, -3)) << 4) + ((SMOOTHED(18, 15) < SMOOTHED(11, -4)) << 3) + ((SMOOTHED(12, 16) < SMOOTHED(8, 7)) << 2) + ((SMOOTHED(-14, -8) < SMOOTHED(-3, 9)) << 1) + ((SMOOTHED(-6, 0) < SMOOTHED(2, -4)) << 0));
desc[31] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-1, 2)) << 7) + ((SMOOTHED(8, -7) < SMOOTHED(-6, 18)) << 6) + ((SMOOTHED(9, 12) < SMOOTHED(-7, -23)) << 5) + ((SMOOTHED(8, -6) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-9, 6) < SMOOTHED(-12, -7)) << 3) + ((SMOOTHED(-1, -2) < SMOOTHED(-7, 2)) << 2) + ((SMOOTHED(9, 9) < SMOOTHED(7, 15)) << 1) + ((SMOOTHED(6, 2) < SMOOTHED(-6, 6)) << 0));
#undef SMOOTHED

@ -1,67 +0,0 @@
// Code generated with '$ scripts/generate_code.py src/test_pairs.txt 64'
#define SMOOTHED(y,x) smoothedSum(sum, pt, y, x)
desc[0] = (uchar)(((SMOOTHED(-2, -1) < SMOOTHED(7, -1)) << 7) + ((SMOOTHED(-14, -1) < SMOOTHED(-3, 3)) << 6) + ((SMOOTHED(1, -2) < SMOOTHED(11, 2)) << 5) + ((SMOOTHED(1, 6) < SMOOTHED(-10, -7)) << 4) + ((SMOOTHED(13, 2) < SMOOTHED(-1, 0)) << 3) + ((SMOOTHED(-14, 5) < SMOOTHED(5, -3)) << 2) + ((SMOOTHED(-2, 8) < SMOOTHED(2, 4)) << 1) + ((SMOOTHED(-11, 8) < SMOOTHED(-15, 5)) << 0));
desc[1] = (uchar)(((SMOOTHED(-6, -23) < SMOOTHED(8, -9)) << 7) + ((SMOOTHED(-12, 6) < SMOOTHED(-10, 8)) << 6) + ((SMOOTHED(-3, -1) < SMOOTHED(8, 1)) << 5) + ((SMOOTHED(3, 6) < SMOOTHED(5, 6)) << 4) + ((SMOOTHED(-7, -6) < SMOOTHED(5, -5)) << 3) + ((SMOOTHED(22, -2) < SMOOTHED(-11, -8)) << 2) + ((SMOOTHED(14, 7) < SMOOTHED(8, 5)) << 1) + ((SMOOTHED(-1, 14) < SMOOTHED(-5, -14)) << 0));
desc[2] = (uchar)(((SMOOTHED(-14, 9) < SMOOTHED(2, 0)) << 7) + ((SMOOTHED(7, -3) < SMOOTHED(22, 6)) << 6) + ((SMOOTHED(-6, 6) < SMOOTHED(-8, -5)) << 5) + ((SMOOTHED(-5, 9) < SMOOTHED(7, -1)) << 4) + ((SMOOTHED(-3, -7) < SMOOTHED(-10, -18)) << 3) + ((SMOOTHED(4, -5) < SMOOTHED(0, 11)) << 2) + ((SMOOTHED(2, 3) < SMOOTHED(9, 10)) << 1) + ((SMOOTHED(-10, 3) < SMOOTHED(4, 9)) << 0));
desc[3] = (uchar)(((SMOOTHED(0, 12) < SMOOTHED(-3, 19)) << 7) + ((SMOOTHED(1, 15) < SMOOTHED(-11, -5)) << 6) + ((SMOOTHED(14, -1) < SMOOTHED(7, 8)) << 5) + ((SMOOTHED(7, -23) < SMOOTHED(-5, 5)) << 4) + ((SMOOTHED(0, -6) < SMOOTHED(-10, 17)) << 3) + ((SMOOTHED(13, -4) < SMOOTHED(-3, -4)) << 2) + ((SMOOTHED(-12, 1) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(0, 8) < SMOOTHED(3, 22)) << 0));
desc[4] = (uchar)(((SMOOTHED(-13, 13) < SMOOTHED(3, -1)) << 7) + ((SMOOTHED(-16, 17) < SMOOTHED(6, 10)) << 6) + ((SMOOTHED(7, 15) < SMOOTHED(-5, 0)) << 5) + ((SMOOTHED(2, -12) < SMOOTHED(19, -2)) << 4) + ((SMOOTHED(3, -6) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(8, 3) < SMOOTHED(0, 14)) << 2) + ((SMOOTHED(4, -11) < SMOOTHED(5, 5)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(7, 1)) << 0));
desc[5] = (uchar)(((SMOOTHED(6, 12) < SMOOTHED(21, 3)) << 7) + ((SMOOTHED(-3, 2) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(5, 1) < SMOOTHED(-5, 11)) << 5) + ((SMOOTHED(3, -17) < SMOOTHED(-6, 2)) << 4) + ((SMOOTHED(6, 8) < SMOOTHED(5, -10)) << 3) + ((SMOOTHED(-14, -2) < SMOOTHED(0, 4)) << 2) + ((SMOOTHED(5, -7) < SMOOTHED(-6, 5)) << 1) + ((SMOOTHED(10, 4) < SMOOTHED(4, -7)) << 0));
desc[6] = (uchar)(((SMOOTHED(22, 0) < SMOOTHED(7, -18)) << 7) + ((SMOOTHED(-1, -3) < SMOOTHED(0, 18)) << 6) + ((SMOOTHED(-4, 22) < SMOOTHED(-5, 3)) << 5) + ((SMOOTHED(1, -7) < SMOOTHED(2, -3)) << 4) + ((SMOOTHED(19, -20) < SMOOTHED(17, -2)) << 3) + ((SMOOTHED(3, -10) < SMOOTHED(-8, 24)) << 2) + ((SMOOTHED(-5, -14) < SMOOTHED(7, 5)) << 1) + ((SMOOTHED(-2, 12) < SMOOTHED(-4, -15)) << 0));
desc[7] = (uchar)(((SMOOTHED(4, 12) < SMOOTHED(0, -19)) << 7) + ((SMOOTHED(20, 13) < SMOOTHED(3, 5)) << 6) + ((SMOOTHED(-8, -12) < SMOOTHED(5, 0)) << 5) + ((SMOOTHED(-5, 6) < SMOOTHED(-7, -11)) << 4) + ((SMOOTHED(6, -11) < SMOOTHED(-3, -22)) << 3) + ((SMOOTHED(15, 4) < SMOOTHED(10, 1)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(15, -6)) << 1) + ((SMOOTHED(5, 10) < SMOOTHED(0, 24)) << 0));
desc[8] = (uchar)(((SMOOTHED(3, 6) < SMOOTHED(22, -2)) << 7) + ((SMOOTHED(-13, 14) < SMOOTHED(4, -4)) << 6) + ((SMOOTHED(-13, 8) < SMOOTHED(-18, -22)) << 5) + ((SMOOTHED(-1, -1) < SMOOTHED(-7, 3)) << 4) + ((SMOOTHED(-19, -12) < SMOOTHED(4, 3)) << 3) + ((SMOOTHED(8, 10) < SMOOTHED(13, -2)) << 2) + ((SMOOTHED(-6, -1) < SMOOTHED(-6, -5)) << 1) + ((SMOOTHED(2, -21) < SMOOTHED(-3, 2)) << 0));
desc[9] = (uchar)(((SMOOTHED(4, -7) < SMOOTHED(0, 16)) << 7) + ((SMOOTHED(-6, -5) < SMOOTHED(-12, -1)) << 6) + ((SMOOTHED(1, -1) < SMOOTHED(9, 18)) << 5) + ((SMOOTHED(-7, 10) < SMOOTHED(-11, 6)) << 4) + ((SMOOTHED(4, 3) < SMOOTHED(19, -7)) << 3) + ((SMOOTHED(-18, 5) < SMOOTHED(-4, 5)) << 2) + ((SMOOTHED(4, 0) < SMOOTHED(-20, 4)) << 1) + ((SMOOTHED(7, -11) < SMOOTHED(18, 12)) << 0));
desc[10] = (uchar)(((SMOOTHED(-20, 17) < SMOOTHED(-18, 7)) << 7) + ((SMOOTHED(2, 15) < SMOOTHED(19, -11)) << 6) + ((SMOOTHED(-18, 6) < SMOOTHED(-7, 3)) << 5) + ((SMOOTHED(-4, 1) < SMOOTHED(-14, 13)) << 4) + ((SMOOTHED(17, 3) < SMOOTHED(2, -8)) << 3) + ((SMOOTHED(-7, 2) < SMOOTHED(1, 6)) << 2) + ((SMOOTHED(17, -9) < SMOOTHED(-2, 8)) << 1) + ((SMOOTHED(-8, -6) < SMOOTHED(-1, 12)) << 0));
desc[11] = (uchar)(((SMOOTHED(-2, 4) < SMOOTHED(-1, 6)) << 7) + ((SMOOTHED(-2, 7) < SMOOTHED(6, 8)) << 6) + ((SMOOTHED(-8, -1) < SMOOTHED(-7, -9)) << 5) + ((SMOOTHED(8, -9) < SMOOTHED(15, 0)) << 4) + ((SMOOTHED(0, 22) < SMOOTHED(-4, -15)) << 3) + ((SMOOTHED(-14, -1) < SMOOTHED(3, -2)) << 2) + ((SMOOTHED(-7, -4) < SMOOTHED(17, -7)) << 1) + ((SMOOTHED(-8, -2) < SMOOTHED(9, -4)) << 0));
desc[12] = (uchar)(((SMOOTHED(5, -7) < SMOOTHED(7, 7)) << 7) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 11)) << 6) + ((SMOOTHED(11, -4) < SMOOTHED(0, 8)) << 5) + ((SMOOTHED(5, -11) < SMOOTHED(-9, -6)) << 4) + ((SMOOTHED(2, -6) < SMOOTHED(3, -20)) << 3) + ((SMOOTHED(-6, 2) < SMOOTHED(6, 10)) << 2) + ((SMOOTHED(-6, -6) < SMOOTHED(-15, 7)) << 1) + ((SMOOTHED(-6, -3) < SMOOTHED(2, 1)) << 0));
desc[13] = (uchar)(((SMOOTHED(11, 0) < SMOOTHED(-3, 2)) << 7) + ((SMOOTHED(7, -12) < SMOOTHED(14, 5)) << 6) + ((SMOOTHED(0, -7) < SMOOTHED(-1, -1)) << 5) + ((SMOOTHED(-16, 0) < SMOOTHED(6, 8)) << 4) + ((SMOOTHED(22, 11) < SMOOTHED(0, -3)) << 3) + ((SMOOTHED(19, 0) < SMOOTHED(5, -17)) << 2) + ((SMOOTHED(-23, -14) < SMOOTHED(-13, -19)) << 1) + ((SMOOTHED(-8, 10) < SMOOTHED(-11, -2)) << 0));
desc[14] = (uchar)(((SMOOTHED(-11, 6) < SMOOTHED(-10, 13)) << 7) + ((SMOOTHED(1, -7) < SMOOTHED(14, 0)) << 6) + ((SMOOTHED(-12, 1) < SMOOTHED(-5, -5)) << 5) + ((SMOOTHED(4, 7) < SMOOTHED(8, -1)) << 4) + ((SMOOTHED(-1, -5) < SMOOTHED(15, 2)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(7, -10)) << 2) + ((SMOOTHED(3, -6) < SMOOTHED(10, -18)) << 1) + ((SMOOTHED(-7, -13) < SMOOTHED(-13, 10)) << 0));
desc[15] = (uchar)(((SMOOTHED(1, -1) < SMOOTHED(13, -10)) << 7) + ((SMOOTHED(-19, 14) < SMOOTHED(8, -14)) << 6) + ((SMOOTHED(-4, -13) < SMOOTHED(7, 1)) << 5) + ((SMOOTHED(1, -2) < SMOOTHED(12, -7)) << 4) + ((SMOOTHED(3, -5) < SMOOTHED(1, -5)) << 3) + ((SMOOTHED(-2, -2) < SMOOTHED(8, -10)) << 2) + ((SMOOTHED(2, 14) < SMOOTHED(8, 7)) << 1) + ((SMOOTHED(3, 9) < SMOOTHED(8, 2)) << 0));
desc[16] = (uchar)(((SMOOTHED(-9, 1) < SMOOTHED(-18, 0)) << 7) + ((SMOOTHED(4, 0) < SMOOTHED(1, 12)) << 6) + ((SMOOTHED(0, 9) < SMOOTHED(-14, -10)) << 5) + ((SMOOTHED(-13, -9) < SMOOTHED(-2, 6)) << 4) + ((SMOOTHED(1, 5) < SMOOTHED(10, 10)) << 3) + ((SMOOTHED(-3, -6) < SMOOTHED(-16, -5)) << 2) + ((SMOOTHED(11, 6) < SMOOTHED(-5, 0)) << 1) + ((SMOOTHED(-23, 10) < SMOOTHED(1, 2)) << 0));
desc[17] = (uchar)(((SMOOTHED(13, -5) < SMOOTHED(-3, 9)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-13, -5)) << 6) + ((SMOOTHED(10, 13) < SMOOTHED(-11, 8)) << 5) + ((SMOOTHED(19, 20) < SMOOTHED(-9, 2)) << 4) + ((SMOOTHED(4, -8) < SMOOTHED(0, -9)) << 3) + ((SMOOTHED(-14, 10) < SMOOTHED(15, 19)) << 2) + ((SMOOTHED(-14, -12) < SMOOTHED(-10, -3)) << 1) + ((SMOOTHED(-23, -3) < SMOOTHED(17, -2)) << 0));
desc[18] = (uchar)(((SMOOTHED(-3, -11) < SMOOTHED(6, -14)) << 7) + ((SMOOTHED(19, -2) < SMOOTHED(-4, 2)) << 6) + ((SMOOTHED(-5, 5) < SMOOTHED(3, -13)) << 5) + ((SMOOTHED(2, -2) < SMOOTHED(-5, 4)) << 4) + ((SMOOTHED(17, 4) < SMOOTHED(17, -11)) << 3) + ((SMOOTHED(-7, -2) < SMOOTHED(1, 23)) << 2) + ((SMOOTHED(8, 13) < SMOOTHED(1, -16)) << 1) + ((SMOOTHED(-13, -5) < SMOOTHED(1, -17)) << 0));
desc[19] = (uchar)(((SMOOTHED(4, 6) < SMOOTHED(-8, -3)) << 7) + ((SMOOTHED(-5, -9) < SMOOTHED(-2, -10)) << 6) + ((SMOOTHED(-9, 0) < SMOOTHED(-7, -2)) << 5) + ((SMOOTHED(5, 0) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-4, -16) < SMOOTHED(6, 3)) << 3) + ((SMOOTHED(2, -15) < SMOOTHED(-2, 12)) << 2) + ((SMOOTHED(4, -1) < SMOOTHED(6, 2)) << 1) + ((SMOOTHED(1, 1) < SMOOTHED(-2, -8)) << 0));
desc[20] = (uchar)(((SMOOTHED(-2, 12) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, 8) < SMOOTHED(-9, 9)) << 6) + ((SMOOTHED(2, -10) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-4, 10) < SMOOTHED(-9, 4)) << 4) + ((SMOOTHED(6, 12) < SMOOTHED(2, 5)) << 3) + ((SMOOTHED(-3, -8) < SMOOTHED(0, 5)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-7, 2)) << 1) + ((SMOOTHED(-1, -10) < SMOOTHED(7, -18)) << 0));
desc[21] = (uchar)(((SMOOTHED(-1, 8) < SMOOTHED(-9, -10)) << 7) + ((SMOOTHED(-23, -1) < SMOOTHED(6, 2)) << 6) + ((SMOOTHED(-5, -3) < SMOOTHED(3, 2)) << 5) + ((SMOOTHED(0, 11) < SMOOTHED(-4, -7)) << 4) + ((SMOOTHED(15, 2) < SMOOTHED(-10, -3)) << 3) + ((SMOOTHED(-20, -8) < SMOOTHED(-13, 3)) << 2) + ((SMOOTHED(-19, -12) < SMOOTHED(5, -11)) << 1) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 0));
desc[22] = (uchar)(((SMOOTHED(7, 4) < SMOOTHED(-12, 0)) << 7) + ((SMOOTHED(5, -1) < SMOOTHED(-14, -6)) << 6) + ((SMOOTHED(-4, 11) < SMOOTHED(0, -4)) << 5) + ((SMOOTHED(3, 10) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(13, 21) < SMOOTHED(-11, 6)) << 3) + ((SMOOTHED(-12, 24) < SMOOTHED(-7, -4)) << 2) + ((SMOOTHED(4, 16) < SMOOTHED(3, -14)) << 1) + ((SMOOTHED(-3, 5) < SMOOTHED(-7, -12)) << 0));
desc[23] = (uchar)(((SMOOTHED(0, -4) < SMOOTHED(7, -5)) << 7) + ((SMOOTHED(-17, -9) < SMOOTHED(13, -7)) << 6) + ((SMOOTHED(22, -6) < SMOOTHED(-11, 5)) << 5) + ((SMOOTHED(2, -8) < SMOOTHED(23, -11)) << 4) + ((SMOOTHED(7, -10) < SMOOTHED(-1, 14)) << 3) + ((SMOOTHED(-3, -10) < SMOOTHED(8, 3)) << 2) + ((SMOOTHED(-13, 1) < SMOOTHED(-6, 0)) << 1) + ((SMOOTHED(-7, -21) < SMOOTHED(6, -14)) << 0));
desc[24] = (uchar)(((SMOOTHED(18, 19) < SMOOTHED(-4, -6)) << 7) + ((SMOOTHED(10, 7) < SMOOTHED(-1, -4)) << 6) + ((SMOOTHED(-1, 21) < SMOOTHED(1, -5)) << 5) + ((SMOOTHED(-10, 6) < SMOOTHED(-11, -2)) << 4) + ((SMOOTHED(18, -3) < SMOOTHED(-1, 7)) << 3) + ((SMOOTHED(-3, -9) < SMOOTHED(-5, 10)) << 2) + ((SMOOTHED(-13, 14) < SMOOTHED(17, -3)) << 1) + ((SMOOTHED(11, -19) < SMOOTHED(-1, -18)) << 0));
desc[25] = (uchar)(((SMOOTHED(8, -2) < SMOOTHED(-18, -23)) << 7) + ((SMOOTHED(0, -5) < SMOOTHED(-2, -9)) << 6) + ((SMOOTHED(-4, -11) < SMOOTHED(2, -8)) << 5) + ((SMOOTHED(14, 6) < SMOOTHED(-3, -6)) << 4) + ((SMOOTHED(-3, 0) < SMOOTHED(-15, 0)) << 3) + ((SMOOTHED(-9, 4) < SMOOTHED(-15, -9)) << 2) + ((SMOOTHED(-1, 11) < SMOOTHED(3, 11)) << 1) + ((SMOOTHED(-10, -16) < SMOOTHED(-7, 7)) << 0));
desc[26] = (uchar)(((SMOOTHED(-2, -10) < SMOOTHED(-10, -2)) << 7) + ((SMOOTHED(-5, -3) < SMOOTHED(5, -23)) << 6) + ((SMOOTHED(13, -8) < SMOOTHED(-15, -11)) << 5) + ((SMOOTHED(-15, 11) < SMOOTHED(6, -6)) << 4) + ((SMOOTHED(-16, -3) < SMOOTHED(-2, 2)) << 3) + ((SMOOTHED(6, 12) < SMOOTHED(-16, 24)) << 2) + ((SMOOTHED(-10, 0) < SMOOTHED(8, 11)) << 1) + ((SMOOTHED(-7, 7) < SMOOTHED(-19, -7)) << 0));
desc[27] = (uchar)(((SMOOTHED(5, 16) < SMOOTHED(9, -3)) << 7) + ((SMOOTHED(9, 7) < SMOOTHED(-7, -16)) << 6) + ((SMOOTHED(3, 2) < SMOOTHED(-10, 9)) << 5) + ((SMOOTHED(21, 1) < SMOOTHED(8, 7)) << 4) + ((SMOOTHED(7, 0) < SMOOTHED(1, 17)) << 3) + ((SMOOTHED(-8, 12) < SMOOTHED(9, 6)) << 2) + ((SMOOTHED(11, -7) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(19, 0) < SMOOTHED(9, 3)) << 0));
desc[28] = (uchar)(((SMOOTHED(1, -7) < SMOOTHED(-5, -11)) << 7) + ((SMOOTHED(0, 8) < SMOOTHED(-2, 14)) << 6) + ((SMOOTHED(12, -2) < SMOOTHED(-15, -6)) << 5) + ((SMOOTHED(4, 12) < SMOOTHED(0, -21)) << 4) + ((SMOOTHED(17, -4) < SMOOTHED(-6, -7)) << 3) + ((SMOOTHED(-10, -9) < SMOOTHED(-14, -7)) << 2) + ((SMOOTHED(-15, -10) < SMOOTHED(-15, -14)) << 1) + ((SMOOTHED(-7, -5) < SMOOTHED(5, -12)) << 0));
desc[29] = (uchar)(((SMOOTHED(-4, 0) < SMOOTHED(15, -4)) << 7) + ((SMOOTHED(5, 2) < SMOOTHED(-6, -23)) << 6) + ((SMOOTHED(-4, -21) < SMOOTHED(-6, 4)) << 5) + ((SMOOTHED(-10, 5) < SMOOTHED(-15, 6)) << 4) + ((SMOOTHED(4, -3) < SMOOTHED(-1, 5)) << 3) + ((SMOOTHED(-4, 19) < SMOOTHED(-23, -4)) << 2) + ((SMOOTHED(-4, 17) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(1, 12) < SMOOTHED(4, -14)) << 0));
desc[30] = (uchar)(((SMOOTHED(-11, -6) < SMOOTHED(-20, 10)) << 7) + ((SMOOTHED(4, 5) < SMOOTHED(3, 20)) << 6) + ((SMOOTHED(-8, -20) < SMOOTHED(3, 1)) << 5) + ((SMOOTHED(-19, 9) < SMOOTHED(9, -3)) << 4) + ((SMOOTHED(18, 15) < SMOOTHED(11, -4)) << 3) + ((SMOOTHED(12, 16) < SMOOTHED(8, 7)) << 2) + ((SMOOTHED(-14, -8) < SMOOTHED(-3, 9)) << 1) + ((SMOOTHED(-6, 0) < SMOOTHED(2, -4)) << 0));
desc[31] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-1, 2)) << 7) + ((SMOOTHED(8, -7) < SMOOTHED(-6, 18)) << 6) + ((SMOOTHED(9, 12) < SMOOTHED(-7, -23)) << 5) + ((SMOOTHED(8, -6) < SMOOTHED(5, 2)) << 4) + ((SMOOTHED(-9, 6) < SMOOTHED(-12, -7)) << 3) + ((SMOOTHED(-1, -2) < SMOOTHED(-7, 2)) << 2) + ((SMOOTHED(9, 9) < SMOOTHED(7, 15)) << 1) + ((SMOOTHED(6, 2) < SMOOTHED(-6, 6)) << 0));
desc[32] = (uchar)(((SMOOTHED(16, 12) < SMOOTHED(0, 19)) << 7) + ((SMOOTHED(4, 3) < SMOOTHED(6, 0)) << 6) + ((SMOOTHED(-2, -1) < SMOOTHED(2, 17)) << 5) + ((SMOOTHED(8, 1) < SMOOTHED(3, 1)) << 4) + ((SMOOTHED(-12, -1) < SMOOTHED(-11, 0)) << 3) + ((SMOOTHED(-11, 2) < SMOOTHED(7, 9)) << 2) + ((SMOOTHED(-1, 3) < SMOOTHED(-19, 4)) << 1) + ((SMOOTHED(-1, -11) < SMOOTHED(-1, 3)) << 0));
desc[33] = (uchar)(((SMOOTHED(1, -10) < SMOOTHED(-10, -4)) << 7) + ((SMOOTHED(-2, 3) < SMOOTHED(6, 11)) << 6) + ((SMOOTHED(3, 7) < SMOOTHED(-9, -8)) << 5) + ((SMOOTHED(24, -14) < SMOOTHED(-2, -10)) << 4) + ((SMOOTHED(-3, -3) < SMOOTHED(-18, -6)) << 3) + ((SMOOTHED(-13, -10) < SMOOTHED(-7, -1)) << 2) + ((SMOOTHED(2, -7) < SMOOTHED(9, -6)) << 1) + ((SMOOTHED(2, -4) < SMOOTHED(6, -13)) << 0));
desc[34] = (uchar)(((SMOOTHED(4, -4) < SMOOTHED(-2, 3)) << 7) + ((SMOOTHED(-4, 2) < SMOOTHED(9, 13)) << 6) + ((SMOOTHED(-11, 5) < SMOOTHED(-6, -11)) << 5) + ((SMOOTHED(4, -2) < SMOOTHED(11, -9)) << 4) + ((SMOOTHED(-19, 0) < SMOOTHED(-23, -5)) << 3) + ((SMOOTHED(-5, -7) < SMOOTHED(-3, -6)) << 2) + ((SMOOTHED(-6, -4) < SMOOTHED(12, 14)) << 1) + ((SMOOTHED(12, -11) < SMOOTHED(-8, -16)) << 0));
desc[35] = (uchar)(((SMOOTHED(-21, 15) < SMOOTHED(-12, 6)) << 7) + ((SMOOTHED(-2, -1) < SMOOTHED(-8, 16)) << 6) + ((SMOOTHED(6, -1) < SMOOTHED(-8, -2)) << 5) + ((SMOOTHED(1, -1) < SMOOTHED(-9, 8)) << 4) + ((SMOOTHED(3, -4) < SMOOTHED(-2, -2)) << 3) + ((SMOOTHED(-7, 0) < SMOOTHED(4, -8)) << 2) + ((SMOOTHED(11, -11) < SMOOTHED(-12, 2)) << 1) + ((SMOOTHED(2, 3) < SMOOTHED(11, 7)) << 0));
desc[36] = (uchar)(((SMOOTHED(-7, -4) < SMOOTHED(-9, -6)) << 7) + ((SMOOTHED(3, -7) < SMOOTHED(-5, 0)) << 6) + ((SMOOTHED(3, -7) < SMOOTHED(-10, -5)) << 5) + ((SMOOTHED(-3, -1) < SMOOTHED(8, -10)) << 4) + ((SMOOTHED(0, 8) < SMOOTHED(5, 1)) << 3) + ((SMOOTHED(9, 0) < SMOOTHED(1, 16)) << 2) + ((SMOOTHED(8, 4) < SMOOTHED(-11, -3)) << 1) + ((SMOOTHED(-15, 9) < SMOOTHED(8, 17)) << 0));
desc[37] = (uchar)(((SMOOTHED(0, 2) < SMOOTHED(-9, 17)) << 7) + ((SMOOTHED(-6, -11) < SMOOTHED(-10, -3)) << 6) + ((SMOOTHED(1, 1) < SMOOTHED(15, -8)) << 5) + ((SMOOTHED(-12, -13) < SMOOTHED(-2, 4)) << 4) + ((SMOOTHED(-6, 4) < SMOOTHED(-6, -10)) << 3) + ((SMOOTHED(5, -7) < SMOOTHED(7, -5)) << 2) + ((SMOOTHED(10, 6) < SMOOTHED(8, 9)) << 1) + ((SMOOTHED(-5, 7) < SMOOTHED(-18, -3)) << 0));
desc[38] = (uchar)(((SMOOTHED(-6, 3) < SMOOTHED(5, 4)) << 7) + ((SMOOTHED(-10, -13) < SMOOTHED(-5, -3)) << 6) + ((SMOOTHED(-11, 2) < SMOOTHED(-16, 0)) << 5) + ((SMOOTHED(7, -21) < SMOOTHED(-5, -13)) << 4) + ((SMOOTHED(-14, -14) < SMOOTHED(-4, -4)) << 3) + ((SMOOTHED(4, 9) < SMOOTHED(7, -3)) << 2) + ((SMOOTHED(4, 11) < SMOOTHED(10, -4)) << 1) + ((SMOOTHED(6, 17) < SMOOTHED(9, 17)) << 0));
desc[39] = (uchar)(((SMOOTHED(-10, 8) < SMOOTHED(0, -11)) << 7) + ((SMOOTHED(-6, -16) < SMOOTHED(-6, 8)) << 6) + ((SMOOTHED(-13, 5) < SMOOTHED(10, -5)) << 5) + ((SMOOTHED(3, 2) < SMOOTHED(12, 16)) << 4) + ((SMOOTHED(13, -8) < SMOOTHED(0, -6)) << 3) + ((SMOOTHED(10, 0) < SMOOTHED(4, -11)) << 2) + ((SMOOTHED(8, 5) < SMOOTHED(10, -2)) << 1) + ((SMOOTHED(11, -7) < SMOOTHED(-13, 3)) << 0));
desc[40] = (uchar)(((SMOOTHED(2, 4) < SMOOTHED(-7, -3)) << 7) + ((SMOOTHED(-14, -2) < SMOOTHED(-11, 16)) << 6) + ((SMOOTHED(11, -6) < SMOOTHED(7, 6)) << 5) + ((SMOOTHED(-3, 15) < SMOOTHED(8, -10)) << 4) + ((SMOOTHED(-3, 8) < SMOOTHED(12, -12)) << 3) + ((SMOOTHED(-13, 6) < SMOOTHED(-14, 7)) << 2) + ((SMOOTHED(-11, -5) < SMOOTHED(-8, -6)) << 1) + ((SMOOTHED(7, -6) < SMOOTHED(6, 3)) << 0));
desc[41] = (uchar)(((SMOOTHED(-4, 10) < SMOOTHED(5, 1)) << 7) + ((SMOOTHED(9, 16) < SMOOTHED(10, 13)) << 6) + ((SMOOTHED(-17, 10) < SMOOTHED(2, 8)) << 5) + ((SMOOTHED(-5, 1) < SMOOTHED(4, -4)) << 4) + ((SMOOTHED(-14, 8) < SMOOTHED(-5, 2)) << 3) + ((SMOOTHED(4, -9) < SMOOTHED(-6, -3)) << 2) + ((SMOOTHED(3, -7) < SMOOTHED(-10, 0)) << 1) + ((SMOOTHED(-2, -8) < SMOOTHED(-10, 4)) << 0));
desc[42] = (uchar)(((SMOOTHED(-8, 5) < SMOOTHED(-9, 24)) << 7) + ((SMOOTHED(2, -8) < SMOOTHED(8, -9)) << 6) + ((SMOOTHED(-4, 17) < SMOOTHED(-5, 2)) << 5) + ((SMOOTHED(14, 0) < SMOOTHED(-9, 9)) << 4) + ((SMOOTHED(11, 15) < SMOOTHED(-6, 5)) << 3) + ((SMOOTHED(-8, 1) < SMOOTHED(-3, 4)) << 2) + ((SMOOTHED(9, -21) < SMOOTHED(10, 2)) << 1) + ((SMOOTHED(2, -1) < SMOOTHED(4, 11)) << 0));
desc[43] = (uchar)(((SMOOTHED(24, 3) < SMOOTHED(2, -2)) << 7) + ((SMOOTHED(-8, 17) < SMOOTHED(-14, -10)) << 6) + ((SMOOTHED(6, 5) < SMOOTHED(-13, 7)) << 5) + ((SMOOTHED(11, 10) < SMOOTHED(0, -1)) << 4) + ((SMOOTHED(4, 6) < SMOOTHED(-10, 6)) << 3) + ((SMOOTHED(-12, -2) < SMOOTHED(5, 6)) << 2) + ((SMOOTHED(3, -1) < SMOOTHED(8, -15)) << 1) + ((SMOOTHED(1, -4) < SMOOTHED(-7, 11)) << 0));
desc[44] = (uchar)(((SMOOTHED(1, 11) < SMOOTHED(5, 0)) << 7) + ((SMOOTHED(6, -12) < SMOOTHED(10, 1)) << 6) + ((SMOOTHED(-3, -2) < SMOOTHED(-1, 4)) << 5) + ((SMOOTHED(-2, -11) < SMOOTHED(-1, 12)) << 4) + ((SMOOTHED(7, -8) < SMOOTHED(-20, -18)) << 3) + ((SMOOTHED(2, 0) < SMOOTHED(-9, 2)) << 2) + ((SMOOTHED(-13, -1) < SMOOTHED(-16, 2)) << 1) + ((SMOOTHED(3, -1) < SMOOTHED(-5, -17)) << 0));
desc[45] = (uchar)(((SMOOTHED(15, 8) < SMOOTHED(3, -14)) << 7) + ((SMOOTHED(-13, -12) < SMOOTHED(6, 15)) << 6) + ((SMOOTHED(2, -8) < SMOOTHED(2, 6)) << 5) + ((SMOOTHED(6, 22) < SMOOTHED(-3, -23)) << 4) + ((SMOOTHED(-2, -7) < SMOOTHED(-6, 0)) << 3) + ((SMOOTHED(13, -10) < SMOOTHED(-6, 6)) << 2) + ((SMOOTHED(6, 7) < SMOOTHED(-10, 12)) << 1) + ((SMOOTHED(-6, 7) < SMOOTHED(-2, 11)) << 0));
desc[46] = (uchar)(((SMOOTHED(0, -22) < SMOOTHED(-2, -17)) << 7) + ((SMOOTHED(-4, -1) < SMOOTHED(-11, -14)) << 6) + ((SMOOTHED(-2, -8) < SMOOTHED(7, 12)) << 5) + ((SMOOTHED(12, -5) < SMOOTHED(7, -13)) << 4) + ((SMOOTHED(2, -2) < SMOOTHED(-7, 6)) << 3) + ((SMOOTHED(0, 8) < SMOOTHED(-3, 23)) << 2) + ((SMOOTHED(6, 12) < SMOOTHED(13, -11)) << 1) + ((SMOOTHED(-21, -10) < SMOOTHED(10, 8)) << 0));
desc[47] = (uchar)(((SMOOTHED(-3, 0) < SMOOTHED(7, 15)) << 7) + ((SMOOTHED(7, -6) < SMOOTHED(-5, -12)) << 6) + ((SMOOTHED(-21, -10) < SMOOTHED(12, -11)) << 5) + ((SMOOTHED(-5, -11) < SMOOTHED(8, -11)) << 4) + ((SMOOTHED(5, 0) < SMOOTHED(-11, -1)) << 3) + ((SMOOTHED(8, -9) < SMOOTHED(7, -1)) << 2) + ((SMOOTHED(11, -23) < SMOOTHED(21, -5)) << 1) + ((SMOOTHED(0, -5) < SMOOTHED(-8, 6)) << 0));
desc[48] = (uchar)(((SMOOTHED(-6, 8) < SMOOTHED(8, 12)) << 7) + ((SMOOTHED(-7, 5) < SMOOTHED(3, -2)) << 6) + ((SMOOTHED(-5, -20) < SMOOTHED(-12, 9)) << 5) + ((SMOOTHED(-6, 12) < SMOOTHED(-11, 3)) << 4) + ((SMOOTHED(4, 5) < SMOOTHED(13, 11)) << 3) + ((SMOOTHED(2, 12) < SMOOTHED(13, -12)) << 2) + ((SMOOTHED(-4, -13) < SMOOTHED(4, 7)) << 1) + ((SMOOTHED(0, 15) < SMOOTHED(-3, -16)) << 0));
desc[49] = (uchar)(((SMOOTHED(-3, 2) < SMOOTHED(-2, 14)) << 7) + ((SMOOTHED(4, -14) < SMOOTHED(16, -11)) << 6) + ((SMOOTHED(-13, 3) < SMOOTHED(23, 10)) << 5) + ((SMOOTHED(9, -19) < SMOOTHED(2, 5)) << 4) + ((SMOOTHED(5, 3) < SMOOTHED(14, -7)) << 3) + ((SMOOTHED(19, -13) < SMOOTHED(-11, 15)) << 2) + ((SMOOTHED(14, 0) < SMOOTHED(-2, -5)) << 1) + ((SMOOTHED(11, -4) < SMOOTHED(0, -6)) << 0));
desc[50] = (uchar)(((SMOOTHED(-2, 5) < SMOOTHED(-13, -8)) << 7) + ((SMOOTHED(-11, -15) < SMOOTHED(-7, -17)) << 6) + ((SMOOTHED(1, 3) < SMOOTHED(-10, -8)) << 5) + ((SMOOTHED(-13, -10) < SMOOTHED(7, -12)) << 4) + ((SMOOTHED(0, -13) < SMOOTHED(23, -6)) << 3) + ((SMOOTHED(2, -17) < SMOOTHED(-7, -3)) << 2) + ((SMOOTHED(1, 3) < SMOOTHED(4, -10)) << 1) + ((SMOOTHED(13, 4) < SMOOTHED(14, -6)) << 0));
desc[51] = (uchar)(((SMOOTHED(-19, -2) < SMOOTHED(-1, 5)) << 7) + ((SMOOTHED(9, -8) < SMOOTHED(10, -5)) << 6) + ((SMOOTHED(7, -1) < SMOOTHED(5, 7)) << 5) + ((SMOOTHED(9, -10) < SMOOTHED(19, 0)) << 4) + ((SMOOTHED(7, 5) < SMOOTHED(-4, -7)) << 3) + ((SMOOTHED(-11, 1) < SMOOTHED(-1, -11)) << 2) + ((SMOOTHED(2, -1) < SMOOTHED(-4, 11)) << 1) + ((SMOOTHED(-1, 7) < SMOOTHED(2, -2)) << 0));
desc[52] = (uchar)(((SMOOTHED(1, -20) < SMOOTHED(-9, -6)) << 7) + ((SMOOTHED(-4, -18) < SMOOTHED(8, -18)) << 6) + ((SMOOTHED(-16, -2) < SMOOTHED(7, -6)) << 5) + ((SMOOTHED(-3, -6) < SMOOTHED(-1, -4)) << 4) + ((SMOOTHED(0, -16) < SMOOTHED(24, -5)) << 3) + ((SMOOTHED(-4, -2) < SMOOTHED(-1, 9)) << 2) + ((SMOOTHED(-8, 2) < SMOOTHED(-6, 15)) << 1) + ((SMOOTHED(11, 4) < SMOOTHED(0, -3)) << 0));
desc[53] = (uchar)(((SMOOTHED(7, 6) < SMOOTHED(2, -10)) << 7) + ((SMOOTHED(-7, -9) < SMOOTHED(12, -6)) << 6) + ((SMOOTHED(24, 15) < SMOOTHED(-8, -1)) << 5) + ((SMOOTHED(15, -9) < SMOOTHED(-3, -15)) << 4) + ((SMOOTHED(17, -5) < SMOOTHED(11, -10)) << 3) + ((SMOOTHED(-2, 13) < SMOOTHED(-15, 4)) << 2) + ((SMOOTHED(-2, -1) < SMOOTHED(4, -23)) << 1) + ((SMOOTHED(-16, 3) < SMOOTHED(-7, -14)) << 0));
desc[54] = (uchar)(((SMOOTHED(-3, -5) < SMOOTHED(-10, -9)) << 7) + ((SMOOTHED(-5, 3) < SMOOTHED(-2, -1)) << 6) + ((SMOOTHED(-1, 4) < SMOOTHED(1, 8)) << 5) + ((SMOOTHED(12, 9) < SMOOTHED(9, -14)) << 4) + ((SMOOTHED(-9, 17) < SMOOTHED(-3, 0)) << 3) + ((SMOOTHED(5, 4) < SMOOTHED(13, -6)) << 2) + ((SMOOTHED(-1, -8) < SMOOTHED(19, 10)) << 1) + ((SMOOTHED(8, -5) < SMOOTHED(-15, 2)) << 0));
desc[55] = (uchar)(((SMOOTHED(-12, -9) < SMOOTHED(-4, -5)) << 7) + ((SMOOTHED(12, 0) < SMOOTHED(24, 4)) << 6) + ((SMOOTHED(8, -2) < SMOOTHED(14, 4)) << 5) + ((SMOOTHED(8, -4) < SMOOTHED(-7, 16)) << 4) + ((SMOOTHED(5, -1) < SMOOTHED(-8, -4)) << 3) + ((SMOOTHED(-2, 18) < SMOOTHED(-5, 17)) << 2) + ((SMOOTHED(8, -2) < SMOOTHED(-9, -2)) << 1) + ((SMOOTHED(3, -7) < SMOOTHED(1, -6)) << 0));
desc[56] = (uchar)(((SMOOTHED(-5, -22) < SMOOTHED(-5, -2)) << 7) + ((SMOOTHED(-8, -10) < SMOOTHED(14, 1)) << 6) + ((SMOOTHED(-3, -13) < SMOOTHED(3, 9)) << 5) + ((SMOOTHED(-4, -1) < SMOOTHED(-1, 0)) << 4) + ((SMOOTHED(-7, -21) < SMOOTHED(12, -19)) << 3) + ((SMOOTHED(-8, 8) < SMOOTHED(24, 8)) << 2) + ((SMOOTHED(12, -6) < SMOOTHED(-2, 3)) << 1) + ((SMOOTHED(-5, -11) < SMOOTHED(-22, -4)) << 0));
desc[57] = (uchar)(((SMOOTHED(-3, 5) < SMOOTHED(-4, 4)) << 7) + ((SMOOTHED(-16, 24) < SMOOTHED(7, -9)) << 6) + ((SMOOTHED(-10, 23) < SMOOTHED(-9, 18)) << 5) + ((SMOOTHED(1, 12) < SMOOTHED(17, 21)) << 4) + ((SMOOTHED(24, -6) < SMOOTHED(-3, -11)) << 3) + ((SMOOTHED(-7, 17) < SMOOTHED(1, -6)) << 2) + ((SMOOTHED(4, 4) < SMOOTHED(2, -7)) << 1) + ((SMOOTHED(14, 6) < SMOOTHED(-12, 3)) << 0));
desc[58] = (uchar)(((SMOOTHED(-6, 0) < SMOOTHED(-16, 13)) << 7) + ((SMOOTHED(-10, 5) < SMOOTHED(7, 12)) << 6) + ((SMOOTHED(5, 2) < SMOOTHED(6, -3)) << 5) + ((SMOOTHED(7, 0) < SMOOTHED(-23, 1)) << 4) + ((SMOOTHED(15, -5) < SMOOTHED(1, 14)) << 3) + ((SMOOTHED(-3, -1) < SMOOTHED(6, 6)) << 2) + ((SMOOTHED(6, -9) < SMOOTHED(-9, 12)) << 1) + ((SMOOTHED(4, -2) < SMOOTHED(-4, 7)) << 0));
desc[59] = (uchar)(((SMOOTHED(-4, -5) < SMOOTHED(4, 4)) << 7) + ((SMOOTHED(-13, 0) < SMOOTHED(6, -10)) << 6) + ((SMOOTHED(2, -12) < SMOOTHED(-6, -3)) << 5) + ((SMOOTHED(16, 0) < SMOOTHED(-3, 3)) << 4) + ((SMOOTHED(5, -14) < SMOOTHED(6, 11)) << 3) + ((SMOOTHED(5, 11) < SMOOTHED(0, -13)) << 2) + ((SMOOTHED(7, 5) < SMOOTHED(-1, -5)) << 1) + ((SMOOTHED(12, 4) < SMOOTHED(6, 10)) << 0));
desc[60] = (uchar)(((SMOOTHED(-10, 4) < SMOOTHED(-1, -11)) << 7) + ((SMOOTHED(4, 10) < SMOOTHED(-14, 5)) << 6) + ((SMOOTHED(11, -14) < SMOOTHED(-13, 0)) << 5) + ((SMOOTHED(2, 8) < SMOOTHED(12, 24)) << 4) + ((SMOOTHED(-1, 3) < SMOOTHED(-1, 2)) << 3) + ((SMOOTHED(9, -14) < SMOOTHED(-23, 3)) << 2) + ((SMOOTHED(-8, -6) < SMOOTHED(0, 9)) << 1) + ((SMOOTHED(-15, 14) < SMOOTHED(10, -10)) << 0));
desc[61] = (uchar)(((SMOOTHED(-10, -6) < SMOOTHED(-7, -5)) << 7) + ((SMOOTHED(11, 5) < SMOOTHED(-3, -15)) << 6) + ((SMOOTHED(1, 0) < SMOOTHED(1, 8)) << 5) + ((SMOOTHED(-11, -6) < SMOOTHED(-4, -18)) << 4) + ((SMOOTHED(9, 0) < SMOOTHED(22, -4)) << 3) + ((SMOOTHED(-5, -1) < SMOOTHED(-9, 4)) << 2) + ((SMOOTHED(-20, 2) < SMOOTHED(1, 6)) << 1) + ((SMOOTHED(1, 2) < SMOOTHED(-9, -12)) << 0));
desc[62] = (uchar)(((SMOOTHED(5, 15) < SMOOTHED(4, -6)) << 7) + ((SMOOTHED(19, 4) < SMOOTHED(4, 11)) << 6) + ((SMOOTHED(17, -4) < SMOOTHED(-8, -1)) << 5) + ((SMOOTHED(-8, -12) < SMOOTHED(7, -3)) << 4) + ((SMOOTHED(11, 9) < SMOOTHED(8, 1)) << 3) + ((SMOOTHED(9, 22) < SMOOTHED(-15, 15)) << 2) + ((SMOOTHED(-7, -7) < SMOOTHED(1, -23)) << 1) + ((SMOOTHED(-5, 13) < SMOOTHED(-8, 2)) << 0));
desc[63] = (uchar)(((SMOOTHED(3, -5) < SMOOTHED(11, -11)) << 7) + ((SMOOTHED(3, -18) < SMOOTHED(14, -5)) << 6) + ((SMOOTHED(-20, 7) < SMOOTHED(-10, -23)) << 5) + ((SMOOTHED(-2, -5) < SMOOTHED(6, 0)) << 4) + ((SMOOTHED(-17, -13) < SMOOTHED(-3, 2)) << 3) + ((SMOOTHED(-6, -1) < SMOOTHED(14, -2)) << 2) + ((SMOOTHED(-12, -16) < SMOOTHED(15, 6)) << 1) + ((SMOOTHED(-12, -2) < SMOOTHED(3, -19)) << 0));
#undef SMOOTHED

@ -50,26 +50,7 @@
namespace cv
{
Mat windowedMatchingMask( const std::vector<KeyPoint>& keypoints1, const std::vector<KeyPoint>& keypoints2,
float maxDeltaX, float maxDeltaY )
{
if( keypoints1.empty() || keypoints2.empty() )
return Mat();
int n1 = (int)keypoints1.size(), n2 = (int)keypoints2.size();
Mat mask( n1, n2, CV_8UC1 );
for( int i = 0; i < n1; i++ )
{
for( int j = 0; j < n2; j++ )
{
Point2f diff = keypoints2[j].pt - keypoints1[i].pt;
mask.at<uchar>(i, j) = std::abs(diff.x) < maxDeltaX && std::abs(diff.y) < maxDeltaY;
}
}
return mask;
}
//////////////////////////////////////////////////////////////////ocl functions for BFMatcher ///////////////////////////////////////////////////////////////
/////////////////////// ocl functions for BFMatcher ///////////////////////////
static void ensureSizeIsEnough(int rows, int cols, int type, UMat &m)
{
@ -1507,382 +1488,4 @@ void FlannBasedMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vect
convertToDMatches( mergedDescriptors, indices, dists, matches );
}
/****************************************************************************************\
* GenericDescriptorMatcher *
\****************************************************************************************/
/*
* KeyPointCollection
*/
GenericDescriptorMatcher::KeyPointCollection::KeyPointCollection() : pointCount(0)
{}
GenericDescriptorMatcher::KeyPointCollection::KeyPointCollection( const KeyPointCollection& collection )
{
pointCount = collection.pointCount;
std::transform( collection.images.begin(), collection.images.end(), images.begin(), clone_op );
keypoints.resize( collection.keypoints.size() );
for( size_t i = 0; i < keypoints.size(); i++ )
std::copy( collection.keypoints[i].begin(), collection.keypoints[i].end(), keypoints[i].begin() );
std::copy( collection.startIndices.begin(), collection.startIndices.end(), startIndices.begin() );
}
void GenericDescriptorMatcher::KeyPointCollection::add( const std::vector<Mat>& _images,
const std::vector<std::vector<KeyPoint> >& _points )
{
CV_Assert( !_images.empty() );
CV_Assert( _images.size() == _points.size() );
images.insert( images.end(), _images.begin(), _images.end() );
keypoints.insert( keypoints.end(), _points.begin(), _points.end() );
for( size_t i = 0; i < _points.size(); i++ )
pointCount += (int)_points[i].size();
size_t prevSize = startIndices.size(), addSize = _images.size();
startIndices.resize( prevSize + addSize );
if( prevSize == 0 )
startIndices[prevSize] = 0; //first
else
startIndices[prevSize] = (int)(startIndices[prevSize-1] + keypoints[prevSize-1].size());
for( size_t i = prevSize + 1; i < prevSize + addSize; i++ )
{
startIndices[i] = (int)(startIndices[i - 1] + keypoints[i - 1].size());
}
}
void GenericDescriptorMatcher::KeyPointCollection::clear()
{
pointCount = 0;
images.clear();
keypoints.clear();
startIndices.clear();
}
size_t GenericDescriptorMatcher::KeyPointCollection::keypointCount() const
{
return pointCount;
}
size_t GenericDescriptorMatcher::KeyPointCollection::imageCount() const
{
return images.size();
}
const std::vector<std::vector<KeyPoint> >& GenericDescriptorMatcher::KeyPointCollection::getKeypoints() const
{
return keypoints;
}
const std::vector<KeyPoint>& GenericDescriptorMatcher::KeyPointCollection::getKeypoints( int imgIdx ) const
{
CV_Assert( imgIdx < (int)imageCount() );
return keypoints[imgIdx];
}
const KeyPoint& GenericDescriptorMatcher::KeyPointCollection::getKeyPoint( int imgIdx, int localPointIdx ) const
{
CV_Assert( imgIdx < (int)images.size() );
CV_Assert( localPointIdx < (int)keypoints[imgIdx].size() );
return keypoints[imgIdx][localPointIdx];
}
const KeyPoint& GenericDescriptorMatcher::KeyPointCollection::getKeyPoint( int globalPointIdx ) const
{
int imgIdx, localPointIdx;
getLocalIdx( globalPointIdx, imgIdx, localPointIdx );
return keypoints[imgIdx][localPointIdx];
}
void GenericDescriptorMatcher::KeyPointCollection::getLocalIdx( int globalPointIdx, int& imgIdx, int& localPointIdx ) const
{
imgIdx = -1;
CV_Assert( globalPointIdx < (int)keypointCount() );
for( size_t i = 1; i < startIndices.size(); i++ )
{
if( globalPointIdx < startIndices[i] )
{
imgIdx = (int)(i - 1);
break;
}
}
imgIdx = imgIdx == -1 ? (int)(startIndices.size() - 1) : imgIdx;
localPointIdx = globalPointIdx - startIndices[imgIdx];
}
const std::vector<Mat>& GenericDescriptorMatcher::KeyPointCollection::getImages() const
{
return images;
}
const Mat& GenericDescriptorMatcher::KeyPointCollection::getImage( int imgIdx ) const
{
CV_Assert( imgIdx < (int)imageCount() );
return images[imgIdx];
}
/*
* GenericDescriptorMatcher
*/
GenericDescriptorMatcher::GenericDescriptorMatcher()
{}
GenericDescriptorMatcher::~GenericDescriptorMatcher()
{}
void GenericDescriptorMatcher::add( InputArrayOfArrays _images,
std::vector<std::vector<KeyPoint> >& keypoints )
{
std::vector<Mat> images;
_images.getMatVector(images);
CV_Assert( !images.empty() );
CV_Assert( images.size() == keypoints.size() );
for( size_t i = 0; i < images.size(); i++ )
{
CV_Assert( !images[i].empty() );
KeyPointsFilter::runByImageBorder( keypoints[i], images[i].size(), 0 );
KeyPointsFilter::runByKeypointSize( keypoints[i], std::numeric_limits<float>::epsilon() );
}
trainPointCollection.add( images, keypoints );
}
const std::vector<Mat>& GenericDescriptorMatcher::getTrainImages() const
{
return trainPointCollection.getImages();
}
const std::vector<std::vector<KeyPoint> >& GenericDescriptorMatcher::getTrainKeypoints() const
{
return trainPointCollection.getKeypoints();
}
void GenericDescriptorMatcher::clear()
{
trainPointCollection.clear();
}
void GenericDescriptorMatcher::train()
{}
void GenericDescriptorMatcher::classify( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
InputArray trainImage, std::vector<KeyPoint>& trainKeypoints ) const
{
std::vector<DMatch> matches;
match( queryImage, queryKeypoints, trainImage, trainKeypoints, matches );
// remap keypoint indices to descriptors
for( size_t i = 0; i < matches.size(); i++ )
queryKeypoints[matches[i].queryIdx].class_id = trainKeypoints[matches[i].trainIdx].class_id;
}
void GenericDescriptorMatcher::classify( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints )
{
std::vector<DMatch> matches;
match( queryImage, queryKeypoints, matches );
// remap keypoint indices to descriptors
for( size_t i = 0; i < matches.size(); i++ )
queryKeypoints[matches[i].queryIdx].class_id = trainPointCollection.getKeyPoint( matches[i].trainIdx, matches[i].trainIdx ).class_id;
}
void GenericDescriptorMatcher::match( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
InputArray _trainImage, std::vector<KeyPoint>& trainKeypoints,
std::vector<DMatch>& matches, InputArray mask ) const
{
Mat trainImage = _trainImage.getMat();
Ptr<GenericDescriptorMatcher> tempMatcher = clone( true );
std::vector<std::vector<KeyPoint> > vecTrainPoints(1, trainKeypoints);
tempMatcher->add( std::vector<Mat>(1, trainImage), vecTrainPoints );
tempMatcher->match( queryImage, queryKeypoints, matches, std::vector<Mat>(1, mask.getMat()) );
vecTrainPoints[0].swap( trainKeypoints );
}
void GenericDescriptorMatcher::knnMatch( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
InputArray _trainImage, std::vector<KeyPoint>& trainKeypoints,
std::vector<std::vector<DMatch> >& matches, int knn, InputArray mask, bool compactResult ) const
{
Mat trainImage = _trainImage.getMat();
Ptr<GenericDescriptorMatcher> tempMatcher = clone( true );
std::vector<std::vector<KeyPoint> > vecTrainPoints(1, trainKeypoints);
tempMatcher->add( std::vector<Mat>(1, trainImage), vecTrainPoints );
tempMatcher->knnMatch( queryImage, queryKeypoints, matches, knn, std::vector<Mat>(1, mask.getMat()), compactResult );
vecTrainPoints[0].swap( trainKeypoints );
}
void GenericDescriptorMatcher::radiusMatch( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
InputArray _trainImage, std::vector<KeyPoint>& trainKeypoints,
std::vector<std::vector<DMatch> >& matches, float maxDistance,
InputArray mask, bool compactResult ) const
{
Mat trainImage = _trainImage.getMat();
Ptr<GenericDescriptorMatcher> tempMatcher = clone( true );
std::vector<std::vector<KeyPoint> > vecTrainPoints(1, trainKeypoints);
tempMatcher->add( std::vector<Mat>(1, trainImage), vecTrainPoints );
tempMatcher->radiusMatch( queryImage, queryKeypoints, matches, maxDistance, std::vector<Mat>(1, mask.getMat()), compactResult );
vecTrainPoints[0].swap( trainKeypoints );
}
void GenericDescriptorMatcher::match( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<DMatch>& matches, InputArrayOfArrays masks )
{
std::vector<std::vector<DMatch> > knnMatches;
knnMatch( queryImage, queryKeypoints, knnMatches, 1, masks, false );
convertMatches( knnMatches, matches );
}
void GenericDescriptorMatcher::knnMatch( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, int knn,
InputArrayOfArrays masks, bool compactResult )
{
matches.clear();
if( queryImage.empty() || queryKeypoints.empty() )
return;
KeyPointsFilter::runByImageBorder( queryKeypoints, queryImage.size(), 0 );
KeyPointsFilter::runByKeypointSize( queryKeypoints, std::numeric_limits<float>::epsilon() );
train();
knnMatchImpl( queryImage, queryKeypoints, matches, knn, masks, compactResult );
}
void GenericDescriptorMatcher::radiusMatch( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, float maxDistance,
InputArrayOfArrays masks, bool compactResult )
{
matches.clear();
if( queryImage.empty() || queryKeypoints.empty() )
return;
KeyPointsFilter::runByImageBorder( queryKeypoints, queryImage.size(), 0 );
KeyPointsFilter::runByKeypointSize( queryKeypoints, std::numeric_limits<float>::epsilon() );
train();
radiusMatchImpl( queryImage, queryKeypoints, matches, maxDistance, masks, compactResult );
}
void GenericDescriptorMatcher::read( const FileNode& )
{}
void GenericDescriptorMatcher::write( FileStorage& ) const
{}
bool GenericDescriptorMatcher::empty() const
{
return true;
}
/*
* Factory function for GenericDescriptorMatch creating
*/
Ptr<GenericDescriptorMatcher> GenericDescriptorMatcher::create( const String& genericDescritptorMatcherType,
const String &paramsFilename )
{
Ptr<GenericDescriptorMatcher> descriptorMatcher =
Algorithm::create<GenericDescriptorMatcher>("DescriptorMatcher." + genericDescritptorMatcherType);
if( !paramsFilename.empty() && descriptorMatcher )
{
FileStorage fs = FileStorage( paramsFilename, FileStorage::READ );
if( fs.isOpened() )
{
descriptorMatcher->read( fs.root() );
fs.release();
}
}
return descriptorMatcher;
}
/****************************************************************************************\
* VectorDescriptorMatcher *
\****************************************************************************************/
VectorDescriptorMatcher::VectorDescriptorMatcher( const Ptr<DescriptorExtractor>& _extractor,
const Ptr<DescriptorMatcher>& _matcher )
: extractor( _extractor ), matcher( _matcher )
{
CV_Assert( extractor && matcher );
}
VectorDescriptorMatcher::~VectorDescriptorMatcher()
{}
void VectorDescriptorMatcher::add( InputArrayOfArrays _imgCollection,
std::vector<std::vector<KeyPoint> >& pointCollection )
{
std::vector<Mat> imgCollection, descriptors;
_imgCollection.getMatVector(imgCollection);
extractor->compute( imgCollection, pointCollection, descriptors );
matcher->add( descriptors );
trainPointCollection.add( imgCollection, pointCollection );
}
void VectorDescriptorMatcher::clear()
{
//extractor->clear();
matcher->clear();
GenericDescriptorMatcher::clear();
}
void VectorDescriptorMatcher::train()
{
matcher->train();
}
bool VectorDescriptorMatcher::isMaskSupported()
{
return matcher->isMaskSupported();
}
void VectorDescriptorMatcher::knnMatchImpl( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, int knn,
InputArrayOfArrays masks, bool compactResult )
{
Mat queryDescriptors;
extractor->compute( queryImage, queryKeypoints, queryDescriptors );
matcher->knnMatch( queryDescriptors, matches, knn, masks, compactResult );
}
void VectorDescriptorMatcher::radiusMatchImpl( InputArray queryImage, std::vector<KeyPoint>& queryKeypoints,
std::vector<std::vector<DMatch> >& matches, float maxDistance,
InputArrayOfArrays masks, bool compactResult )
{
Mat queryDescriptors;
extractor->compute( queryImage, queryKeypoints, queryDescriptors );
matcher->radiusMatch( queryDescriptors, matches, maxDistance, masks, compactResult );
}
void VectorDescriptorMatcher::read( const FileNode& fn )
{
GenericDescriptorMatcher::read(fn);
extractor->read(fn);
}
void VectorDescriptorMatcher::write (FileStorage& fs) const
{
GenericDescriptorMatcher::write(fs);
extractor->write (fs);
}
bool VectorDescriptorMatcher::empty() const
{
return !extractor || extractor->empty() ||
!matcher || matcher->empty();
}
Ptr<GenericDescriptorMatcher> VectorDescriptorMatcher::clone( bool emptyTrainData ) const
{
// TODO clone extractor
return makePtr<VectorDescriptorMatcher>( extractor, matcher->clone(emptyTrainData) );
}
}

@ -1,472 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2008-2012, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
namespace cv
{
template <typename inMatType, typename outMatType> static void
computeIntegralImages( const Mat& matI, Mat& matS, Mat& matT, Mat& _FT,
int iiType )
{
int x, y, rows = matI.rows, cols = matI.cols;
matS.create(rows + 1, cols + 1, iiType );
matT.create(rows + 1, cols + 1, iiType );
_FT.create(rows + 1, cols + 1, iiType );
const inMatType* I = matI.ptr<inMatType>();
outMatType *S = matS.ptr<outMatType>();
outMatType *T = matT.ptr<outMatType>();
outMatType *FT = _FT.ptr<outMatType>();
int istep = (int)(matI.step/matI.elemSize());
int step = (int)(matS.step/matS.elemSize());
for( x = 0; x <= cols; x++ )
S[x] = T[x] = FT[x] = 0;
S += step; T += step; FT += step;
S[0] = T[0] = 0;
FT[0] = I[0];
for( x = 1; x < cols; x++ )
{
S[x] = S[x-1] + I[x-1];
T[x] = I[x-1];
FT[x] = I[x] + I[x-1];
}
S[cols] = S[cols-1] + I[cols-1];
T[cols] = FT[cols] = I[cols-1];
for( y = 2; y <= rows; y++ )
{
I += istep, S += step, T += step, FT += step;
S[0] = S[-step]; S[1] = S[-step+1] + I[0];
T[0] = T[-step + 1];
T[1] = FT[0] = T[-step + 2] + I[-istep] + I[0];
FT[1] = FT[-step + 2] + I[-istep] + I[1] + I[0];
for( x = 2; x < cols; x++ )
{
S[x] = S[x - 1] + S[-step + x] - S[-step + x - 1] + I[x - 1];
T[x] = T[-step + x - 1] + T[-step + x + 1] - T[-step*2 + x] + I[-istep + x - 1] + I[x - 1];
FT[x] = FT[-step + x - 1] + FT[-step + x + 1] - FT[-step*2 + x] + I[x] + I[x-1];
}
S[cols] = S[cols - 1] + S[-step + cols] - S[-step + cols - 1] + I[cols - 1];
T[cols] = FT[cols] = T[-step + cols - 1] + I[-istep + cols - 1] + I[cols - 1];
}
}
template <typename iiMatType> static int
StarDetectorComputeResponses( const Mat& img, Mat& responses, Mat& sizes,
int maxSize, int iiType )
{
const int MAX_PATTERN = 17;
static const int sizes0[] = {1, 2, 3, 4, 6, 8, 11, 12, 16, 22, 23, 32, 45, 46, 64, 90, 128, -1};
static const int pairs[][2] = {{1, 0}, {3, 1}, {4, 2}, {5, 3}, {7, 4}, {8, 5}, {9, 6},
{11, 8}, {13, 10}, {14, 11}, {15, 12}, {16, 14}, {-1, -1}};
float invSizes[MAX_PATTERN][2];
int sizes1[MAX_PATTERN];
#if CV_SSE2
__m128 invSizes4[MAX_PATTERN][2];
__m128 sizes1_4[MAX_PATTERN];
union { int i; float f; } absmask;
absmask.i = 0x7fffffff;
volatile bool useSIMD = cv::checkHardwareSupport(CV_CPU_SSE2) && iiType == CV_32S;
#endif
struct StarFeature
{
int area;
iiMatType* p[8];
};
StarFeature f[MAX_PATTERN];
Mat sum, tilted, flatTilted;
int y, rows = img.rows, cols = img.cols;
int border, npatterns=0, maxIdx=0;
responses.create( img.size(), CV_32F );
sizes.create( img.size(), CV_16S );
while( pairs[npatterns][0] >= 0 && !
( sizes0[pairs[npatterns][0]] >= maxSize
|| sizes0[pairs[npatterns+1][0]] + sizes0[pairs[npatterns+1][0]]/2 >= std::min(rows, cols) ) )
{
++npatterns;
}
npatterns += (pairs[npatterns-1][0] >= 0);
maxIdx = pairs[npatterns-1][0];
// Create the integral image appropriate for our type & usage
if ( img.type() == CV_8U )
computeIntegralImages<uchar, iiMatType>( img, sum, tilted, flatTilted, iiType );
else if ( img.type() == CV_8S )
computeIntegralImages<char, iiMatType>( img, sum, tilted, flatTilted, iiType );
else if ( img.type() == CV_16U )
computeIntegralImages<ushort, iiMatType>( img, sum, tilted, flatTilted, iiType );
else if ( img.type() == CV_16S )
computeIntegralImages<short, iiMatType>( img, sum, tilted, flatTilted, iiType );
else
CV_Error( Error::StsUnsupportedFormat, "" );
int step = (int)(sum.step/sum.elemSize());
for(int i = 0; i <= maxIdx; i++ )
{
int ur_size = sizes0[i], t_size = sizes0[i] + sizes0[i]/2;
int ur_area = (2*ur_size + 1)*(2*ur_size + 1);
int t_area = t_size*t_size + (t_size + 1)*(t_size + 1);
f[i].p[0] = sum.ptr<iiMatType>() + (ur_size + 1)*step + ur_size + 1;
f[i].p[1] = sum.ptr<iiMatType>() - ur_size*step + ur_size + 1;
f[i].p[2] = sum.ptr<iiMatType>() + (ur_size + 1)*step - ur_size;
f[i].p[3] = sum.ptr<iiMatType>() - ur_size*step - ur_size;
f[i].p[4] = tilted.ptr<iiMatType>() + (t_size + 1)*step + 1;
f[i].p[5] = flatTilted.ptr<iiMatType>() - t_size;
f[i].p[6] = flatTilted.ptr<iiMatType>() + t_size + 1;
f[i].p[7] = tilted.ptr<iiMatType>() - t_size*step + 1;
f[i].area = ur_area + t_area;
sizes1[i] = sizes0[i];
}
// negate end points of the size range
// for a faster rejection of very small or very large features in non-maxima suppression.
sizes1[0] = -sizes1[0];
sizes1[1] = -sizes1[1];
sizes1[maxIdx] = -sizes1[maxIdx];
border = sizes0[maxIdx] + sizes0[maxIdx]/2;
for(int i = 0; i < npatterns; i++ )
{
int innerArea = f[pairs[i][1]].area;
int outerArea = f[pairs[i][0]].area - innerArea;
invSizes[i][0] = 1.f/outerArea;
invSizes[i][1] = 1.f/innerArea;
}
#if CV_SSE2
if( useSIMD )
{
for(int i = 0; i < npatterns; i++ )
{
_mm_store_ps((float*)&invSizes4[i][0], _mm_set1_ps(invSizes[i][0]));
_mm_store_ps((float*)&invSizes4[i][1], _mm_set1_ps(invSizes[i][1]));
}
for(int i = 0; i <= maxIdx; i++ )
_mm_store_ps((float*)&sizes1_4[i], _mm_set1_ps((float)sizes1[i]));
}
#endif
for( y = 0; y < border; y++ )
{
float* r_ptr = responses.ptr<float>(y);
float* r_ptr2 = responses.ptr<float>(rows - 1 - y);
short* s_ptr = sizes.ptr<short>(y);
short* s_ptr2 = sizes.ptr<short>(rows - 1 - y);
memset( r_ptr, 0, cols*sizeof(r_ptr[0]));
memset( r_ptr2, 0, cols*sizeof(r_ptr2[0]));
memset( s_ptr, 0, cols*sizeof(s_ptr[0]));
memset( s_ptr2, 0, cols*sizeof(s_ptr2[0]));
}
for( y = border; y < rows - border; y++ )
{
int x = border;
float* r_ptr = responses.ptr<float>(y);
short* s_ptr = sizes.ptr<short>(y);
memset( r_ptr, 0, border*sizeof(r_ptr[0]));
memset( s_ptr, 0, border*sizeof(s_ptr[0]));
memset( r_ptr + cols - border, 0, border*sizeof(r_ptr[0]));
memset( s_ptr + cols - border, 0, border*sizeof(s_ptr[0]));
#if CV_SSE2
if( useSIMD )
{
__m128 absmask4 = _mm_set1_ps(absmask.f);
for( ; x <= cols - border - 4; x += 4 )
{
int ofs = y*step + x;
__m128 vals[MAX_PATTERN];
__m128 bestResponse = _mm_setzero_ps();
__m128 bestSize = _mm_setzero_ps();
for(int i = 0; i <= maxIdx; i++ )
{
const iiMatType** p = (const iiMatType**)&f[i].p[0];
__m128i r0 = _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(p[0]+ofs)),
_mm_loadu_si128((const __m128i*)(p[1]+ofs)));
__m128i r1 = _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(p[3]+ofs)),
_mm_loadu_si128((const __m128i*)(p[2]+ofs)));
__m128i r2 = _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(p[4]+ofs)),
_mm_loadu_si128((const __m128i*)(p[5]+ofs)));
__m128i r3 = _mm_sub_epi32(_mm_loadu_si128((const __m128i*)(p[7]+ofs)),
_mm_loadu_si128((const __m128i*)(p[6]+ofs)));
r0 = _mm_add_epi32(_mm_add_epi32(r0,r1), _mm_add_epi32(r2,r3));
_mm_store_ps((float*)&vals[i], _mm_cvtepi32_ps(r0));
}
for(int i = 0; i < npatterns; i++ )
{
__m128 inner_sum = vals[pairs[i][1]];
__m128 outer_sum = _mm_sub_ps(vals[pairs[i][0]], inner_sum);
__m128 response = _mm_sub_ps(_mm_mul_ps(inner_sum, invSizes4[i][1]),
_mm_mul_ps(outer_sum, invSizes4[i][0]));
__m128 swapmask = _mm_cmpgt_ps(_mm_and_ps(response,absmask4),
_mm_and_ps(bestResponse,absmask4));
bestResponse = _mm_xor_ps(bestResponse,
_mm_and_ps(_mm_xor_ps(response,bestResponse), swapmask));
bestSize = _mm_xor_ps(bestSize,
_mm_and_ps(_mm_xor_ps(sizes1_4[pairs[i][0]], bestSize), swapmask));
}
_mm_storeu_ps(r_ptr + x, bestResponse);
_mm_storel_epi64((__m128i*)(s_ptr + x),
_mm_packs_epi32(_mm_cvtps_epi32(bestSize),_mm_setzero_si128()));
}
}
#endif
for( ; x < cols - border; x++ )
{
int ofs = y*step + x;
int vals[MAX_PATTERN];
float bestResponse = 0;
int bestSize = 0;
for(int i = 0; i <= maxIdx; i++ )
{
const iiMatType** p = (const iiMatType**)&f[i].p[0];
vals[i] = (int)(p[0][ofs] - p[1][ofs] - p[2][ofs] + p[3][ofs] +
p[4][ofs] - p[5][ofs] - p[6][ofs] + p[7][ofs]);
}
for(int i = 0; i < npatterns; i++ )
{
int inner_sum = vals[pairs[i][1]];
int outer_sum = vals[pairs[i][0]] - inner_sum;
float response = inner_sum*invSizes[i][1] - outer_sum*invSizes[i][0];
if( fabs(response) > fabs(bestResponse) )
{
bestResponse = response;
bestSize = sizes1[pairs[i][0]];
}
}
r_ptr[x] = bestResponse;
s_ptr[x] = (short)bestSize;
}
}
return border;
}
static bool StarDetectorSuppressLines( const Mat& responses, const Mat& sizes, Point pt,
int lineThresholdProjected, int lineThresholdBinarized )
{
const float* r_ptr = responses.ptr<float>();
int rstep = (int)(responses.step/sizeof(r_ptr[0]));
const short* s_ptr = sizes.ptr<short>();
int sstep = (int)(sizes.step/sizeof(s_ptr[0]));
int sz = s_ptr[pt.y*sstep + pt.x];
int x, y, delta = sz/4, radius = delta*4;
float Lxx = 0, Lyy = 0, Lxy = 0;
int Lxxb = 0, Lyyb = 0, Lxyb = 0;
for( y = pt.y - radius; y <= pt.y + radius; y += delta )
for( x = pt.x - radius; x <= pt.x + radius; x += delta )
{
float Lx = r_ptr[y*rstep + x + 1] - r_ptr[y*rstep + x - 1];
float Ly = r_ptr[(y+1)*rstep + x] - r_ptr[(y-1)*rstep + x];
Lxx += Lx*Lx; Lyy += Ly*Ly; Lxy += Lx*Ly;
}
if( (Lxx + Lyy)*(Lxx + Lyy) >= lineThresholdProjected*(Lxx*Lyy - Lxy*Lxy) )
return true;
for( y = pt.y - radius; y <= pt.y + radius; y += delta )
for( x = pt.x - radius; x <= pt.x + radius; x += delta )
{
int Lxb = (s_ptr[y*sstep + x + 1] == sz) - (s_ptr[y*sstep + x - 1] == sz);
int Lyb = (s_ptr[(y+1)*sstep + x] == sz) - (s_ptr[(y-1)*sstep + x] == sz);
Lxxb += Lxb * Lxb; Lyyb += Lyb * Lyb; Lxyb += Lxb * Lyb;
}
if( (Lxxb + Lyyb)*(Lxxb + Lyyb) >= lineThresholdBinarized*(Lxxb*Lyyb - Lxyb*Lxyb) )
return true;
return false;
}
static void
StarDetectorSuppressNonmax( const Mat& responses, const Mat& sizes,
std::vector<KeyPoint>& keypoints, int border,
int responseThreshold,
int lineThresholdProjected,
int lineThresholdBinarized,
int suppressNonmaxSize )
{
int x, y, x1, y1, delta = suppressNonmaxSize/2;
int rows = responses.rows, cols = responses.cols;
const float* r_ptr = responses.ptr<float>();
int rstep = (int)(responses.step/sizeof(r_ptr[0]));
const short* s_ptr = sizes.ptr<short>();
int sstep = (int)(sizes.step/sizeof(s_ptr[0]));
short featureSize = 0;
for( y = border; y < rows - border; y += delta+1 )
for( x = border; x < cols - border; x += delta+1 )
{
float maxResponse = (float)responseThreshold;
float minResponse = (float)-responseThreshold;
Point maxPt(-1, -1), minPt(-1, -1);
int tileEndY = MIN(y + delta, rows - border - 1);
int tileEndX = MIN(x + delta, cols - border - 1);
for( y1 = y; y1 <= tileEndY; y1++ )
for( x1 = x; x1 <= tileEndX; x1++ )
{
float val = r_ptr[y1*rstep + x1];
if( maxResponse < val )
{
maxResponse = val;
maxPt = Point(x1, y1);
}
else if( minResponse > val )
{
minResponse = val;
minPt = Point(x1, y1);
}
}
if( maxPt.x >= 0 )
{
for( y1 = maxPt.y - delta; y1 <= maxPt.y + delta; y1++ )
for( x1 = maxPt.x - delta; x1 <= maxPt.x + delta; x1++ )
{
float val = r_ptr[y1*rstep + x1];
if( val >= maxResponse && (y1 != maxPt.y || x1 != maxPt.x))
goto skip_max;
}
if( (featureSize = s_ptr[maxPt.y*sstep + maxPt.x]) >= 4 &&
!StarDetectorSuppressLines( responses, sizes, maxPt, lineThresholdProjected,
lineThresholdBinarized ))
{
KeyPoint kpt((float)maxPt.x, (float)maxPt.y, featureSize, -1, maxResponse);
keypoints.push_back(kpt);
}
}
skip_max:
if( minPt.x >= 0 )
{
for( y1 = minPt.y - delta; y1 <= minPt.y + delta; y1++ )
for( x1 = minPt.x - delta; x1 <= minPt.x + delta; x1++ )
{
float val = r_ptr[y1*rstep + x1];
if( val <= minResponse && (y1 != minPt.y || x1 != minPt.x))
goto skip_min;
}
if( (featureSize = s_ptr[minPt.y*sstep + minPt.x]) >= 4 &&
!StarDetectorSuppressLines( responses, sizes, minPt,
lineThresholdProjected, lineThresholdBinarized))
{
KeyPoint kpt((float)minPt.x, (float)minPt.y, featureSize, -1, maxResponse);
keypoints.push_back(kpt);
}
}
skip_min:
;
}
}
StarDetector::StarDetector(int _maxSize, int _responseThreshold,
int _lineThresholdProjected,
int _lineThresholdBinarized,
int _suppressNonmaxSize)
: maxSize(_maxSize), responseThreshold(_responseThreshold),
lineThresholdProjected(_lineThresholdProjected),
lineThresholdBinarized(_lineThresholdBinarized),
suppressNonmaxSize(_suppressNonmaxSize)
{}
void StarDetector::detectImpl( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) const
{
Mat image = _image.getMat(), mask = _mask.getMat(), grayImage = image;
if( image.channels() > 1 ) cvtColor( image, grayImage, COLOR_BGR2GRAY );
(*this)(grayImage, keypoints);
KeyPointsFilter::runByPixelsMask( keypoints, mask );
}
void StarDetector::operator()(const Mat& img, std::vector<KeyPoint>& keypoints) const
{
Mat responses, sizes;
int border;
// Use 32-bit integers if we won't overflow in the integral image
if ((img.depth() == CV_8U || img.depth() == CV_8S) &&
(img.rows * img.cols) < 8388608 ) // 8388608 = 2 ^ (32 - 8(bit depth) - 1(sign bit))
border = StarDetectorComputeResponses<int>( img, responses, sizes, maxSize, CV_32S );
else
border = StarDetectorComputeResponses<double>( img, responses, sizes, maxSize, CV_64F );
keypoints.clear();
if( border >= 0 )
StarDetectorSuppressNonmax( responses, sizes, keypoints, border,
responseThreshold, lineThresholdProjected,
lineThresholdBinarized, suppressNonmaxSize );
}
}

@ -327,28 +327,6 @@ TEST( Features2d_DescriptorExtractor_ORB, regression )
test.safe_run();
}
TEST( Features2d_DescriptorExtractor_FREAK, regression )
{
// TODO adjust the parameters below
CV_DescriptorExtractorTest<Hamming> test( "descriptor-freak", (CV_DescriptorExtractorTest<Hamming>::DistanceType)12.f,
DescriptorExtractor::create("FREAK") );
test.safe_run();
}
TEST( Features2d_DescriptorExtractor_BRIEF, regression )
{
CV_DescriptorExtractorTest<Hamming> test( "descriptor-brief", 1,
DescriptorExtractor::create("BRIEF") );
test.safe_run();
}
TEST( Features2d_DescriptorExtractor_OpponentBRIEF, regression )
{
CV_DescriptorExtractorTest<Hamming> test( "descriptor-opponent-brief", 1,
DescriptorExtractor::create("OpponentBRIEF") );
test.safe_run();
}
TEST( Features2d_DescriptorExtractor_KAZE, regression )
{
CV_DescriptorExtractorTest< L2<float> > test( "descriptor-kaze", 0.03f,

@ -277,12 +277,6 @@ TEST( Features2d_Detector_MSER, DISABLED_regression )
test.safe_run();
}
TEST( Features2d_Detector_STAR, regression )
{
CV_FeatureDetectorTest test( "detector-star", FeatureDetector::create("STAR") );
test.safe_run();
}
TEST( Features2d_Detector_ORB, regression )
{
CV_FeatureDetectorTest test( "detector-orb", FeatureDetector::create("ORB") );
@ -300,15 +294,3 @@ TEST( Features2d_Detector_AKAZE, regression )
CV_FeatureDetectorTest test( "detector-akaze", FeatureDetector::create("AKAZE") );
test.safe_run();
}
TEST( Features2d_Detector_GridFAST, regression )
{
CV_FeatureDetectorTest test( "detector-grid-fast", FeatureDetector::create("GridFAST") );
test.safe_run();
}
TEST( Features2d_Detector_PyramidFAST, regression )
{
CV_FeatureDetectorTest test( "detector-pyramid-fast", FeatureDetector::create("PyramidFAST") );
test.safe_run();
}

@ -155,18 +155,6 @@ TEST(Features2d_Detector_Keypoints_ORB, validation)
test.safe_run();
}
TEST(Features2d_Detector_Keypoints_Star, validation)
{
CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.STAR"));
test.safe_run();
}
TEST(Features2d_Detector_Keypoints_Dense, validation)
{
CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.Dense"));
test.safe_run();
}
TEST(Features2d_Detector_Keypoints_KAZE, validation)
{
CV_FeatureDetectorKeypointsTest test(Algorithm::create<FeatureDetector>("Feature2D.KAZE"));

@ -840,6 +840,66 @@ typename Distance::ResultType ensureSquareDistance( typename Distance::ResultTyp
return dummy( dist );
}
/*
* ...and a template to ensure the user that he will process the normal distance,
* and not squared distance, without loosing processing time calling sqrt(ensureSquareDistance)
* that will result in doing actually sqrt(dist*dist) for L1 distance for instance.
*/
template <typename Distance, typename ElementType>
struct simpleDistance
{
typedef typename Distance::ResultType ResultType;
ResultType operator()( ResultType dist ) { return dist; }
};
template <typename ElementType>
struct simpleDistance<L2_Simple<ElementType>, ElementType>
{
typedef typename L2_Simple<ElementType>::ResultType ResultType;
ResultType operator()( ResultType dist ) { return sqrt(dist); }
};
template <typename ElementType>
struct simpleDistance<L2<ElementType>, ElementType>
{
typedef typename L2<ElementType>::ResultType ResultType;
ResultType operator()( ResultType dist ) { return sqrt(dist); }
};
template <typename ElementType>
struct simpleDistance<MinkowskiDistance<ElementType>, ElementType>
{
typedef typename MinkowskiDistance<ElementType>::ResultType ResultType;
ResultType operator()( ResultType dist ) { return sqrt(dist); }
};
template <typename ElementType>
struct simpleDistance<HellingerDistance<ElementType>, ElementType>
{
typedef typename HellingerDistance<ElementType>::ResultType ResultType;
ResultType operator()( ResultType dist ) { return sqrt(dist); }
};
template <typename ElementType>
struct simpleDistance<ChiSquareDistance<ElementType>, ElementType>
{
typedef typename ChiSquareDistance<ElementType>::ResultType ResultType;
ResultType operator()( ResultType dist ) { return sqrt(dist); }
};
template <typename Distance>
typename Distance::ResultType ensureSimpleDistance( typename Distance::ResultType dist )
{
typedef typename Distance::ElementType ElementType;
simpleDistance<Distance, ElementType> dummy;
return dummy( dist );
}
}
#endif //OPENCV_FLANN_DIST_H_

@ -154,7 +154,7 @@ bool Jpeg2KDecoder::readData( Mat& img )
{
bool result = false;
int color = img.channels() > 1;
uchar* data = img.data;
uchar* data = img.ptr();
int step = (int)img.step;
jas_stream_t* stream = (jas_stream_t*)m_stream;
jas_image_t* image = (jas_image_t*)m_image;
@ -478,7 +478,7 @@ bool Jpeg2KEncoder::writeComponent8u( void *__img, const Mat& _img )
for( int y = 0; y < h; y++ )
{
uchar* data = _img.data + _img.step*y;
const uchar* data = _img.ptr(y);
for( int i = 0; i < ncmpts; i++ )
{
for( int x = 0; x < w; x++)
@ -502,7 +502,7 @@ bool Jpeg2KEncoder::writeComponent16u( void *__img, const Mat& _img )
for( int y = 0; y < h; y++ )
{
uchar* data = _img.data + _img.step*y;
const uchar* data = _img.ptr(y);
for( int i = 0; i < ncmpts; i++ )
{
for( int x = 0; x < w; x++)

@ -138,9 +138,9 @@ static ImageDecoder findDecoder( const Mat& buf )
maxlen = std::max(maxlen, len);
}
String signature(maxlen, ' ');
size_t bufSize = buf.rows*buf.cols*buf.elemSize();
maxlen = std::min(maxlen, bufSize);
String signature(maxlen, ' ');
memcpy( (void*)signature.c_str(), buf.data, maxlen );
for( i = 0; i < codecs.decoders.size(); i++ )

@ -0,0 +1,107 @@
ColorMaps in OpenCV
===================
applyColorMap
---------------------
Applies a GNU Octave/MATLAB equivalent colormap on a given image.
.. ocv:function:: void applyColorMap(InputArray src, OutputArray dst, int colormap)
:param src: The source image, grayscale or colored does not matter.
:param dst: The result is the colormapped source image. Note: :ocv:func:`Mat::create` is called on dst.
:param colormap: The colormap to apply, see the list of available colormaps below.
Currently the following GNU Octave/MATLAB equivalent colormaps are implemented:
.. code-block:: cpp
enum
{
COLORMAP_AUTUMN = 0,
COLORMAP_BONE = 1,
COLORMAP_JET = 2,
COLORMAP_WINTER = 3,
COLORMAP_RAINBOW = 4,
COLORMAP_OCEAN = 5,
COLORMAP_SUMMER = 6,
COLORMAP_SPRING = 7,
COLORMAP_COOL = 8,
COLORMAP_HSV = 9,
COLORMAP_PINK = 10,
COLORMAP_HOT = 11
}
Description
-----------
The human perception isn't built for observing fine changes in grayscale images. Human eyes are more sensitive to observing changes between colors, so you often need to recolor your grayscale images to get a clue about them. OpenCV now comes with various colormaps to enhance the visualization in your computer vision application.
In OpenCV 2.4 you only need :ocv:func:`applyColorMap` to apply a colormap on a given image. The following sample code reads the path to an image from command line, applies a Jet colormap on it and shows the result:
.. code-block:: cpp
#include <opencv2/contrib.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
int main(int argc, const char *argv[]) {
// Get the path to the image, if it was given
// if no arguments were given.
String filename;
if (argc > 1) {
filename = String(argv[1]);
}
// The following lines show how to apply a colormap on a given image
// and show it with cv::imshow example with an image. An exception is
// thrown if the path to the image is invalid.
if(!filename.empty()) {
Mat img0 = imread(filename);
// Throw an exception, if the image can't be read:
if(img0.empty()) {
CV_Error(CV_StsBadArg, "Sample image is empty. Please adjust your path, so it points to a valid input image!");
}
// Holds the colormap version of the image:
Mat cm_img0;
// Apply the colormap:
applyColorMap(img0, cm_img0, COLORMAP_JET);
// Show the result:
imshow("cm_img0", cm_img0);
waitKey(0);
}
return 0;
}
And here are the color scales for each of the available colormaps:
+-----------------------+---------------------------------------------------+
| Class | Scale |
+=======================+===================================================+
| COLORMAP_AUTUMN | .. image:: pics/colormaps/colorscale_autumn.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_BONE | .. image:: pics/colormaps/colorscale_bone.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_COOL | .. image:: pics/colormaps/colorscale_cool.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_HOT | .. image:: pics/colormaps/colorscale_hot.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_HSV | .. image:: pics/colormaps/colorscale_hsv.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_JET | .. image:: pics/colormaps/colorscale_jet.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_OCEAN | .. image:: pics/colormaps/colorscale_ocean.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_PINK | .. image:: pics/colormaps/colorscale_pink.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_RAINBOW | .. image:: pics/colormaps/colorscale_rainbow.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_SPRING | .. image:: pics/colormaps/colorscale_spring.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_SUMMER | .. image:: pics/colormaps/colorscale_summer.jpg |
+-----------------------+---------------------------------------------------+
| COLORMAP_WINTER | .. image:: pics/colormaps/colorscale_winter.jpg |
+-----------------------+---------------------------------------------------+

@ -504,6 +504,8 @@ Constructs the Gaussian pyramid for an image.
:param maxlevel: 0-based index of the last (the smallest) pyramid layer. It must be non-negative.
:param borderType: Pixel extrapolation method (BORDER_CONSTANT don't supported). See :ocv:func:`borderInterpolate` for details.
The function constructs a vector of images and builds the Gaussian pyramid by recursively applying
:ocv:func:`pyrDown` to the previously built pyramid layers, starting from ``dst[0]==src`` .
@ -1256,12 +1258,16 @@ Blurs an image and downsamples it.
:param dst: output image; it has the specified size and the same type as ``src``.
:param dstsize: size of the output image; by default, it is computed as ``Size((src.cols+1)/2, (src.rows+1)/2)``, but in any case, the following conditions should be satisfied:
:param dstsize: size of the output image.
.. math::
:param borderType: Pixel extrapolation method (BORDER_CONSTANT don't supported). See :ocv:func:`borderInterpolate` for details.
By default, size of the output image is computed as ``Size((src.cols+1)/2, (src.rows+1)/2)``, but in any case, the following conditions should be satisfied:
\begin{array}{l}
| \texttt{dstsize.width} *2-src.cols| \leq 2 \\ | \texttt{dstsize.height} *2-src.rows| \leq 2 \end{array}
.. math::
\begin{array}{l}
| \texttt{dstsize.width} *2-src.cols| \leq 2 \\ | \texttt{dstsize.height} *2-src.rows| \leq 2 \end{array}
The function performs the downsampling step of the Gaussian pyramid construction. First, it convolves the source image with the kernel:
@ -1271,8 +1277,6 @@ The function performs the downsampling step of the Gaussian pyramid construction
Then, it downsamples the image by rejecting even rows and columns.
pyrUp
-----
Upsamples an image and then blurs it.
@ -1287,12 +1291,16 @@ Upsamples an image and then blurs it.
:param dst: output image. It has the specified size and the same type as ``src`` .
:param dstsize: size of the output image; by default, it is computed as ``Size(src.cols*2, (src.rows*2)``, but in any case, the following conditions should be satisfied:
:param dstsize: size of the output image.
.. math::
:param borderType: Pixel extrapolation method (only BORDER_DEFAULT supported). See :ocv:func:`borderInterpolate` for details.
By default, size of the output image is computed as ``Size(src.cols*2, (src.rows*2)``, but in any case, the following conditions should be satisfied:
.. math::
\begin{array}{l}
| \texttt{dstsize.width} -src.cols*2| \leq ( \texttt{dstsize.width} \mod 2) \\ | \texttt{dstsize.height} -src.rows*2| \leq ( \texttt{dstsize.height} \mod 2) \end{array}
\begin{array}{l}
| \texttt{dstsize.width} -src.cols*2| \leq ( \texttt{dstsize.width} \mod 2) \\ | \texttt{dstsize.height} -src.rows*2| \leq ( \texttt{dstsize.height} \mod 2) \end{array}
The function performs the upsampling step of the Gaussian pyramid construction, though it can actually be used to construct the Laplacian pyramid. First, it upsamples the source image by injecting even zero rows and columns and then convolves the result with the same kernel as in
:ocv:func:`pyrDown` multiplied by 4.

@ -10,6 +10,7 @@ imgproc. Image Processing
filtering
geometric_transformations
miscellaneous_transformations
colormaps
histograms
structural_analysis_and_shape_descriptors
motion_analysis_and_object_tracking

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -1518,6 +1518,24 @@ CV_EXPORTS Ptr<GeneralizedHoughGuil> createGeneralizedHoughGuil();
//! Performs linear blending of two images
CV_EXPORTS void blendLinear(InputArray src1, InputArray src2, InputArray weights1, InputArray weights2, OutputArray dst);
enum
{
COLORMAP_AUTUMN = 0,
COLORMAP_BONE = 1,
COLORMAP_JET = 2,
COLORMAP_WINTER = 3,
COLORMAP_RAINBOW = 4,
COLORMAP_OCEAN = 5,
COLORMAP_SUMMER = 6,
COLORMAP_SPRING = 7,
COLORMAP_COOL = 8,
COLORMAP_HSV = 9,
COLORMAP_PINK = 10,
COLORMAP_HOT = 11
};
CV_EXPORTS_W void applyColorMap(InputArray src, OutputArray dst, int colormap);
} // cv
#endif

@ -126,10 +126,11 @@ namespace clahe
namespace
{
template <class T, int histSize, int shift>
class CLAHE_CalcLut_Body : public cv::ParallelLoopBody
{
public:
CLAHE_CalcLut_Body(const cv::Mat& src, cv::Mat& lut, cv::Size tileSize, int tilesX, int clipLimit, float lutScale) :
CLAHE_CalcLut_Body(const cv::Mat& src, const cv::Mat& lut, const cv::Size& tileSize, const int& tilesX, const int& clipLimit, const float& lutScale) :
src_(src), lut_(lut), tileSize_(tileSize), tilesX_(tilesX), clipLimit_(clipLimit), lutScale_(lutScale)
{
}
@ -146,12 +147,11 @@ namespace
float lutScale_;
};
void CLAHE_CalcLut_Body::operator ()(const cv::Range& range) const
template <class T, int histSize, int shift>
void CLAHE_CalcLut_Body<T,histSize,shift>::operator ()(const cv::Range& range) const
{
const int histSize = 256;
uchar* tileLut = lut_.ptr(range.start);
const size_t lut_step = lut_.step;
T* tileLut = lut_.ptr<T>(range.start);
const size_t lut_step = lut_.step / sizeof(T);
for (int k = range.start; k < range.end; ++k, tileLut += lut_step)
{
@ -173,20 +173,20 @@ namespace
int tileHist[histSize] = {0, };
int height = tileROI.height;
const size_t sstep = tile.step;
for (const uchar* ptr = tile.ptr<uchar>(0); height--; ptr += sstep)
const size_t sstep = src_.step / sizeof(T);
for (const T* ptr = tile.ptr<T>(0); height--; ptr += sstep)
{
int x = 0;
for (; x <= tileROI.width - 4; x += 4)
{
int t0 = ptr[x], t1 = ptr[x+1];
tileHist[t0]++; tileHist[t1]++;
tileHist[t0 >> shift]++; tileHist[t1 >> shift]++;
t0 = ptr[x+2]; t1 = ptr[x+3];
tileHist[t0]++; tileHist[t1]++;
tileHist[t0 >> shift]++; tileHist[t1 >> shift]++;
}
for (; x < tileROI.width; ++x)
tileHist[ptr[x]]++;
tileHist[ptr[x] >> shift]++;
}
// clip histogram
@ -221,15 +221,16 @@ namespace
for (int i = 0; i < histSize; ++i)
{
sum += tileHist[i];
tileLut[i] = cv::saturate_cast<uchar>(sum * lutScale_);
tileLut[i] = cv::saturate_cast<T>(sum * lutScale_);
}
}
}
template <class T>
class CLAHE_Interpolation_Body : public cv::ParallelLoopBody
{
public:
CLAHE_Interpolation_Body(const cv::Mat& src, cv::Mat& dst, const cv::Mat& lut, cv::Size tileSize, int tilesX, int tilesY) :
CLAHE_Interpolation_Body(const cv::Mat& src, const cv::Mat& dst, const cv::Mat& lut, const cv::Size& tileSize, const int& tilesX, const int& tilesY) :
src_(src), dst_(dst), lut_(lut), tileSize_(tileSize), tilesX_(tilesX), tilesY_(tilesY)
{
}
@ -246,14 +247,15 @@ namespace
int tilesY_;
};
void CLAHE_Interpolation_Body::operator ()(const cv::Range& range) const
template <class T>
void CLAHE_Interpolation_Body<T>::operator ()(const cv::Range& range) const
{
const size_t lut_step = lut_.step;
const size_t lut_step = lut_.step / sizeof(T);
for (int y = range.start; y < range.end; ++y)
{
const uchar* srcRow = src_.ptr<uchar>(y);
uchar* dstRow = dst_.ptr<uchar>(y);
const T* srcRow = src_.ptr<T>(y);
T* dstRow = dst_.ptr<T>(y);
const float tyf = (static_cast<float>(y) / tileSize_.height) - 0.5f;
@ -265,8 +267,8 @@ namespace
ty1 = std::max(ty1, 0);
ty2 = std::min(ty2, tilesY_ - 1);
const uchar* lutPlane1 = lut_.ptr(ty1 * tilesX_);
const uchar* lutPlane2 = lut_.ptr(ty2 * tilesX_);
const T* lutPlane1 = lut_.ptr<T>(ty1 * tilesX_);
const T* lutPlane2 = lut_.ptr<T>(ty2 * tilesX_);
for (int x = 0; x < src_.cols; ++x)
{
@ -292,7 +294,7 @@ namespace
res += lutPlane2[ind1] * ((1.0f - xa) * (ya));
res += lutPlane2[ind2] * ((xa) * (ya));
dstRow[x] = cv::saturate_cast<uchar>(res);
dstRow[x] = cv::saturate_cast<T>(res);
}
}
}
@ -340,13 +342,13 @@ namespace
void CLAHE_Impl::apply(cv::InputArray _src, cv::OutputArray _dst)
{
CV_Assert( _src.type() == CV_8UC1 );
CV_Assert( _src.type() == CV_8UC1 || _src.type() == CV_16UC1 );
#ifdef HAVE_OPENCL
bool useOpenCL = cv::ocl::useOpenCL() && _src.isUMat() && _src.dims()<=2;
bool useOpenCL = cv::ocl::useOpenCL() && _src.isUMat() && _src.dims()<=2 && _src.type() == CV_8UC1;
#endif
const int histSize = 256;
int histSize = _src.type() == CV_8UC1 ? 256 : 4096;
cv::Size tileSize;
cv::_InputArray _srcForLut;
@ -394,13 +396,23 @@ namespace
_dst.create( src.size(), src.type() );
cv::Mat dst = _dst.getMat();
cv::Mat srcForLut = _srcForLut.getMat();
lut_.create(tilesX_ * tilesY_, histSize, CV_8UC1);
CLAHE_CalcLut_Body calcLutBody(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale);
cv::parallel_for_(cv::Range(0, tilesX_ * tilesY_), calcLutBody);
CLAHE_Interpolation_Body interpolationBody(src, dst, lut_, tileSize, tilesX_, tilesY_);
cv::parallel_for_(cv::Range(0, src.rows), interpolationBody);
lut_.create(tilesX_ * tilesY_, histSize, _src.type());
cv::Ptr<cv::ParallelLoopBody> calcLutBody;
if (_src.type() == CV_8UC1)
calcLutBody = cv::makePtr<CLAHE_CalcLut_Body<uchar, 256, 0> >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale);
else if (_src.type() == CV_16UC1)
calcLutBody = cv::makePtr<CLAHE_CalcLut_Body<ushort, 4096, 4> >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale);
CV_Assert(!calcLutBody.empty());
cv::parallel_for_(cv::Range(0, tilesX_ * tilesY_), *calcLutBody);
cv::Ptr<cv::ParallelLoopBody> interpolationBody;
if (_src.type() == CV_8UC1)
interpolationBody = cv::makePtr<CLAHE_Interpolation_Body<uchar> >(src, dst, lut_, tileSize, tilesX_, tilesY_);
else if (_src.type() == CV_16UC1)
interpolationBody = cv::makePtr<CLAHE_Interpolation_Body<ushort> >(src, dst, lut_, tileSize, tilesX_, tilesY_);
CV_Assert(!interpolationBody.empty());
cv::parallel_for_(cv::Range(0, src.rows), *interpolationBody);
}
void CLAHE_Impl::setClipLimit(double clipLimit)

@ -3381,18 +3381,16 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
_dst.create(sz, CV_8UC2);
dst = _dst.getMat();
#ifdef HAVE_IPP
#if defined(HAVE_IPP) && 0 // breaks OCL accuracy tests
CV_SUPPRESS_DEPRECATED_START
#if 0
if (code == CV_BGR2BGR565 && scn == 3)
{
if (CvtColorIPPLoop(src, dst, IPPGeneralFunctor((ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R)))
return;
setIppErrorStatus();
}
else
#endif
if (code == CV_BGRA2BGR565 && scn == 4)
else if (code == CV_BGRA2BGR565 && scn == 4)
{
if (CvtColorIPPLoopCopy(src, dst,
IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
@ -3787,6 +3785,7 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
if( depth == CV_8U || depth == CV_16U )
{
#if 0 // breaks OCL accuracy tests
if( code == CV_BGR2HSV_FULL && scn == 3 )
{
if( CvtColorIPPLoopCopy(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) )
@ -3799,15 +3798,16 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
return;
setIppErrorStatus();
}
else if( code == CV_RGB2HSV_FULL && scn == 3 && depth == CV_16U )
else if( code == CV_RGB2HSV_FULL && scn == 4 )
{
if( CvtColorIPPLoopCopy(src, dst, IPPGeneralFunctor(ippiRGB2HSVTab[depth])) )
if( CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 0, 1, 2, depth)) )
return;
setIppErrorStatus();
}
else if( code == CV_RGB2HSV_FULL && scn == 4 )
} else
#endif
if( code == CV_RGB2HSV_FULL && scn == 3 && depth == CV_16U )
{
if( CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 0, 1, 2, depth)) )
if( CvtColorIPPLoopCopy(src, dst, IPPGeneralFunctor(ippiRGB2HSVTab[depth])) )
return;
setIppErrorStatus();
}

@ -0,0 +1,530 @@
/*
* Copyright (c) 2011. Philipp Wagner <bytefish[at]gmx[dot]de>.
* Released to public domain under terms of the BSD Simplified license.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the organization nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* See <http://www.opensource.org/licenses/bsd-license>
*/
#include "precomp.hpp"
#include <iostream>
#ifdef _MSC_VER
#pragma warning( disable: 4305 )
#endif
namespace cv
{
static Mat linspace(float x0, float x1, int n)
{
Mat pts(n, 1, CV_32FC1);
float step = (x1-x0)/(n-1);
for(int i = 0; i < n; i++)
pts.at<float>(i,0) = x0+i*step;
return pts;
}
//------------------------------------------------------------------------------
// cv::sortMatrixRowsByIndices
//------------------------------------------------------------------------------
static void sortMatrixRowsByIndices(InputArray _src, InputArray _indices, OutputArray _dst)
{
if(_indices.getMat().type() != CV_32SC1)
CV_Error(Error::StsUnsupportedFormat, "cv::sortRowsByIndices only works on integer indices!");
Mat src = _src.getMat();
std::vector<int> indices = _indices.getMat();
_dst.create(src.rows, src.cols, src.type());
Mat dst = _dst.getMat();
for(size_t idx = 0; idx < indices.size(); idx++) {
Mat originalRow = src.row(indices[idx]);
Mat sortedRow = dst.row((int)idx);
originalRow.copyTo(sortedRow);
}
}
static Mat sortMatrixRowsByIndices(InputArray src, InputArray indices)
{
Mat dst;
sortMatrixRowsByIndices(src, indices, dst);
return dst;
}
static Mat argsort(InputArray _src, bool ascending=true)
{
Mat src = _src.getMat();
if (src.rows != 1 && src.cols != 1)
CV_Error(Error::StsBadArg, "cv::argsort only sorts 1D matrices.");
int flags = SORT_EVERY_ROW | (ascending ? SORT_ASCENDING : SORT_DESCENDING);
Mat sorted_indices;
sortIdx(src.reshape(1,1),sorted_indices,flags);
return sorted_indices;
}
template <typename _Tp> static
Mat interp1_(const Mat& X_, const Mat& Y_, const Mat& XI)
{
int n = XI.rows;
// sort input table
std::vector<int> sort_indices = argsort(X_);
Mat X = sortMatrixRowsByIndices(X_,sort_indices);
Mat Y = sortMatrixRowsByIndices(Y_,sort_indices);
// interpolated values
Mat yi = Mat::zeros(XI.size(), XI.type());
for(int i = 0; i < n; i++) {
int c = 0;
int low = 0;
int high = X.rows - 1;
// set bounds
if(XI.at<_Tp>(i,0) < X.at<_Tp>(low, 0))
high = 1;
if(XI.at<_Tp>(i,0) > X.at<_Tp>(high, 0))
low = high - 1;
// binary search
while((high-low)>1) {
c = low + ((high - low) >> 1);
if(XI.at<_Tp>(i,0) > X.at<_Tp>(c,0)) {
low = c;
} else {
high = c;
}
}
// linear interpolation
yi.at<_Tp>(i,0) += Y.at<_Tp>(low,0)
+ (XI.at<_Tp>(i,0) - X.at<_Tp>(low,0))
* (Y.at<_Tp>(high,0) - Y.at<_Tp>(low,0))
/ (X.at<_Tp>(high,0) - X.at<_Tp>(low,0));
}
return yi;
}
static Mat interp1(InputArray _x, InputArray _Y, InputArray _xi)
{
// get matrices
Mat x = _x.getMat();
Mat Y = _Y.getMat();
Mat xi = _xi.getMat();
// check types & alignment
CV_Assert((x.type() == Y.type()) && (Y.type() == xi.type()));
CV_Assert((x.cols == 1) && (x.rows == Y.rows) && (x.cols == Y.cols));
// call templated interp1
switch(x.type()) {
case CV_8SC1: return interp1_<char>(x,Y,xi); break;
case CV_8UC1: return interp1_<unsigned char>(x,Y,xi); break;
case CV_16SC1: return interp1_<short>(x,Y,xi); break;
case CV_16UC1: return interp1_<unsigned short>(x,Y,xi); break;
case CV_32SC1: return interp1_<int>(x,Y,xi); break;
case CV_32FC1: return interp1_<float>(x,Y,xi); break;
case CV_64FC1: return interp1_<double>(x,Y,xi); break;
default: CV_Error(Error::StsUnsupportedFormat, ""); break;
}
return Mat();
}
namespace colormap
{
class ColorMap {
protected:
Mat _lut;
public:
virtual ~ColorMap() {}
// Applies the colormap on a given image.
//
// This function expects BGR-aligned data of type CV_8UC1 or
// CV_8UC3. If the wrong image type is given, the original image
// will be returned.
//
// Throws an error for wrong-aligned lookup table, which must be
// of size 256 in the latest OpenCV release (2.3.1).
void operator()(InputArray src, OutputArray dst) const;
// Setup base map to interpolate from.
virtual void init(int n) = 0;
// Interpolates from a base colormap.
static Mat linear_colormap(InputArray X,
InputArray r, InputArray g, InputArray b,
int n) {
return linear_colormap(X,r,g,b,linspace(0,1,n));
}
// Interpolates from a base colormap.
static Mat linear_colormap(InputArray X,
InputArray r, InputArray g, InputArray b,
float begin, float end, float n) {
return linear_colormap(X,r,g,b,linspace(begin,end, cvRound(n)));
}
// Interpolates from a base colormap.
static Mat linear_colormap(InputArray X,
InputArray r, InputArray g, InputArray b,
InputArray xi);
};
// Equals the GNU Octave colormap "autumn".
class Autumn : public ColorMap {
public:
Autumn() : ColorMap() {
init(256);
}
Autumn(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
float g[] = { 0, 0.01587301587301587, 0.03174603174603174, 0.04761904761904762, 0.06349206349206349, 0.07936507936507936, 0.09523809523809523, 0.1111111111111111, 0.126984126984127, 0.1428571428571428, 0.1587301587301587, 0.1746031746031746, 0.1904761904761905, 0.2063492063492063, 0.2222222222222222, 0.2380952380952381, 0.253968253968254, 0.2698412698412698, 0.2857142857142857, 0.3015873015873016, 0.3174603174603174, 0.3333333333333333, 0.3492063492063492, 0.3650793650793651, 0.3809523809523809, 0.3968253968253968, 0.4126984126984127, 0.4285714285714285, 0.4444444444444444, 0.4603174603174603, 0.4761904761904762, 0.492063492063492, 0.5079365079365079, 0.5238095238095238, 0.5396825396825397, 0.5555555555555556, 0.5714285714285714, 0.5873015873015873, 0.6031746031746031, 0.6190476190476191, 0.6349206349206349, 0.6507936507936508, 0.6666666666666666, 0.6825396825396826, 0.6984126984126984, 0.7142857142857143, 0.7301587301587301, 0.746031746031746, 0.7619047619047619, 0.7777777777777778, 0.7936507936507936, 0.8095238095238095, 0.8253968253968254, 0.8412698412698413, 0.8571428571428571, 0.873015873015873, 0.8888888888888888, 0.9047619047619048, 0.9206349206349206, 0.9365079365079365, 0.9523809523809523, 0.9682539682539683, 0.9841269841269841, 1};
float b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "bone".
class Bone : public ColorMap {
public:
Bone() : ColorMap() {
init(256);
}
Bone(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 0, 0.01388888888888889, 0.02777777777777778, 0.04166666666666666, 0.05555555555555555, 0.06944444444444445, 0.08333333333333333, 0.09722222222222221, 0.1111111111111111, 0.125, 0.1388888888888889, 0.1527777777777778, 0.1666666666666667, 0.1805555555555556, 0.1944444444444444, 0.2083333333333333, 0.2222222222222222, 0.2361111111111111, 0.25, 0.2638888888888889, 0.2777777777777778, 0.2916666666666666, 0.3055555555555555, 0.3194444444444444, 0.3333333333333333, 0.3472222222222222, 0.3611111111111111, 0.375, 0.3888888888888888, 0.4027777777777777, 0.4166666666666666, 0.4305555555555555, 0.4444444444444444, 0.4583333333333333, 0.4722222222222222, 0.4861111111111112, 0.5, 0.5138888888888888, 0.5277777777777778, 0.5416666666666667, 0.5555555555555556, 0.5694444444444444, 0.5833333333333333, 0.5972222222222222, 0.611111111111111, 0.6249999999999999, 0.6388888888888888, 0.6527777777777778, 0.6726190476190474, 0.6944444444444442, 0.7162698412698412, 0.7380952380952381, 0.7599206349206349, 0.7817460317460316, 0.8035714285714286, 0.8253968253968254, 0.8472222222222221, 0.8690476190476188, 0.8908730158730158, 0.9126984126984128, 0.9345238095238095, 0.9563492063492063, 0.978174603174603, 1};
float g[] = { 0, 0.01388888888888889, 0.02777777777777778, 0.04166666666666666, 0.05555555555555555, 0.06944444444444445, 0.08333333333333333, 0.09722222222222221, 0.1111111111111111, 0.125, 0.1388888888888889, 0.1527777777777778, 0.1666666666666667, 0.1805555555555556, 0.1944444444444444, 0.2083333333333333, 0.2222222222222222, 0.2361111111111111, 0.25, 0.2638888888888889, 0.2777777777777778, 0.2916666666666666, 0.3055555555555555, 0.3194444444444444, 0.3353174603174602, 0.3544973544973544, 0.3736772486772486, 0.3928571428571428, 0.412037037037037, 0.4312169312169312, 0.4503968253968254, 0.4695767195767195, 0.4887566137566137, 0.5079365079365078, 0.5271164021164021, 0.5462962962962963, 0.5654761904761904, 0.5846560846560845, 0.6038359788359787, 0.623015873015873, 0.6421957671957671, 0.6613756613756612, 0.6805555555555555, 0.6997354497354497, 0.7189153439153438, 0.7380952380952379, 0.7572751322751322, 0.7764550264550264, 0.7916666666666666, 0.8055555555555555, 0.8194444444444444, 0.8333333333333334, 0.8472222222222222, 0.861111111111111, 0.875, 0.8888888888888888, 0.9027777777777777, 0.9166666666666665, 0.9305555555555555, 0.9444444444444444, 0.9583333333333333, 0.9722222222222221, 0.986111111111111, 1};
float b[] = { 0, 0.01917989417989418, 0.03835978835978836, 0.05753968253968253, 0.07671957671957672, 0.09589947089947089, 0.1150793650793651, 0.1342592592592592, 0.1534391534391534, 0.1726190476190476, 0.1917989417989418, 0.210978835978836, 0.2301587301587301, 0.2493386243386243, 0.2685185185185185, 0.2876984126984127, 0.3068783068783069, 0.326058201058201, 0.3452380952380952, 0.3644179894179894, 0.3835978835978835, 0.4027777777777777, 0.4219576719576719, 0.4411375661375661, 0.4583333333333333, 0.4722222222222222, 0.4861111111111111, 0.5, 0.5138888888888888, 0.5277777777777777, 0.5416666666666666, 0.5555555555555556, 0.5694444444444444, 0.5833333333333333, 0.5972222222222222, 0.6111111111111112, 0.625, 0.6388888888888888, 0.6527777777777778, 0.6666666666666667, 0.6805555555555556, 0.6944444444444444, 0.7083333333333333, 0.7222222222222222, 0.736111111111111, 0.7499999999999999, 0.7638888888888888, 0.7777777777777778, 0.7916666666666666, 0.8055555555555555, 0.8194444444444444, 0.8333333333333334, 0.8472222222222222, 0.861111111111111, 0.875, 0.8888888888888888, 0.9027777777777777, 0.9166666666666665, 0.9305555555555555, 0.9444444444444444, 0.9583333333333333, 0.9722222222222221, 0.986111111111111, 1};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "jet".
class Jet : public ColorMap {
public:
Jet() {
init(256);
}
Jet(int n) : ColorMap() {
init(n);
}
void init(int n) {
// breakpoints
Mat X = linspace(0,1,256);
// define the basemap
float r[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.00588235294117645,0.02156862745098032,0.03725490196078418,0.05294117647058827,0.06862745098039214,0.084313725490196,0.1000000000000001,0.115686274509804,0.1313725490196078,0.1470588235294117,0.1627450980392156,0.1784313725490196,0.1941176470588235,0.2098039215686274,0.2254901960784315,0.2411764705882353,0.2568627450980392,0.2725490196078431,0.2882352941176469,0.303921568627451,0.3196078431372549,0.3352941176470587,0.3509803921568628,0.3666666666666667,0.3823529411764706,0.3980392156862744,0.4137254901960783,0.4294117647058824,0.4450980392156862,0.4607843137254901,0.4764705882352942,0.4921568627450981,0.5078431372549019,0.5235294117647058,0.5392156862745097,0.5549019607843135,0.5705882352941174,0.5862745098039217,0.6019607843137256,0.6176470588235294,0.6333333333333333,0.6490196078431372,0.664705882352941,0.6803921568627449,0.6960784313725492,0.7117647058823531,0.7274509803921569,0.7431372549019608,0.7588235294117647,0.7745098039215685,0.7901960784313724,0.8058823529411763,0.8215686274509801,0.8372549019607844,0.8529411764705883,0.8686274509803922,0.884313725490196,0.8999999999999999,0.9156862745098038,0.9313725490196076,0.947058823529412,0.9627450980392158,0.9784313725490197,0.9941176470588236,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.9862745098039216,0.9705882352941178,0.9549019607843139,0.93921568627451,0.9235294117647062,0.9078431372549018,0.892156862745098,0.8764705882352941,0.8607843137254902,0.8450980392156864,0.8294117647058825,0.8137254901960786,0.7980392156862743,0.7823529411764705,0.7666666666666666,0.7509803921568627,0.7352941176470589,0.719607843137255,0.7039215686274511,0.6882352941176473,0.6725490196078434,0.6568627450980391,0.6411764705882352,0.6254901960784314,0.6098039215686275,0.5941176470588236,0.5784313725490198,0.5627450980392159,0.5470588235294116,0.5313725490196077,0.5156862745098039,0.5};
float g[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.001960784313725483,0.01764705882352935,0.03333333333333333,0.0490196078431373,0.06470588235294117,0.08039215686274503,0.09607843137254901,0.111764705882353,0.1274509803921569,0.1431372549019607,0.1588235294117647,0.1745098039215687,0.1901960784313725,0.2058823529411764,0.2215686274509804,0.2372549019607844,0.2529411764705882,0.2686274509803921,0.2843137254901961,0.3,0.3156862745098039,0.3313725490196078,0.3470588235294118,0.3627450980392157,0.3784313725490196,0.3941176470588235,0.4098039215686274,0.4254901960784314,0.4411764705882353,0.4568627450980391,0.4725490196078431,0.4882352941176471,0.503921568627451,0.5196078431372548,0.5352941176470587,0.5509803921568628,0.5666666666666667,0.5823529411764705,0.5980392156862746,0.6137254901960785,0.6294117647058823,0.6450980392156862,0.6607843137254901,0.6764705882352942,0.692156862745098,0.7078431372549019,0.723529411764706,0.7392156862745098,0.7549019607843137,0.7705882352941176,0.7862745098039214,0.8019607843137255,0.8176470588235294,0.8333333333333333,0.8490196078431373,0.8647058823529412,0.8803921568627451,0.8960784313725489,0.9117647058823528,0.9274509803921569,0.9431372549019608,0.9588235294117646,0.9745098039215687,0.9901960784313726,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.9901960784313726,0.9745098039215687,0.9588235294117649,0.943137254901961,0.9274509803921571,0.9117647058823528,0.8960784313725489,0.8803921568627451,0.8647058823529412,0.8490196078431373,0.8333333333333335,0.8176470588235296,0.8019607843137253,0.7862745098039214,0.7705882352941176,0.7549019607843137,0.7392156862745098,0.723529411764706,0.7078431372549021,0.6921568627450982,0.6764705882352944,0.6607843137254901,0.6450980392156862,0.6294117647058823,0.6137254901960785,0.5980392156862746,0.5823529411764707,0.5666666666666669,0.5509803921568626,0.5352941176470587,0.5196078431372548,0.503921568627451,0.4882352941176471,0.4725490196078432,0.4568627450980394,0.4411764705882355,0.4254901960784316,0.4098039215686273,0.3941176470588235,0.3784313725490196,0.3627450980392157,0.3470588235294119,0.331372549019608,0.3156862745098041,0.2999999999999998,0.284313725490196,0.2686274509803921,0.2529411764705882,0.2372549019607844,0.2215686274509805,0.2058823529411766,0.1901960784313728,0.1745098039215689,0.1588235294117646,0.1431372549019607,0.1274509803921569,0.111764705882353,0.09607843137254912,0.08039215686274526,0.06470588235294139,0.04901960784313708,0.03333333333333321,0.01764705882352935,0.001960784313725483,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
float b[] = {0.5,0.5156862745098039,0.5313725490196078,0.5470588235294118,0.5627450980392157,0.5784313725490196,0.5941176470588235,0.6098039215686275,0.6254901960784314,0.6411764705882352,0.6568627450980392,0.6725490196078432,0.6882352941176471,0.7039215686274509,0.7196078431372549,0.7352941176470589,0.7509803921568627,0.7666666666666666,0.7823529411764706,0.7980392156862746,0.8137254901960784,0.8294117647058823,0.8450980392156863,0.8607843137254902,0.8764705882352941,0.892156862745098,0.907843137254902,0.9235294117647059,0.9392156862745098,0.9549019607843137,0.9705882352941176,0.9862745098039216,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.9941176470588236,0.9784313725490197,0.9627450980392158,0.9470588235294117,0.9313725490196079,0.915686274509804,0.8999999999999999,0.884313725490196,0.8686274509803922,0.8529411764705883,0.8372549019607844,0.8215686274509804,0.8058823529411765,0.7901960784313726,0.7745098039215685,0.7588235294117647,0.7431372549019608,0.7274509803921569,0.7117647058823531,0.696078431372549,0.6803921568627451,0.6647058823529413,0.6490196078431372,0.6333333333333333,0.6176470588235294,0.6019607843137256,0.5862745098039217,0.5705882352941176,0.5549019607843138,0.5392156862745099,0.5235294117647058,0.5078431372549019,0.4921568627450981,0.4764705882352942,0.4607843137254903,0.4450980392156865,0.4294117647058826,0.4137254901960783,0.3980392156862744,0.3823529411764706,0.3666666666666667,0.3509803921568628,0.335294117647059,0.3196078431372551,0.3039215686274508,0.2882352941176469,0.2725490196078431,0.2568627450980392,0.2411764705882353,0.2254901960784315,0.2098039215686276,0.1941176470588237,0.1784313725490199,0.1627450980392156,0.1470588235294117,0.1313725490196078,0.115686274509804,0.1000000000000001,0.08431372549019622,0.06862745098039236,0.05294117647058805,0.03725490196078418,0.02156862745098032,0.00588235294117645,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// now build lookup table
this->_lut = ColorMap::linear_colormap(X,
Mat(256,1, CV_32FC1, r).clone(), // red
Mat(256,1, CV_32FC1, g).clone(), // green
Mat(256,1, CV_32FC1, b).clone(), // blue
n);
}
};
// Equals the GNU Octave colormap "winter".
class Winter : public ColorMap {
public:
Winter() : ColorMap() {
init(256);
}
Winter(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
float g[] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
float b[] = {1.0, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5};
Mat X = linspace(0,1,11);
this->_lut = ColorMap::linear_colormap(X,
Mat(11,1, CV_32FC1, r).clone(), // red
Mat(11,1, CV_32FC1, g).clone(), // green
Mat(11,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "rainbow".
class Rainbow : public ColorMap {
public:
Rainbow() : ColorMap() {
init(256);
}
Rainbow(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9365079365079367, 0.8571428571428572, 0.7777777777777777, 0.6984126984126986, 0.6190476190476191, 0.53968253968254, 0.4603174603174605, 0.3809523809523814, 0.3015873015873018, 0.2222222222222223, 0.1428571428571432, 0.06349206349206415, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03174603174603208, 0.08465608465608465, 0.1375661375661377, 0.1904761904761907, 0.2433862433862437, 0.2962962962962963, 0.3492063492063493, 0.4021164021164023, 0.4550264550264553, 0.5079365079365079, 0.5608465608465609, 0.6137566137566139, 0.666666666666667};
float g[] = { 0, 0.03968253968253968, 0.07936507936507936, 0.119047619047619, 0.1587301587301587, 0.1984126984126984, 0.2380952380952381, 0.2777777777777778, 0.3174603174603174, 0.3571428571428571, 0.3968253968253968, 0.4365079365079365, 0.4761904761904762, 0.5158730158730158, 0.5555555555555556, 0.5952380952380952, 0.6349206349206349, 0.6746031746031745, 0.7142857142857142, 0.753968253968254, 0.7936507936507936, 0.8333333333333333, 0.873015873015873, 0.9126984126984127, 0.9523809523809523, 0.992063492063492, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9841269841269842, 0.9047619047619047, 0.8253968253968256, 0.7460317460317465, 0.666666666666667, 0.587301587301587, 0.5079365079365079, 0.4285714285714288, 0.3492063492063493, 0.2698412698412698, 0.1904761904761907, 0.1111111111111116, 0.03174603174603208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
float b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.01587301587301582, 0.09523809523809534, 0.1746031746031744, 0.2539682539682535, 0.333333333333333, 0.412698412698413, 0.4920634920634921, 0.5714285714285712, 0.6507936507936507, 0.7301587301587302, 0.8095238095238093, 0.8888888888888884, 0.9682539682539679, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "ocean".
class Ocean : public ColorMap {
public:
Ocean() : ColorMap() {
init(256);
}
Ocean(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.04761904761904762, 0.09523809523809523, 0.1428571428571428, 0.1904761904761905, 0.2380952380952381, 0.2857142857142857, 0.3333333333333333, 0.3809523809523809, 0.4285714285714285, 0.4761904761904762, 0.5238095238095238, 0.5714285714285714, 0.6190476190476191, 0.6666666666666666, 0.7142857142857143, 0.7619047619047619, 0.8095238095238095, 0.8571428571428571, 0.9047619047619048, 0.9523809523809523, 1};
float g[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.02380952380952381, 0.04761904761904762, 0.07142857142857142, 0.09523809523809523, 0.119047619047619, 0.1428571428571428, 0.1666666666666667, 0.1904761904761905, 0.2142857142857143, 0.2380952380952381, 0.2619047619047619, 0.2857142857142857, 0.3095238095238095, 0.3333333333333333, 0.3571428571428572, 0.3809523809523809, 0.4047619047619048, 0.4285714285714285, 0.4523809523809524, 0.4761904761904762, 0.5, 0.5238095238095238, 0.5476190476190477, 0.5714285714285714, 0.5952380952380952, 0.6190476190476191, 0.6428571428571429, 0.6666666666666666, 0.6904761904761905, 0.7142857142857143, 0.7380952380952381, 0.7619047619047619, 0.7857142857142857, 0.8095238095238095, 0.8333333333333334, 0.8571428571428571, 0.8809523809523809, 0.9047619047619048, 0.9285714285714286, 0.9523809523809523, 0.9761904761904762, 1};
float b[] = { 0, 0.01587301587301587, 0.03174603174603174, 0.04761904761904762, 0.06349206349206349, 0.07936507936507936, 0.09523809523809523, 0.1111111111111111, 0.126984126984127, 0.1428571428571428, 0.1587301587301587, 0.1746031746031746, 0.1904761904761905, 0.2063492063492063, 0.2222222222222222, 0.2380952380952381, 0.253968253968254, 0.2698412698412698, 0.2857142857142857, 0.3015873015873016, 0.3174603174603174, 0.3333333333333333, 0.3492063492063492, 0.3650793650793651, 0.3809523809523809, 0.3968253968253968, 0.4126984126984127, 0.4285714285714285, 0.4444444444444444, 0.4603174603174603, 0.4761904761904762, 0.492063492063492, 0.5079365079365079, 0.5238095238095238, 0.5396825396825397, 0.5555555555555556, 0.5714285714285714, 0.5873015873015873, 0.6031746031746031, 0.6190476190476191, 0.6349206349206349, 0.6507936507936508, 0.6666666666666666, 0.6825396825396826, 0.6984126984126984, 0.7142857142857143, 0.7301587301587301, 0.746031746031746, 0.7619047619047619, 0.7777777777777778, 0.7936507936507936, 0.8095238095238095, 0.8253968253968254, 0.8412698412698413, 0.8571428571428571, 0.873015873015873, 0.8888888888888888, 0.9047619047619048, 0.9206349206349206, 0.9365079365079365, 0.9523809523809523, 0.9682539682539683, 0.9841269841269841, 1};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "summer".
class Summer : public ColorMap {
public:
Summer() : ColorMap() {
init(256);
}
Summer(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 0, 0.01587301587301587, 0.03174603174603174, 0.04761904761904762, 0.06349206349206349, 0.07936507936507936, 0.09523809523809523, 0.1111111111111111, 0.126984126984127, 0.1428571428571428, 0.1587301587301587, 0.1746031746031746, 0.1904761904761905, 0.2063492063492063, 0.2222222222222222, 0.2380952380952381, 0.253968253968254, 0.2698412698412698, 0.2857142857142857, 0.3015873015873016, 0.3174603174603174, 0.3333333333333333, 0.3492063492063492, 0.3650793650793651, 0.3809523809523809, 0.3968253968253968, 0.4126984126984127, 0.4285714285714285, 0.4444444444444444, 0.4603174603174603, 0.4761904761904762, 0.492063492063492, 0.5079365079365079, 0.5238095238095238, 0.5396825396825397, 0.5555555555555556, 0.5714285714285714, 0.5873015873015873, 0.6031746031746031, 0.6190476190476191, 0.6349206349206349, 0.6507936507936508, 0.6666666666666666, 0.6825396825396826, 0.6984126984126984, 0.7142857142857143, 0.7301587301587301, 0.746031746031746, 0.7619047619047619, 0.7777777777777778, 0.7936507936507936, 0.8095238095238095, 0.8253968253968254, 0.8412698412698413, 0.8571428571428571, 0.873015873015873, 0.8888888888888888, 0.9047619047619048, 0.9206349206349206, 0.9365079365079365, 0.9523809523809523, 0.9682539682539683, 0.9841269841269841, 1};
float g[] = { 0.5, 0.5079365079365079, 0.5158730158730158, 0.5238095238095238, 0.5317460317460317, 0.5396825396825397, 0.5476190476190477, 0.5555555555555556, 0.5634920634920635, 0.5714285714285714, 0.5793650793650793, 0.5873015873015873, 0.5952380952380952, 0.6031746031746031, 0.6111111111111112, 0.6190476190476191, 0.626984126984127, 0.6349206349206349, 0.6428571428571428, 0.6507936507936508, 0.6587301587301587, 0.6666666666666666, 0.6746031746031746, 0.6825396825396826, 0.6904761904761905, 0.6984126984126984, 0.7063492063492063, 0.7142857142857143, 0.7222222222222222, 0.7301587301587301, 0.7380952380952381, 0.746031746031746, 0.753968253968254, 0.7619047619047619, 0.7698412698412698, 0.7777777777777778, 0.7857142857142857, 0.7936507936507937, 0.8015873015873016, 0.8095238095238095, 0.8174603174603174, 0.8253968253968254, 0.8333333333333333, 0.8412698412698413, 0.8492063492063492, 0.8571428571428572, 0.8650793650793651, 0.873015873015873, 0.8809523809523809, 0.8888888888888888, 0.8968253968253967, 0.9047619047619048, 0.9126984126984127, 0.9206349206349207, 0.9285714285714286, 0.9365079365079365, 0.9444444444444444, 0.9523809523809523, 0.9603174603174602, 0.9682539682539683, 0.9761904761904762, 0.9841269841269842, 0.9920634920634921, 1};
float b[] = { 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "spring".
class Spring : public ColorMap {
public:
Spring() : ColorMap() {
init(256);
}
Spring(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
float g[] = { 0, 0.01587301587301587, 0.03174603174603174, 0.04761904761904762, 0.06349206349206349, 0.07936507936507936, 0.09523809523809523, 0.1111111111111111, 0.126984126984127, 0.1428571428571428, 0.1587301587301587, 0.1746031746031746, 0.1904761904761905, 0.2063492063492063, 0.2222222222222222, 0.2380952380952381, 0.253968253968254, 0.2698412698412698, 0.2857142857142857, 0.3015873015873016, 0.3174603174603174, 0.3333333333333333, 0.3492063492063492, 0.3650793650793651, 0.3809523809523809, 0.3968253968253968, 0.4126984126984127, 0.4285714285714285, 0.4444444444444444, 0.4603174603174603, 0.4761904761904762, 0.492063492063492, 0.5079365079365079, 0.5238095238095238, 0.5396825396825397, 0.5555555555555556, 0.5714285714285714, 0.5873015873015873, 0.6031746031746031, 0.6190476190476191, 0.6349206349206349, 0.6507936507936508, 0.6666666666666666, 0.6825396825396826, 0.6984126984126984, 0.7142857142857143, 0.7301587301587301, 0.746031746031746, 0.7619047619047619, 0.7777777777777778, 0.7936507936507936, 0.8095238095238095, 0.8253968253968254, 0.8412698412698413, 0.8571428571428571, 0.873015873015873, 0.8888888888888888, 0.9047619047619048, 0.9206349206349206, 0.9365079365079365, 0.9523809523809523, 0.9682539682539683, 0.9841269841269841, 1};
float b[] = { 1, 0.9841269841269842, 0.9682539682539683, 0.9523809523809523, 0.9365079365079365, 0.9206349206349207, 0.9047619047619048, 0.8888888888888888, 0.873015873015873, 0.8571428571428572, 0.8412698412698413, 0.8253968253968254, 0.8095238095238095, 0.7936507936507937, 0.7777777777777778, 0.7619047619047619, 0.746031746031746, 0.7301587301587302, 0.7142857142857143, 0.6984126984126984, 0.6825396825396826, 0.6666666666666667, 0.6507936507936508, 0.6349206349206349, 0.6190476190476191, 0.6031746031746033, 0.5873015873015873, 0.5714285714285714, 0.5555555555555556, 0.5396825396825398, 0.5238095238095238, 0.5079365079365079, 0.4920634920634921, 0.4761904761904762, 0.4603174603174603, 0.4444444444444444, 0.4285714285714286, 0.4126984126984127, 0.3968253968253969, 0.3809523809523809, 0.3650793650793651, 0.3492063492063492, 0.3333333333333334, 0.3174603174603174, 0.3015873015873016, 0.2857142857142857, 0.2698412698412699, 0.253968253968254, 0.2380952380952381, 0.2222222222222222, 0.2063492063492064, 0.1904761904761905, 0.1746031746031746, 0.1587301587301587, 0.1428571428571429, 0.126984126984127, 0.1111111111111112, 0.09523809523809523, 0.07936507936507942, 0.06349206349206349, 0.04761904761904767, 0.03174603174603174, 0.01587301587301593, 0};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "cool".
class Cool : public ColorMap {
public:
Cool() : ColorMap() {
init(256);
}
Cool(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 0, 0.01587301587301587, 0.03174603174603174, 0.04761904761904762, 0.06349206349206349, 0.07936507936507936, 0.09523809523809523, 0.1111111111111111, 0.126984126984127, 0.1428571428571428, 0.1587301587301587, 0.1746031746031746, 0.1904761904761905, 0.2063492063492063, 0.2222222222222222, 0.2380952380952381, 0.253968253968254, 0.2698412698412698, 0.2857142857142857, 0.3015873015873016, 0.3174603174603174, 0.3333333333333333, 0.3492063492063492, 0.3650793650793651, 0.3809523809523809, 0.3968253968253968, 0.4126984126984127, 0.4285714285714285, 0.4444444444444444, 0.4603174603174603, 0.4761904761904762, 0.492063492063492, 0.5079365079365079, 0.5238095238095238, 0.5396825396825397, 0.5555555555555556, 0.5714285714285714, 0.5873015873015873, 0.6031746031746031, 0.6190476190476191, 0.6349206349206349, 0.6507936507936508, 0.6666666666666666, 0.6825396825396826, 0.6984126984126984, 0.7142857142857143, 0.7301587301587301, 0.746031746031746, 0.7619047619047619, 0.7777777777777778, 0.7936507936507936, 0.8095238095238095, 0.8253968253968254, 0.8412698412698413, 0.8571428571428571, 0.873015873015873, 0.8888888888888888, 0.9047619047619048, 0.9206349206349206, 0.9365079365079365, 0.9523809523809523, 0.9682539682539683, 0.9841269841269841, 1};
float g[] = { 1, 0.9841269841269842, 0.9682539682539683, 0.9523809523809523, 0.9365079365079365, 0.9206349206349207, 0.9047619047619048, 0.8888888888888888, 0.873015873015873, 0.8571428571428572, 0.8412698412698413, 0.8253968253968254, 0.8095238095238095, 0.7936507936507937, 0.7777777777777778, 0.7619047619047619, 0.746031746031746, 0.7301587301587302, 0.7142857142857143, 0.6984126984126984, 0.6825396825396826, 0.6666666666666667, 0.6507936507936508, 0.6349206349206349, 0.6190476190476191, 0.6031746031746033, 0.5873015873015873, 0.5714285714285714, 0.5555555555555556, 0.5396825396825398, 0.5238095238095238, 0.5079365079365079, 0.4920634920634921, 0.4761904761904762, 0.4603174603174603, 0.4444444444444444, 0.4285714285714286, 0.4126984126984127, 0.3968253968253969, 0.3809523809523809, 0.3650793650793651, 0.3492063492063492, 0.3333333333333334, 0.3174603174603174, 0.3015873015873016, 0.2857142857142857, 0.2698412698412699, 0.253968253968254, 0.2380952380952381, 0.2222222222222222, 0.2063492063492064, 0.1904761904761905, 0.1746031746031746, 0.1587301587301587, 0.1428571428571429, 0.126984126984127, 0.1111111111111112, 0.09523809523809523, 0.07936507936507942, 0.06349206349206349, 0.04761904761904767, 0.03174603174603174, 0.01587301587301593, 0};
float b[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "hsv".
class HSV : public ColorMap {
public:
HSV() : ColorMap() {
init(256);
}
HSV(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9523809523809526, 0.8571428571428568, 0.7619047619047614, 0.6666666666666665, 0.5714285714285716, 0.4761904761904763, 0.3809523809523805, 0.2857142857142856, 0.1904761904761907, 0.0952380952380949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09523809523809557, 0.1904761904761905, 0.2857142857142854, 0.3809523809523809, 0.4761904761904765, 0.5714285714285714, 0.6666666666666663, 0.7619047619047619, 0.8571428571428574, 0.9523809523809523, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
float g[] = { 0, 0.09523809523809523, 0.1904761904761905, 0.2857142857142857, 0.3809523809523809, 0.4761904761904762, 0.5714285714285714, 0.6666666666666666, 0.7619047619047619, 0.8571428571428571, 0.9523809523809523, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9523809523809526, 0.8571428571428577, 0.7619047619047619, 0.6666666666666665, 0.5714285714285716, 0.4761904761904767, 0.3809523809523814, 0.2857142857142856, 0.1904761904761907, 0.09523809523809579, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
float b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.09523809523809523, 0.1904761904761905, 0.2857142857142857, 0.3809523809523809, 0.4761904761904762, 0.5714285714285714, 0.6666666666666666, 0.7619047619047619, 0.8571428571428571, 0.9523809523809523, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9523809523809526, 0.8571428571428577, 0.7619047619047614, 0.6666666666666665, 0.5714285714285716, 0.4761904761904767, 0.3809523809523805, 0.2857142857142856, 0.1904761904761907, 0.09523809523809579, 0};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "pink".
class Pink : public ColorMap {
public:
Pink() : ColorMap() {
init(256);
}
Pink(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 0, 0.1571348402636772, 0.2222222222222222, 0.2721655269759087, 0.3142696805273544, 0.3513641844631533, 0.3849001794597505, 0.415739709641549, 0.4444444444444444, 0.4714045207910317, 0.4969039949999532, 0.5211573066470477, 0.5443310539518174, 0.5665577237325317, 0.5879447357921312, 0.6085806194501846, 0.6285393610547089, 0.6478835438717, 0.6666666666666666, 0.6849348892187751, 0.7027283689263065, 0.7200822998230956, 0.7370277311900888, 0.753592220347252, 0.7663560447348133, 0.7732293307186413, 0.7800420555749596, 0.7867957924694432, 0.7934920476158722, 0.8001322641986387, 0.8067178260046388, 0.8132500607904444, 0.8197302434079591, 0.8261595987094034, 0.8325393042503717, 0.8388704928078611, 0.8451542547285166, 0.8513916401208816, 0.8575836609041332, 0.8637312927246217, 0.8698354767504924, 0.8758971213537393, 0.8819171036881968, 0.8878962711712378, 0.8938354428762595, 0.8997354108424372, 0.9055969413076769, 0.9114207758701963, 0.9172076325837248, 0.9229582069908971, 0.9286731730990523, 0.9343531843023135, 0.9399988742535192, 0.9456108576893002, 0.9511897312113418, 0.9567360740266436, 0.9622504486493763, 0.9677334015667416, 0.9731854638710686, 0.9786071518602129, 0.9839989676081821, 0.9893613995077727, 0.9946949227868761, 1};
float g[] = { 0, 0.1028688999747279, 0.1454785934906616, 0.1781741612749496, 0.2057377999494559, 0.2300218531141181, 0.2519763153394848, 0.2721655269759087, 0.2909571869813232, 0.3086066999241838, 0.3253000243161777, 0.3411775438127727, 0.3563483225498992, 0.3708990935094579, 0.3849001794597505, 0.3984095364447979, 0.4114755998989117, 0.4241393401869012, 0.4364357804719847, 0.4483951394230328, 0.4600437062282361, 0.4714045207910317, 0.4824979096371639, 0.4933419132673033, 0.5091750772173156, 0.5328701692569688, 0.5555555555555556, 0.5773502691896257, 0.5983516452371671, 0.6186404847588913, 0.6382847385042254, 0.6573421981221795, 0.6758625033664688, 0.6938886664887108, 0.7114582486036499, 0.7286042804780002, 0.7453559924999299, 0.7617394000445604, 0.7777777777777778, 0.7934920476158723, 0.8089010988089465, 0.8240220541217402, 0.8388704928078611, 0.8534606386520677, 0.8678055195451838, 0.8819171036881968, 0.8958064164776166, 0.9094836413191612, 0.9172076325837248, 0.9229582069908971, 0.9286731730990523, 0.9343531843023135, 0.9399988742535192, 0.9456108576893002, 0.9511897312113418, 0.9567360740266436, 0.9622504486493763, 0.9677334015667416, 0.9731854638710686, 0.9786071518602129, 0.9839989676081821, 0.9893613995077727, 0.9946949227868761, 1};
float b[] = { 0, 0.1028688999747279, 0.1454785934906616, 0.1781741612749496, 0.2057377999494559, 0.2300218531141181, 0.2519763153394848, 0.2721655269759087, 0.2909571869813232, 0.3086066999241838, 0.3253000243161777, 0.3411775438127727, 0.3563483225498992, 0.3708990935094579, 0.3849001794597505, 0.3984095364447979, 0.4114755998989117, 0.4241393401869012, 0.4364357804719847, 0.4483951394230328, 0.4600437062282361, 0.4714045207910317, 0.4824979096371639, 0.4933419132673033, 0.5039526306789697, 0.5143444998736397, 0.5245305283129621, 0.5345224838248488, 0.5443310539518174, 0.5539659798925444, 0.563436169819011, 0.5727497953228163, 0.5819143739626463, 0.5909368402852788, 0.5998236072282915, 0.6085806194501846, 0.6172133998483676, 0.6257270902992705, 0.6341264874742278, 0.642416074439621, 0.6506000486323554, 0.6586823467062358, 0.6666666666666666, 0.6745564876468501, 0.6823550876255453, 0.6900655593423541, 0.6976908246297114, 0.7052336473499384, 0.7237468644557459, 0.7453559924999298, 0.7663560447348133, 0.7867957924694432, 0.8067178260046388, 0.8261595987094034, 0.8451542547285166, 0.8637312927246217, 0.8819171036881968, 0.8997354108424372, 0.9172076325837248, 0.9343531843023135, 0.9511897312113418, 0.9677334015667416, 0.9839989676081821, 1};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
// Equals the GNU Octave colormap "hot".
class Hot : public ColorMap {
public:
Hot() : ColorMap() {
init(256);
}
Hot(int n) : ColorMap() {
init(n);
}
void init(int n) {
float r[] = { 0, 0.03968253968253968, 0.07936507936507936, 0.119047619047619, 0.1587301587301587, 0.1984126984126984, 0.2380952380952381, 0.2777777777777778, 0.3174603174603174, 0.3571428571428571, 0.3968253968253968, 0.4365079365079365, 0.4761904761904762, 0.5158730158730158, 0.5555555555555556, 0.5952380952380952, 0.6349206349206349, 0.6746031746031745, 0.7142857142857142, 0.753968253968254, 0.7936507936507936, 0.8333333333333333, 0.873015873015873, 0.9126984126984127, 0.9523809523809523, 0.992063492063492, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
float g[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03174603174603163, 0.0714285714285714, 0.1111111111111112, 0.1507936507936507, 0.1904761904761905, 0.23015873015873, 0.2698412698412698, 0.3095238095238093, 0.3492063492063491, 0.3888888888888888, 0.4285714285714284, 0.4682539682539679, 0.5079365079365079, 0.5476190476190477, 0.5873015873015872, 0.6269841269841268, 0.6666666666666665, 0.7063492063492065, 0.746031746031746, 0.7857142857142856, 0.8253968253968254, 0.8650793650793651, 0.9047619047619047, 0.9444444444444442, 0.984126984126984, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
float b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.04761904761904745, 0.1269841269841265, 0.2063492063492056, 0.2857142857142856, 0.3650793650793656, 0.4444444444444446, 0.5238095238095237, 0.6031746031746028, 0.6825396825396828, 0.7619047619047619, 0.8412698412698409, 0.92063492063492, 1};
Mat X = linspace(0,1,64);
this->_lut = ColorMap::linear_colormap(X,
Mat(64,1, CV_32FC1, r).clone(), // red
Mat(64,1, CV_32FC1, g).clone(), // green
Mat(64,1, CV_32FC1, b).clone(), // blue
n); // number of sample points
}
};
void ColorMap::operator()(InputArray _src, OutputArray _dst) const
{
if(_lut.total() != 256)
CV_Error(Error::StsAssert, "cv::LUT only supports tables of size 256.");
Mat src = _src.getMat();
// Return original matrix if wrong type is given (is fail loud better here?)
if(src.type() != CV_8UC1 && src.type() != CV_8UC3)
{
src.copyTo(_dst);
return;
}
// Turn into a BGR matrix into its grayscale representation.
if(src.type() == CV_8UC3)
cvtColor(src.clone(), src, COLOR_BGR2GRAY);
cvtColor(src.clone(), src, COLOR_GRAY2BGR);
// Apply the ColorMap.
LUT(src, _lut, _dst);
}
Mat ColorMap::linear_colormap(InputArray X,
InputArray r, InputArray g, InputArray b,
InputArray xi) {
Mat lut, lut8;
Mat planes[] = {
interp1(X, b, xi),
interp1(X, g, xi),
interp1(X, r, xi)};
merge(planes, 3, lut);
lut.convertTo(lut8, CV_8U, 255.);
return lut8;
}
}
void applyColorMap(InputArray src, OutputArray dst, int colormap)
{
colormap::ColorMap* cm =
colormap == COLORMAP_AUTUMN ? (colormap::ColorMap*)(new colormap::Autumn) :
colormap == COLORMAP_BONE ? (colormap::ColorMap*)(new colormap::Bone) :
colormap == COLORMAP_COOL ? (colormap::ColorMap*)(new colormap::Cool) :
colormap == COLORMAP_HOT ? (colormap::ColorMap*)(new colormap::Hot) :
colormap == COLORMAP_HSV ? (colormap::ColorMap*)(new colormap::HSV) :
colormap == COLORMAP_JET ? (colormap::ColorMap*)(new colormap::Jet) :
colormap == COLORMAP_OCEAN ? (colormap::ColorMap*)(new colormap::Ocean) :
colormap == COLORMAP_PINK ? (colormap::ColorMap*)(new colormap::Pink) :
colormap == COLORMAP_RAINBOW ? (colormap::ColorMap*)(new colormap::Rainbow) :
colormap == COLORMAP_SPRING ? (colormap::ColorMap*)(new colormap::Spring) :
colormap == COLORMAP_SUMMER ? (colormap::ColorMap*)(new colormap::Summer) :
colormap == COLORMAP_WINTER ? (colormap::ColorMap*)(new colormap::Winter) : 0;
if( !cm )
CV_Error( Error::StsBadArg, "Unknown colormap id; use one of COLORMAP_*");
(*cm)(src, dst);
delete cm;
}
}

@ -2074,7 +2074,8 @@ static bool ocl_resize( InputArray _src, OutputArray _dst, Size dsize,
// datatypes because the observed error is low.
bool useSampler = (interpolation == INTER_LINEAR && ocl::Device::getDefault().imageSupport() &&
ocl::Image2D::canCreateAlias(src) && depth <= 4 &&
ocl::Image2D::isFormatSupported(depth, cn, true));
ocl::Image2D::isFormatSupported(depth, cn, true) &&
src.offset==0);
if (useSampler)
{
int wdepth = std::max(depth, CV_32S);
@ -2380,7 +2381,7 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
inv_scale_y = (double)dsize.height/ssize.height;
}
CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat() && _src.cols() > 10 && _src.rows() > 10,
ocl_resize(_src, _dst, dsize, inv_scale_x, inv_scale_y, interpolation))
Mat src = _src.getMat();

@ -1268,10 +1268,11 @@ static bool IPPMorphOp(int op, InputArray _src, OutputArray _dst,
int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
if( !( depth == CV_8U || depth == CV_32F ) || !(cn == 1 || cn == 3 || cn == 4) ||
!( borderType == cv::BORDER_REPLICATE || (borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue()) )
|| !( op == MORPH_DILATE || op == MORPH_ERODE) || _src.isSubmatrix() )
!( borderType == cv::BORDER_REPLICATE || (borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue() &&
kernel.size() == Size(3,3)) ) || !( op == MORPH_DILATE || op == MORPH_ERODE) || _src.isSubmatrix() )
return false;
// In case BORDER_CONSTANT, IPPMorphReplicate works correct with kernels of size 3*3 only
if( borderType == cv::BORDER_CONSTANT && kernel.data )
{
int x, y;
@ -1510,22 +1511,6 @@ static bool ocl_morphOp(InputArray _src, OutputArray _dst, InputArray _kernel,
bool haveExtraMat = !_extraMat.empty();
CV_Assert(actual_op <= 3 || haveExtraMat);
// try to use OpenCL kernel adopted for small morph kernel
if (dev.isIntel() && !(dev.type() & ocl::Device::TYPE_CPU) &&
((ksize.width < 5 && ksize.height < 5 && esz <= 4) ||
(ksize.width == 5 && ksize.height == 5 && cn == 1)) &&
(iterations == 1))
{
if (ocl_morphSmall(_src, _dst, _kernel, anchor, borderType, op, actual_op, _extraMat))
return true;
}
if (iterations == 0 || kernel.rows*kernel.cols == 1)
{
_src.copyTo(_dst);
return true;
}
if (!kernel.data)
{
kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2));
@ -1542,6 +1527,22 @@ static bool ocl_morphOp(InputArray _src, OutputArray _dst, InputArray _kernel,
iterations = 1;
}
// try to use OpenCL kernel adopted for small morph kernel
if (dev.isIntel() && !(dev.type() & ocl::Device::TYPE_CPU) &&
((ksize.width < 5 && ksize.height < 5 && esz <= 4) ||
(ksize.width == 5 && ksize.height == 5 && cn == 1)) &&
(iterations == 1))
{
if (ocl_morphSmall(_src, _dst, kernel, anchor, borderType, op, actual_op, _extraMat))
return true;
}
if (iterations == 0 || kernel.rows*kernel.cols == 1)
{
_src.copyTo(_dst);
return true;
}
#ifdef ANDROID
size_t localThreads[2] = { 16, 8 };
#else

@ -47,7 +47,7 @@
#define noconvert
__kernel void calculate_histogram(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols,
__kernel void calculate_histogram(__global const uchar * src_ptr, int src_step, int src_offset, int src_rows, int src_cols,
__global uchar * histptr, int total)
{
int lid = get_local_id(0);
@ -61,6 +61,7 @@ __kernel void calculate_histogram(__global const uchar * src, int src_step, int
localhist[i] = 0;
barrier(CLK_LOCAL_MEM_FENCE);
__global const uchar * src = src_ptr + src_offset;
int src_index;
for (int grain = HISTS_COUNT * WGS * kercn; id < total; id += grain)
@ -68,7 +69,7 @@ __kernel void calculate_histogram(__global const uchar * src, int src_step, int
#ifdef HAVE_SRC_CONT
src_index = id;
#else
src_index = mad24(id / src_cols, src_step, src_offset + id % src_cols);
src_index = mad24(id / src_cols, src_step, id % src_cols);
#endif
#if kercn == 1

@ -53,16 +53,16 @@
#if defined BORDER_REPLICATE
// aaaaaa|abcdefgh|hhhhhhh
#define EXTRAPOLATE(x, maxV) clamp(x, 0, maxV-1)
#define EXTRAPOLATE(x, maxV) clamp((x), 0, (maxV)-1)
#elif defined BORDER_WRAP
// cdefgh|abcdefgh|abcdefg
#define EXTRAPOLATE(x, maxV) ( (x) + (maxV) ) % (maxV)
#elif defined BORDER_REFLECT
// fedcba|abcdefgh|hgfedcb
#define EXTRAPOLATE(x, maxV) min(((maxV)-1)*2-(x)+1, max((x),-(x)-1) )
#define EXTRAPOLATE(x, maxV) clamp(min(((maxV)-1)*2-(x)+1, max((x),-(x)-1) ), 0, (maxV)-1)
#elif defined BORDER_REFLECT_101 || defined BORDER_REFLECT101
// gfedcb|abcdefgh|gfedcba
#define EXTRAPOLATE(x, maxV) min(((maxV)-1)*2-(x), max((x),-(x)) )
#define EXTRAPOLATE(x, maxV) clamp(min(((maxV)-1)*2-(x), max((x),-(x)) ), 0, (maxV)-1)
#else
#error No extrapolation method
#endif

@ -413,9 +413,9 @@ __kernel void remap_2_32FC1(__global const uchar * srcptr, int src_step, int src
__global T * dst = (__global T *)(dstptr + dst_index);
#if defined BORDER_CONSTANT
float xf = map1[0], yf = map2[0];
int sx = convert_int_sat_rtn(xf), sy = convert_int_sat_rtn(yf);
int sx = convert_int_sat_rtz(mad(xf, INTER_TAB_SIZE, 0.5f)) >> INTER_BITS;
int sy = convert_int_sat_rtz(mad(yf, INTER_TAB_SIZE, 0.5f)) >> INTER_BITS;
__constant float * coeffs_x = coeffs + ((convert_int_rte(xf * INTER_TAB_SIZE) & (INTER_TAB_SIZE - 1)) << 1);
__constant float * coeffs_y = coeffs + ((convert_int_rte(yf * INTER_TAB_SIZE) & (INTER_TAB_SIZE - 1)) << 1);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save