--- /dev/null
+/*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, Willow Garage Inc., all rights reserved.
+// Copyright (C) 2013, OpenCV Foundation, 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*/
+
+#ifndef __OPENCV_CALIB3D_HPP__
+#define __OPENCV_CALIB3D_HPP__
+
+#include "opencv2/core.hpp"
+#include "opencv2/features2d.hpp"
++#include "opencv2/core/affine.hpp"
+
+namespace cv
+{
+
+//! type of the robust estimation algorithm
+enum { LMEDS = 4, //!< least-median algorithm
+ RANSAC = 8 //!< RANSAC algorithm
+ };
+
+enum { ITERATIVE = 0,
+ EPNP = 1, // F.Moreno-Noguer, V.Lepetit and P.Fua "EPnP: Efficient Perspective-n-Point Camera Pose Estimation"
+ P3P = 2 // X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang; "Complete Solution Classification for the Perspective-Three-Point Problem"
+ };
+
+enum { CALIB_CB_ADAPTIVE_THRESH = 1,
+ CALIB_CB_NORMALIZE_IMAGE = 2,
+ CALIB_CB_FILTER_QUADS = 4,
+ CALIB_CB_FAST_CHECK = 8
+ };
+
+enum { CALIB_CB_SYMMETRIC_GRID = 1,
+ CALIB_CB_ASYMMETRIC_GRID = 2,
+ CALIB_CB_CLUSTERING = 4
+ };
+
+enum { CALIB_USE_INTRINSIC_GUESS = 0x00001,
+ CALIB_FIX_ASPECT_RATIO = 0x00002,
+ CALIB_FIX_PRINCIPAL_POINT = 0x00004,
+ CALIB_ZERO_TANGENT_DIST = 0x00008,
+ CALIB_FIX_FOCAL_LENGTH = 0x00010,
+ CALIB_FIX_K1 = 0x00020,
+ CALIB_FIX_K2 = 0x00040,
+ CALIB_FIX_K3 = 0x00080,
+ CALIB_FIX_K4 = 0x00800,
+ CALIB_FIX_K5 = 0x01000,
+ CALIB_FIX_K6 = 0x02000,
+ CALIB_RATIONAL_MODEL = 0x04000,
+ CALIB_THIN_PRISM_MODEL = 0x08000,
+ CALIB_FIX_S1_S2_S3_S4 = 0x10000,
+ // only for stereo
+ CALIB_FIX_INTRINSIC = 0x00100,
+ CALIB_SAME_FOCAL_LENGTH = 0x00200,
+ // for stereo rectification
+ CALIB_ZERO_DISPARITY = 0x00400
+ };
+
+//! the algorithm for finding fundamental matrix
+enum { FM_7POINT = 1, //!< 7-point algorithm
+ FM_8POINT = 2, //!< 8-point algorithm
+ FM_LMEDS = 4, //!< least-median algorithm
+ FM_RANSAC = 8 //!< RANSAC algorithm
+ };
+
+
+
+//! converts rotation vector to rotation matrix or vice versa using Rodrigues transformation
+CV_EXPORTS_W void Rodrigues( InputArray src, OutputArray dst, OutputArray jacobian = noArray() );
+
+//! computes the best-fit perspective transformation mapping srcPoints to dstPoints.
+CV_EXPORTS_W Mat findHomography( InputArray srcPoints, InputArray dstPoints,
+ int method = 0, double ransacReprojThreshold = 3,
+ OutputArray mask=noArray());
+
+//! variant of findHomography for backward compatibility
+CV_EXPORTS Mat findHomography( InputArray srcPoints, InputArray dstPoints,
+ OutputArray mask, int method = 0, double ransacReprojThreshold = 3 );
+
+//! Computes RQ decomposition of 3x3 matrix
+CV_EXPORTS_W Vec3d RQDecomp3x3( InputArray src, OutputArray mtxR, OutputArray mtxQ,
+ OutputArray Qx = noArray(),
+ OutputArray Qy = noArray(),
+ OutputArray Qz = noArray());
+
+//! Decomposes the projection matrix into camera matrix and the rotation martix and the translation vector
+CV_EXPORTS_W void decomposeProjectionMatrix( InputArray projMatrix, OutputArray cameraMatrix,
+ OutputArray rotMatrix, OutputArray transVect,
+ OutputArray rotMatrixX = noArray(),
+ OutputArray rotMatrixY = noArray(),
+ OutputArray rotMatrixZ = noArray(),
+ OutputArray eulerAngles =noArray() );
+
+//! computes derivatives of the matrix product w.r.t each of the multiplied matrix coefficients
+CV_EXPORTS_W void matMulDeriv( InputArray A, InputArray B, OutputArray dABdA, OutputArray dABdB );
+
+//! composes 2 [R|t] transformations together. Also computes the derivatives of the result w.r.t the arguments
+CV_EXPORTS_W void composeRT( InputArray rvec1, InputArray tvec1,
+ InputArray rvec2, InputArray tvec2,
+ OutputArray rvec3, OutputArray tvec3,
+ OutputArray dr3dr1 = noArray(), OutputArray dr3dt1 = noArray(),
+ OutputArray dr3dr2 = noArray(), OutputArray dr3dt2 = noArray(),
+ OutputArray dt3dr1 = noArray(), OutputArray dt3dt1 = noArray(),
+ OutputArray dt3dr2 = noArray(), OutputArray dt3dt2 = noArray() );
+
+//! projects points from the model coordinate space to the image coordinates. Also computes derivatives of the image coordinates w.r.t the intrinsic and extrinsic camera parameters
+CV_EXPORTS_W void projectPoints( InputArray objectPoints,
+ InputArray rvec, InputArray tvec,
+ InputArray cameraMatrix, InputArray distCoeffs,
+ OutputArray imagePoints,
+ OutputArray jacobian = noArray(),
+ double aspectRatio = 0 );
+
+//! computes the camera pose from a few 3D points and the corresponding projections. The outliers are not handled.
+CV_EXPORTS_W bool solvePnP( InputArray objectPoints, InputArray imagePoints,
+ InputArray cameraMatrix, InputArray distCoeffs,
+ OutputArray rvec, OutputArray tvec,
+ bool useExtrinsicGuess = false, int flags = ITERATIVE );
+
+//! computes the camera pose from a few 3D points and the corresponding projections. The outliers are possible.
+CV_EXPORTS_W void solvePnPRansac( InputArray objectPoints, InputArray imagePoints,
+ InputArray cameraMatrix, InputArray distCoeffs,
+ OutputArray rvec, OutputArray tvec,
+ bool useExtrinsicGuess = false, int iterationsCount = 100,
+ float reprojectionError = 8.0, int minInliersCount = 100,
+ OutputArray inliers = noArray(), int flags = ITERATIVE );
+
+//! initializes camera matrix from a few 3D points and the corresponding projections.
+CV_EXPORTS_W Mat initCameraMatrix2D( InputArrayOfArrays objectPoints,
+ InputArrayOfArrays imagePoints,
+ Size imageSize, double aspectRatio = 1.0 );
+
+//! finds checkerboard pattern of the specified size in the image
+CV_EXPORTS_W bool findChessboardCorners( InputArray image, Size patternSize, OutputArray corners,
+ int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE );
+
+//! finds subpixel-accurate positions of the chessboard corners
+CV_EXPORTS bool find4QuadCornerSubpix( InputArray img, InputOutputArray corners, Size region_size );
+
+//! draws the checkerboard pattern (found or partly found) in the image
+CV_EXPORTS_W void drawChessboardCorners( InputOutputArray image, Size patternSize,
+ InputArray corners, bool patternWasFound );
+
+//! finds circles' grid pattern of the specified size in the image
+CV_EXPORTS_W bool findCirclesGrid( InputArray image, Size patternSize,
+ OutputArray centers, int flags = CALIB_CB_SYMMETRIC_GRID,
+ const Ptr<FeatureDetector> &blobDetector = makePtr<SimpleBlobDetector>());
+
+//! finds intrinsic and extrinsic camera parameters from several fews of a known calibration pattern.
+CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
+ InputArrayOfArrays imagePoints, Size imageSize,
+ InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
+ OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
+ int flags = 0, TermCriteria criteria = TermCriteria(
+ TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
+
+//! computes several useful camera characteristics from the camera matrix, camera frame resolution and the physical sensor size.
+CV_EXPORTS_W void calibrationMatrixValues( InputArray cameraMatrix, Size imageSize,
+ double apertureWidth, double apertureHeight,
+ CV_OUT double& fovx, CV_OUT double& fovy,
+ CV_OUT double& focalLength, CV_OUT Point2d& principalPoint,
+ CV_OUT double& aspectRatio );
+
+//! finds intrinsic and extrinsic parameters of a stereo camera
+CV_EXPORTS_W double stereoCalibrate( InputArrayOfArrays objectPoints,
+ InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2,
+ InputOutputArray cameraMatrix1, InputOutputArray distCoeffs1,
+ InputOutputArray cameraMatrix2, InputOutputArray distCoeffs2,
+ Size imageSize, OutputArray R,OutputArray T, OutputArray E, OutputArray F,
+ int flags = CALIB_FIX_INTRINSIC,
+ TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 1e-6) );
+
+
+//! computes the rectification transformation for a stereo camera from its intrinsic and extrinsic parameters
+CV_EXPORTS_W void stereoRectify( InputArray cameraMatrix1, InputArray distCoeffs1,
+ InputArray cameraMatrix2, InputArray distCoeffs2,
+ Size imageSize, InputArray R, InputArray T,
+ OutputArray R1, OutputArray R2,
+ OutputArray P1, OutputArray P2,
+ OutputArray Q, int flags = CALIB_ZERO_DISPARITY,
+ double alpha = -1, Size newImageSize = Size(),
+ CV_OUT Rect* validPixROI1 = 0, CV_OUT Rect* validPixROI2 = 0 );
+
+//! computes the rectification transformation for an uncalibrated stereo camera (zero distortion is assumed)
+CV_EXPORTS_W bool stereoRectifyUncalibrated( InputArray points1, InputArray points2,
+ InputArray F, Size imgSize,
+ OutputArray H1, OutputArray H2,
+ double threshold = 5 );
+
+//! computes the rectification transformations for 3-head camera, where all the heads are on the same line.
+CV_EXPORTS_W float rectify3Collinear( InputArray cameraMatrix1, InputArray distCoeffs1,
+ InputArray cameraMatrix2, InputArray distCoeffs2,
+ InputArray cameraMatrix3, InputArray distCoeffs3,
+ InputArrayOfArrays imgpt1, InputArrayOfArrays imgpt3,
+ Size imageSize, InputArray R12, InputArray T12,
+ InputArray R13, InputArray T13,
+ OutputArray R1, OutputArray R2, OutputArray R3,
+ OutputArray P1, OutputArray P2, OutputArray P3,
+ OutputArray Q, double alpha, Size newImgSize,
+ CV_OUT Rect* roi1, CV_OUT Rect* roi2, int flags );
+
+//! returns the optimal new camera matrix
+CV_EXPORTS_W Mat getOptimalNewCameraMatrix( InputArray cameraMatrix, InputArray distCoeffs,
+ Size imageSize, double alpha, Size newImgSize = Size(),
+ CV_OUT Rect* validPixROI = 0,
+ bool centerPrincipalPoint = false);
+
+//! converts point coordinates from normal pixel coordinates to homogeneous coordinates ((x,y)->(x,y,1))
+CV_EXPORTS_W void convertPointsToHomogeneous( InputArray src, OutputArray dst );
+
+//! converts point coordinates from homogeneous to normal pixel coordinates ((x,y,z)->(x/z, y/z))
+CV_EXPORTS_W void convertPointsFromHomogeneous( InputArray src, OutputArray dst );
+
+//! for backward compatibility
+CV_EXPORTS void convertPointsHomogeneous( InputArray src, OutputArray dst );
+
+//! finds fundamental matrix from a set of corresponding 2D points
+CV_EXPORTS_W Mat findFundamentalMat( InputArray points1, InputArray points2,
+ int method = FM_RANSAC,
+ double param1 = 3., double param2 = 0.99,
+ OutputArray mask = noArray() );
+
+//! variant of findFundamentalMat for backward compatibility
+CV_EXPORTS Mat findFundamentalMat( InputArray points1, InputArray points2,
+ OutputArray mask, int method = FM_RANSAC,
+ double param1 = 3., double param2 = 0.99 );
+
+//! finds essential matrix from a set of corresponding 2D points using five-point algorithm
+CV_EXPORTS_W Mat findEssentialMat( InputArray points1, InputArray points2,
+ double focal = 1.0, Point2d pp = Point2d(0, 0),
+ int method = RANSAC, double prob = 0.999,
+ double threshold = 1.0, OutputArray mask = noArray() );
+
+//! decompose essential matrix to possible rotation matrix and one translation vector
+CV_EXPORTS_W void decomposeEssentialMat( InputArray E, OutputArray R1, OutputArray R2, OutputArray t );
+
+//! recover relative camera pose from a set of corresponding 2D points
+CV_EXPORTS_W int recoverPose( InputArray E, InputArray points1, InputArray points2,
+ OutputArray R, OutputArray t,
+ double focal = 1.0, Point2d pp = Point2d(0, 0),
+ InputOutputArray mask = noArray() );
+
+
+//! finds coordinates of epipolar lines corresponding the specified points
+CV_EXPORTS_W void computeCorrespondEpilines( InputArray points, int whichImage,
+ InputArray F, OutputArray lines );
+
+CV_EXPORTS_W void triangulatePoints( InputArray projMatr1, InputArray projMatr2,
+ InputArray projPoints1, InputArray projPoints2,
+ OutputArray points4D );
+
+CV_EXPORTS_W void correctMatches( InputArray F, InputArray points1, InputArray points2,
+ OutputArray newPoints1, OutputArray newPoints2 );
+
+//! filters off speckles (small regions of incorrectly computed disparity)
+CV_EXPORTS_W void filterSpeckles( InputOutputArray img, double newVal,
+ int maxSpeckleSize, double maxDiff,
+ InputOutputArray buf = noArray() );
+
+//! computes valid disparity ROI from the valid ROIs of the rectified images (that are returned by cv::stereoRectify())
+CV_EXPORTS_W Rect getValidDisparityROI( Rect roi1, Rect roi2,
+ int minDisparity, int numberOfDisparities,
+ int SADWindowSize );
+
+//! validates disparity using the left-right check. The matrix "cost" should be computed by the stereo correspondence algorithm
+CV_EXPORTS_W void validateDisparity( InputOutputArray disparity, InputArray cost,
+ int minDisparity, int numberOfDisparities,
+ int disp12MaxDisp = 1 );
+
+//! reprojects disparity image to 3D: (x,y,d)->(X,Y,Z) using the matrix Q returned by cv::stereoRectify
+CV_EXPORTS_W void reprojectImageTo3D( InputArray disparity,
+ OutputArray _3dImage, InputArray Q,
+ bool handleMissingValues = false,
+ int ddepth = -1 );
+
+CV_EXPORTS_W int estimateAffine3D(InputArray src, InputArray dst,
+ OutputArray out, OutputArray inliers,
+ double ransacThreshold = 3, double confidence = 0.99);
+
+
+
+class CV_EXPORTS_W StereoMatcher : public Algorithm
+{
+public:
+ enum { DISP_SHIFT = 4,
+ DISP_SCALE = (1 << DISP_SHIFT)
+ };
+
+ CV_WRAP virtual void compute( InputArray left, InputArray right,
+ OutputArray disparity ) = 0;
+
+ CV_WRAP virtual int getMinDisparity() const = 0;
+ CV_WRAP virtual void setMinDisparity(int minDisparity) = 0;
+
+ CV_WRAP virtual int getNumDisparities() const = 0;
+ CV_WRAP virtual void setNumDisparities(int numDisparities) = 0;
+
+ CV_WRAP virtual int getBlockSize() const = 0;
+ CV_WRAP virtual void setBlockSize(int blockSize) = 0;
+
+ CV_WRAP virtual int getSpeckleWindowSize() const = 0;
+ CV_WRAP virtual void setSpeckleWindowSize(int speckleWindowSize) = 0;
+
+ CV_WRAP virtual int getSpeckleRange() const = 0;
+ CV_WRAP virtual void setSpeckleRange(int speckleRange) = 0;
+
+ CV_WRAP virtual int getDisp12MaxDiff() const = 0;
+ CV_WRAP virtual void setDisp12MaxDiff(int disp12MaxDiff) = 0;
+};
+
+
+
+class CV_EXPORTS_W StereoBM : public StereoMatcher
+{
+public:
+ enum { PREFILTER_NORMALIZED_RESPONSE = 0,
+ PREFILTER_XSOBEL = 1
+ };
+
+ CV_WRAP virtual int getPreFilterType() const = 0;
+ CV_WRAP virtual void setPreFilterType(int preFilterType) = 0;
+
+ CV_WRAP virtual int getPreFilterSize() const = 0;
+ CV_WRAP virtual void setPreFilterSize(int preFilterSize) = 0;
+
+ CV_WRAP virtual int getPreFilterCap() const = 0;
+ CV_WRAP virtual void setPreFilterCap(int preFilterCap) = 0;
+
+ CV_WRAP virtual int getTextureThreshold() const = 0;
+ CV_WRAP virtual void setTextureThreshold(int textureThreshold) = 0;
+
+ CV_WRAP virtual int getUniquenessRatio() const = 0;
+ CV_WRAP virtual void setUniquenessRatio(int uniquenessRatio) = 0;
+
+ CV_WRAP virtual int getSmallerBlockSize() const = 0;
+ CV_WRAP virtual void setSmallerBlockSize(int blockSize) = 0;
+
+ CV_WRAP virtual Rect getROI1() const = 0;
+ CV_WRAP virtual void setROI1(Rect roi1) = 0;
+
+ CV_WRAP virtual Rect getROI2() const = 0;
+ CV_WRAP virtual void setROI2(Rect roi2) = 0;
+};
+
+CV_EXPORTS_W Ptr<StereoBM> createStereoBM(int numDisparities = 0, int blockSize = 21);
+
+
+class CV_EXPORTS_W StereoSGBM : public StereoMatcher
+{
+public:
+ enum { MODE_SGBM = 0,
+ MODE_HH = 1
+ };
+
+ CV_WRAP virtual int getPreFilterCap() const = 0;
+ CV_WRAP virtual void setPreFilterCap(int preFilterCap) = 0;
+
+ CV_WRAP virtual int getUniquenessRatio() const = 0;
+ CV_WRAP virtual void setUniquenessRatio(int uniquenessRatio) = 0;
+
+ CV_WRAP virtual int getP1() const = 0;
+ CV_WRAP virtual void setP1(int P1) = 0;
+
+ CV_WRAP virtual int getP2() const = 0;
+ CV_WRAP virtual void setP2(int P2) = 0;
+
+ CV_WRAP virtual int getMode() const = 0;
+ CV_WRAP virtual void setMode(int mode) = 0;
+};
+
+
+CV_EXPORTS_W Ptr<StereoSGBM> createStereoSGBM(int minDisparity, int numDisparities, int blockSize,
+ int P1 = 0, int P2 = 0, int disp12MaxDiff = 0,
+ int preFilterCap = 0, int uniquenessRatio = 0,
+ 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
--- /dev/null
- void subMatrix(const Mat& src, Mat& dst, const vector<int>& cols, const vector<int>& rows);
+ /*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 "precomp.hpp"
+ #include "fisheye.hpp"
+
+ namespace cv { namespace
+ {
+ struct JacobianRow
+ {
+ Vec2d df, dc;
+ Vec4d dk;
+ Vec3d dom, dT;
+ double dalpha;
+ };
+
-void subMatrix(const Mat& src, Mat& dst, const vector<int>& cols, const vector<int>& rows)
++ void subMatrix(const Mat& src, Mat& dst, const std::vector<int>& cols, const std::vector<int>& rows);
+ }}
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::projectPoints
+
+ void cv::fisheye::projectPoints(InputArray objectPoints, OutputArray imagePoints, const Affine3d& affine,
+ InputArray K, InputArray D, double alpha, OutputArray jacobian)
+ {
+ projectPoints(objectPoints, imagePoints, affine.rvec(), affine.translation(), K, D, alpha, jacobian);
+ }
+
+ void cv::fisheye::projectPoints(InputArray objectPoints, OutputArray imagePoints, InputArray _rvec,
+ InputArray _tvec, InputArray _K, InputArray _D, double alpha, OutputArray jacobian)
+ {
+ // will support only 3-channel data now for points
+ CV_Assert(objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3);
+ imagePoints.create(objectPoints.size(), CV_MAKETYPE(objectPoints.depth(), 2));
+ size_t n = objectPoints.total();
+
+ CV_Assert(_rvec.total() * _rvec.channels() == 3 && (_rvec.depth() == CV_32F || _rvec.depth() == CV_64F));
+ CV_Assert(_tvec.total() * _tvec.channels() == 3 && (_tvec.depth() == CV_32F || _tvec.depth() == CV_64F));
+ CV_Assert(_tvec.getMat().isContinuous() && _rvec.getMat().isContinuous());
+
+ Vec3d om = _rvec.depth() == CV_32F ? (Vec3d)*_rvec.getMat().ptr<Vec3f>() : *_rvec.getMat().ptr<Vec3d>();
+ Vec3d T = _tvec.depth() == CV_32F ? (Vec3d)*_tvec.getMat().ptr<Vec3f>() : *_tvec.getMat().ptr<Vec3d>();
+
+ CV_Assert(_K.size() == Size(3,3) && (_K.type() == CV_32F || _K.type() == CV_64F) && _D.type() == _K.type() && _D.total() == 4);
+
+ cv::Vec2d f, c;
+ if (_K.depth() == CV_32F)
+ {
+
+ Matx33f K = _K.getMat();
+ f = Vec2f(K(0, 0), K(1, 1));
+ c = Vec2f(K(0, 2), K(1, 2));
+ }
+ else
+ {
+ Matx33d K = _K.getMat();
+ f = Vec2d(K(0, 0), K(1, 1));
+ c = Vec2d(K(0, 2), K(1, 2));
+ }
+
+ Vec4d k = _D.depth() == CV_32F ? (Vec4d)*_D.getMat().ptr<Vec4f>(): *_D.getMat().ptr<Vec4d>();
+
+ JacobianRow *Jn = 0;
+ if (jacobian.needed())
+ {
+ int nvars = 2 + 2 + 1 + 4 + 3 + 3; // f, c, alpha, k, om, T,
+ jacobian.create(2*(int)n, nvars, CV_64F);
+ Jn = jacobian.getMat().ptr<JacobianRow>(0);
+ }
+
+ Matx33d R;
+ Matx<double, 3, 9> dRdom;
+ Rodrigues(om, R, dRdom);
+ Affine3d aff(om, T);
+
+ const Vec3f* Xf = objectPoints.getMat().ptr<Vec3f>();
+ const Vec3d* Xd = objectPoints.getMat().ptr<Vec3d>();
+ Vec2f *xpf = imagePoints.getMat().ptr<Vec2f>();
+ Vec2d *xpd = imagePoints.getMat().ptr<Vec2d>();
+
+ for(size_t i = 0; i < n; ++i)
+ {
+ Vec3d Xi = objectPoints.depth() == CV_32F ? (Vec3d)Xf[i] : Xd[i];
+ Vec3d Y = aff*Xi;
+
+ Vec2d x(Y[0]/Y[2], Y[1]/Y[2]);
+
+ double r2 = x.dot(x);
+ double r = std::sqrt(r2);
+
+ // Angle of the incoming ray:
+ double theta = atan(r);
+
+ double theta2 = theta*theta, theta3 = theta2*theta, theta4 = theta2*theta2, theta5 = theta4*theta,
+ theta6 = theta3*theta3, theta7 = theta6*theta, theta8 = theta4*theta4, theta9 = theta8*theta;
+
+ double theta_d = theta + k[0]*theta3 + k[1]*theta5 + k[2]*theta7 + k[3]*theta9;
+
+ double inv_r = r > 1e-8 ? 1.0/r : 1;
+ double cdist = r > 1e-8 ? theta_d * inv_r : 1;
+
+ Vec2d xd1 = x * cdist;
+ Vec2d xd3(xd1[0] + alpha*xd1[1], xd1[1]);
+ Vec2d final_point(xd3[0] * f[0] + c[0], xd3[1] * f[1] + c[1]);
+
+ if (objectPoints.depth() == CV_32F)
+ xpf[i] = final_point;
+ else
+ xpd[i] = final_point;
+
+ if (jacobian.needed())
+ {
+ //Vec3d Xi = pdepth == CV_32F ? (Vec3d)Xf[i] : Xd[i];
+ //Vec3d Y = aff*Xi;
+ double dYdR[] = { Xi[0], Xi[1], Xi[2], 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, Xi[0], Xi[1], Xi[2], 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, Xi[0], Xi[1], Xi[2] };
+
+ Matx33d dYdom_data = Matx<double, 3, 9>(dYdR) * dRdom.t();
+ const Vec3d *dYdom = (Vec3d*)dYdom_data.val;
+
+ Matx33d dYdT_data = Matx33d::eye();
+ const Vec3d *dYdT = (Vec3d*)dYdT_data.val;
+
+ //Vec2d x(Y[0]/Y[2], Y[1]/Y[2]);
+ Vec3d dxdom[2];
+ dxdom[0] = (1.0/Y[2]) * dYdom[0] - x[0]/Y[2] * dYdom[2];
+ dxdom[1] = (1.0/Y[2]) * dYdom[1] - x[1]/Y[2] * dYdom[2];
+
+ Vec3d dxdT[2];
+ dxdT[0] = (1.0/Y[2]) * dYdT[0] - x[0]/Y[2] * dYdT[2];
+ dxdT[1] = (1.0/Y[2]) * dYdT[1] - x[1]/Y[2] * dYdT[2];
+
+ //double r2 = x.dot(x);
+ Vec3d dr2dom = 2 * x[0] * dxdom[0] + 2 * x[1] * dxdom[1];
+ Vec3d dr2dT = 2 * x[0] * dxdT[0] + 2 * x[1] * dxdT[1];
+
+ //double r = std::sqrt(r2);
+ double drdr2 = r > 1e-8 ? 1.0/(2*r) : 1;
+ Vec3d drdom = drdr2 * dr2dom;
+ Vec3d drdT = drdr2 * dr2dT;
+
+ // Angle of the incoming ray:
+ //double theta = atan(r);
+ double dthetadr = 1.0/(1+r2);
+ Vec3d dthetadom = dthetadr * drdom;
+ Vec3d dthetadT = dthetadr * drdT;
+
+ //double theta_d = theta + k[0]*theta3 + k[1]*theta5 + k[2]*theta7 + k[3]*theta9;
+ double dtheta_ddtheta = 1 + 3*k[0]*theta2 + 5*k[1]*theta4 + 7*k[2]*theta6 + 9*k[3]*theta8;
+ Vec3d dtheta_ddom = dtheta_ddtheta * dthetadom;
+ Vec3d dtheta_ddT = dtheta_ddtheta * dthetadT;
+ Vec4d dtheta_ddk = Vec4d(theta3, theta5, theta7, theta9);
+
+ //double inv_r = r > 1e-8 ? 1.0/r : 1;
+ //double cdist = r > 1e-8 ? theta_d / r : 1;
+ Vec3d dcdistdom = inv_r * (dtheta_ddom - cdist*drdom);
+ Vec3d dcdistdT = inv_r * (dtheta_ddT - cdist*drdT);
+ Vec4d dcdistdk = inv_r * dtheta_ddk;
+
+ //Vec2d xd1 = x * cdist;
+ Vec4d dxd1dk[2];
+ Vec3d dxd1dom[2], dxd1dT[2];
+ dxd1dom[0] = x[0] * dcdistdom + cdist * dxdom[0];
+ dxd1dom[1] = x[1] * dcdistdom + cdist * dxdom[1];
+ dxd1dT[0] = x[0] * dcdistdT + cdist * dxdT[0];
+ dxd1dT[1] = x[1] * dcdistdT + cdist * dxdT[1];
+ dxd1dk[0] = x[0] * dcdistdk;
+ dxd1dk[1] = x[1] * dcdistdk;
+
+ //Vec2d xd3(xd1[0] + alpha*xd1[1], xd1[1]);
+ Vec4d dxd3dk[2];
+ Vec3d dxd3dom[2], dxd3dT[2];
+ dxd3dom[0] = dxd1dom[0] + alpha * dxd1dom[1];
+ dxd3dom[1] = dxd1dom[1];
+ dxd3dT[0] = dxd1dT[0] + alpha * dxd1dT[1];
+ dxd3dT[1] = dxd1dT[1];
+ dxd3dk[0] = dxd1dk[0] + alpha * dxd1dk[1];
+ dxd3dk[1] = dxd1dk[1];
+
+ Vec2d dxd3dalpha(xd1[1], 0);
+
+ //final jacobian
+ Jn[0].dom = f[0] * dxd3dom[0];
+ Jn[1].dom = f[1] * dxd3dom[1];
+
+ Jn[0].dT = f[0] * dxd3dT[0];
+ Jn[1].dT = f[1] * dxd3dT[1];
+
+ Jn[0].dk = f[0] * dxd3dk[0];
+ Jn[1].dk = f[1] * dxd3dk[1];
+
+ Jn[0].dalpha = f[0] * dxd3dalpha[0];
+ Jn[1].dalpha = 0; //f[1] * dxd3dalpha[1];
+
+ Jn[0].df = Vec2d(xd3[0], 0);
+ Jn[1].df = Vec2d(0, xd3[1]);
+
+ Jn[0].dc = Vec2d(1, 0);
+ Jn[1].dc = Vec2d(0, 1);
+
+ //step to jacobian rows for next point
+ Jn += 2;
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::distortPoints
+
+ void cv::fisheye::distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha)
+ {
+ // will support only 2-channel data now for points
+ CV_Assert(undistorted.type() == CV_32FC2 || undistorted.type() == CV_64FC2);
+ distorted.create(undistorted.size(), undistorted.type());
+ size_t n = undistorted.total();
+
+ CV_Assert(K.size() == Size(3,3) && (K.type() == CV_32F || K.type() == CV_64F) && D.total() == 4);
+
+ cv::Vec2d f, c;
+ if (K.depth() == CV_32F)
+ {
+ Matx33f camMat = K.getMat();
+ f = Vec2f(camMat(0, 0), camMat(1, 1));
+ c = Vec2f(camMat(0, 2), camMat(1, 2));
+ }
+ else
+ {
+ Matx33d camMat = K.getMat();
+ f = Vec2d(camMat(0, 0), camMat(1, 1));
+ c = Vec2d(camMat(0 ,2), camMat(1, 2));
+ }
+
+ Vec4d k = D.depth() == CV_32F ? (Vec4d)*D.getMat().ptr<Vec4f>(): *D.getMat().ptr<Vec4d>();
+
+ const Vec2f* Xf = undistorted.getMat().ptr<Vec2f>();
+ const Vec2d* Xd = undistorted.getMat().ptr<Vec2d>();
+ Vec2f *xpf = distorted.getMat().ptr<Vec2f>();
+ Vec2d *xpd = distorted.getMat().ptr<Vec2d>();
+
+ for(size_t i = 0; i < n; ++i)
+ {
+ Vec2d x = undistorted.depth() == CV_32F ? (Vec2d)Xf[i] : Xd[i];
+
+ double r2 = x.dot(x);
+ double r = std::sqrt(r2);
+
+ // Angle of the incoming ray:
+ double theta = atan(r);
+
+ double theta2 = theta*theta, theta3 = theta2*theta, theta4 = theta2*theta2, theta5 = theta4*theta,
+ theta6 = theta3*theta3, theta7 = theta6*theta, theta8 = theta4*theta4, theta9 = theta8*theta;
+
+ double theta_d = theta + k[0]*theta3 + k[1]*theta5 + k[2]*theta7 + k[3]*theta9;
+
+ double inv_r = r > 1e-8 ? 1.0/r : 1;
+ double cdist = r > 1e-8 ? theta_d * inv_r : 1;
+
+ Vec2d xd1 = x * cdist;
+ Vec2d xd3(xd1[0] + alpha*xd1[1], xd1[1]);
+ Vec2d final_point(xd3[0] * f[0] + c[0], xd3[1] * f[1] + c[1]);
+
+ if (undistorted.depth() == CV_32F)
+ xpf[i] = final_point;
+ else
+ xpd[i] = final_point;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::undistortPoints
+
+ void cv::fisheye::undistortPoints( InputArray distorted, OutputArray undistorted, InputArray K, InputArray D, InputArray R, InputArray P)
+ {
+ // will support only 2-channel data now for points
+ CV_Assert(distorted.type() == CV_32FC2 || distorted.type() == CV_64FC2);
+ undistorted.create(distorted.size(), distorted.type());
+
+ CV_Assert(P.empty() || P.size() == Size(3, 3) || P.size() == Size(4, 3));
+ CV_Assert(R.empty() || R.size() == Size(3, 3) || R.total() * R.channels() == 3);
+ CV_Assert(D.total() == 4 && K.size() == Size(3, 3) && (K.depth() == CV_32F || K.depth() == CV_64F));
+
+ cv::Vec2d f, c;
+ if (K.depth() == CV_32F)
+ {
+ Matx33f camMat = K.getMat();
+ f = Vec2f(camMat(0, 0), camMat(1, 1));
+ c = Vec2f(camMat(0, 2), camMat(1, 2));
+ }
+ else
+ {
+ Matx33d camMat = K.getMat();
+ f = Vec2d(camMat(0, 0), camMat(1, 1));
+ c = Vec2d(camMat(0, 2), camMat(1, 2));
+ }
+
+ Vec4d k = D.depth() == CV_32F ? (Vec4d)*D.getMat().ptr<Vec4f>(): *D.getMat().ptr<Vec4d>();
+
+ cv::Matx33d RR = cv::Matx33d::eye();
+ if (!R.empty() && R.total() * R.channels() == 3)
+ {
+ cv::Vec3d rvec;
+ R.getMat().convertTo(rvec, CV_64F);
+ RR = cv::Affine3d(rvec).rotation();
+ }
+ else if (!R.empty() && R.size() == Size(3, 3))
+ R.getMat().convertTo(RR, CV_64F);
+
+ if(!P.empty())
+ {
+ cv::Matx33d PP;
+ P.getMat().colRange(0, 3).convertTo(PP, CV_64F);
+ RR = PP * RR;
+ }
+
+ // start undistorting
+ const cv::Vec2f* srcf = distorted.getMat().ptr<cv::Vec2f>();
+ const cv::Vec2d* srcd = distorted.getMat().ptr<cv::Vec2d>();
+ cv::Vec2f* dstf = undistorted.getMat().ptr<cv::Vec2f>();
+ cv::Vec2d* dstd = undistorted.getMat().ptr<cv::Vec2d>();
+
+ size_t n = distorted.total();
+ int sdepth = distorted.depth();
+
+ for(size_t i = 0; i < n; i++ )
+ {
+ Vec2d pi = sdepth == CV_32F ? (Vec2d)srcf[i] : srcd[i]; // image point
+ Vec2d pw((pi[0] - c[0])/f[0], (pi[1] - c[1])/f[1]); // world point
+
+ double scale = 1.0;
+
+ double theta_d = sqrt(pw[0]*pw[0] + pw[1]*pw[1]);
+ if (theta_d > 1e-8)
+ {
+ // compensate distortion iteratively
+ double theta = theta_d;
+ for(int j = 0; j < 10; j++ )
+ {
+ double theta2 = theta*theta, theta4 = theta2*theta2, theta6 = theta4*theta2, theta8 = theta6*theta2;
+ theta = theta_d / (1 + k[0] * theta2 + k[1] * theta4 + k[2] * theta6 + k[3] * theta8);
+ }
+
+ scale = std::tan(theta) / theta_d;
+ }
+
+ Vec2d pu = pw * scale; //undistorted point
+
+ // reproject
+ Vec3d pr = RR * Vec3d(pu[0], pu[1], 1.0); // rotated point optionally multiplied by new camera matrix
+ Vec2d fi(pr[0]/pr[2], pr[1]/pr[2]); // final
+
+ if( sdepth == CV_32F )
+ dstf[i] = fi;
+ else
+ dstd[i] = fi;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::undistortPoints
+
+ void cv::fisheye::initUndistortRectifyMap( InputArray K, InputArray D, InputArray R, InputArray P,
+ const cv::Size& size, int m1type, OutputArray map1, OutputArray map2 )
+ {
+ CV_Assert( m1type == CV_16SC2 || m1type == CV_32F || m1type <=0 );
+ map1.create( size, m1type <= 0 ? CV_16SC2 : m1type );
+ map2.create( size, map1.type() == CV_16SC2 ? CV_16UC1 : CV_32F );
+
+ CV_Assert((K.depth() == CV_32F || K.depth() == CV_64F) && (D.depth() == CV_32F || D.depth() == CV_64F));
+ CV_Assert((P.depth() == CV_32F || P.depth() == CV_64F) && (R.depth() == CV_32F || R.depth() == CV_64F));
+ CV_Assert(K.size() == Size(3, 3) && (D.empty() || D.total() == 4));
+ CV_Assert(R.empty() || R.size() == Size(3, 3) || R.total() * R.channels() == 3);
+ CV_Assert(P.empty() || P.size() == Size(3, 3) || P.size() == Size(4, 3));
+
+ cv::Vec2d f, c;
+ if (K.depth() == CV_32F)
+ {
+ Matx33f camMat = K.getMat();
+ f = Vec2f(camMat(0, 0), camMat(1, 1));
+ c = Vec2f(camMat(0, 2), camMat(1, 2));
+ }
+ else
+ {
+ Matx33d camMat = K.getMat();
+ f = Vec2d(camMat(0, 0), camMat(1, 1));
+ c = Vec2d(camMat(0, 2), camMat(1, 2));
+ }
+
+ Vec4d k = Vec4d::all(0);
+ if (!D.empty())
+ k = D.depth() == CV_32F ? (Vec4d)*D.getMat().ptr<Vec4f>(): *D.getMat().ptr<Vec4d>();
+
+ cv::Matx33d RR = cv::Matx33d::eye();
+ if (!R.empty() && R.total() * R.channels() == 3)
+ {
+ cv::Vec3d rvec;
+ R.getMat().convertTo(rvec, CV_64F);
+ RR = Affine3d(rvec).rotation();
+ }
+ else if (!R.empty() && R.size() == Size(3, 3))
+ R.getMat().convertTo(RR, CV_64F);
+
+ cv::Matx33d PP = cv::Matx33d::eye();
+ if (!P.empty())
+ P.getMat().colRange(0, 3).convertTo(PP, CV_64F);
+
+ cv::Matx33d iR = (PP * RR).inv(cv::DECOMP_SVD);
+
+ for( int i = 0; i < size.height; ++i)
+ {
+ float* m1f = map1.getMat().ptr<float>(i);
+ float* m2f = map2.getMat().ptr<float>(i);
+ short* m1 = (short*)m1f;
+ ushort* m2 = (ushort*)m2f;
+
+ double _x = i*iR(0, 1) + iR(0, 2),
+ _y = i*iR(1, 1) + iR(1, 2),
+ _w = i*iR(2, 1) + iR(2, 2);
+
+ for( int j = 0; j < size.width; ++j)
+ {
+ double x = _x/_w, y = _y/_w;
+
+ double r = sqrt(x*x + y*y);
+ double theta = atan(r);
+
+ double theta2 = theta*theta, theta4 = theta2*theta2, theta6 = theta4*theta2, theta8 = theta4*theta4;
+ double theta_d = theta * (1 + k[0]*theta2 + k[1]*theta4 + k[2]*theta6 + k[3]*theta8);
+
+ double scale = (r == 0) ? 1.0 : theta_d / r;
+ double u = f[0]*x*scale + c[0];
+ double v = f[1]*y*scale + c[1];
+
+ if( m1type == CV_16SC2 )
+ {
+ int iu = cv::saturate_cast<int>(u*cv::INTER_TAB_SIZE);
+ int iv = cv::saturate_cast<int>(v*cv::INTER_TAB_SIZE);
+ m1[j*2+0] = (short)(iu >> cv::INTER_BITS);
+ m1[j*2+1] = (short)(iv >> cv::INTER_BITS);
+ m2[j] = (ushort)((iv & (cv::INTER_TAB_SIZE-1))*cv::INTER_TAB_SIZE + (iu & (cv::INTER_TAB_SIZE-1)));
+ }
+ else if( m1type == CV_32FC1 )
+ {
+ m1f[j] = (float)u;
+ m2f[j] = (float)v;
+ }
+
+ _x += iR(0, 0);
+ _y += iR(1, 0);
+ _w += iR(2, 0);
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::undistortImage
+
+ void cv::fisheye::undistortImage(InputArray distorted, OutputArray undistorted,
+ InputArray K, InputArray D, InputArray Knew, const Size& new_size)
+ {
+ Size size = new_size.area() != 0 ? new_size : distorted.size();
+
+ cv::Mat map1, map2;
+ fisheye::initUndistortRectifyMap(K, D, cv::Matx33d::eye(), Knew, size, CV_16SC2, map1, map2 );
+ cv::remap(distorted, undistorted, map1, map2, INTER_LINEAR, BORDER_CONSTANT);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::estimateNewCameraMatrixForUndistortRectify
+
+ void cv::fisheye::estimateNewCameraMatrixForUndistortRectify(InputArray K, InputArray D, const Size &image_size, InputArray R,
+ OutputArray P, double balance, const Size& new_size, double fov_scale)
+ {
+ CV_Assert( K.size() == Size(3, 3) && (K.depth() == CV_32F || K.depth() == CV_64F));
+ CV_Assert((D.empty() || D.total() == 4) && (D.depth() == CV_32F || D.depth() == CV_64F || D.empty()));
+
+ int w = image_size.width, h = image_size.height;
+ balance = std::min(std::max(balance, 0.0), 1.0);
+
+ cv::Mat points(1, 4, CV_64FC2);
+ Vec2d* pptr = points.ptr<Vec2d>();
+ pptr[0] = Vec2d(w/2, 0);
+ pptr[1] = Vec2d(w, h/2);
+ pptr[2] = Vec2d(w/2, h);
+ pptr[3] = Vec2d(0, h/2);
+
+ #if 0
+ const int N = 10;
+ cv::Mat points(1, N * 4, CV_64FC2);
+ Vec2d* pptr = points.ptr<Vec2d>();
+ for(int i = 0, k = 0; i < 10; ++i)
+ {
+ pptr[k++] = Vec2d(w/2, 0) - Vec2d(w/8, 0) + Vec2d(w/4/N*i, 0);
+ pptr[k++] = Vec2d(w/2, h-1) - Vec2d(w/8, h-1) + Vec2d(w/4/N*i, h-1);
+
+ pptr[k++] = Vec2d(0, h/2) - Vec2d(0, h/8) + Vec2d(0, h/4/N*i);
+ pptr[k++] = Vec2d(w-1, h/2) - Vec2d(w-1, h/8) + Vec2d(w-1, h/4/N*i);
+ }
+ #endif
+
+ fisheye::undistortPoints(points, points, K, D, R);
+ cv::Scalar center_mass = mean(points);
+ cv::Vec2d cn(center_mass.val);
+
+ double aspect_ratio = (K.depth() == CV_32F) ? K.getMat().at<float >(0,0)/K.getMat().at<float> (1,1)
+ : K.getMat().at<double>(0,0)/K.getMat().at<double>(1,1);
+
+ // convert to identity ratio
+ cn[0] *= aspect_ratio;
+ for(size_t i = 0; i < points.total(); ++i)
+ pptr[i][1] *= aspect_ratio;
+
+ double minx = DBL_MAX, miny = DBL_MAX, maxx = -DBL_MAX, maxy = -DBL_MAX;
+ for(size_t i = 0; i < points.total(); ++i)
+ {
+ miny = std::min(miny, pptr[i][1]);
+ maxy = std::max(maxy, pptr[i][1]);
+ minx = std::min(minx, pptr[i][0]);
+ maxx = std::max(maxx, pptr[i][0]);
+ }
+
+ #if 0
+ double minx = -DBL_MAX, miny = -DBL_MAX, maxx = DBL_MAX, maxy = DBL_MAX;
+ for(size_t i = 0; i < points.total(); ++i)
+ {
+ if (i % 4 == 0) miny = std::max(miny, pptr[i][1]);
+ if (i % 4 == 1) maxy = std::min(maxy, pptr[i][1]);
+ if (i % 4 == 2) minx = std::max(minx, pptr[i][0]);
+ if (i % 4 == 3) maxx = std::min(maxx, pptr[i][0]);
+ }
+ #endif
+
+ double f1 = w * 0.5/(cn[0] - minx);
+ double f2 = w * 0.5/(maxx - cn[0]);
+ double f3 = h * 0.5 * aspect_ratio/(cn[1] - miny);
+ double f4 = h * 0.5 * aspect_ratio/(maxy - cn[1]);
+
+ double fmin = std::min(f1, std::min(f2, std::min(f3, f4)));
+ double fmax = std::max(f1, std::max(f2, std::max(f3, f4)));
+
+ double f = balance * fmin + (1.0 - balance) * fmax;
+ f *= fov_scale > 0 ? 1.0/fov_scale : 1.0;
+
+ cv::Vec2d new_f(f, f), new_c = -cn * f + Vec2d(w, h * aspect_ratio) * 0.5;
+
+ // restore aspect ratio
+ new_f[1] /= aspect_ratio;
+ new_c[1] /= aspect_ratio;
+
+ if (new_size.area() > 0)
+ {
+ double rx = new_size.width /(double)image_size.width;
+ double ry = new_size.height/(double)image_size.height;
+
+ new_f[0] *= rx; new_f[1] *= ry;
+ new_c[0] *= rx; new_c[1] *= ry;
+ }
+
+ Mat(Matx33d(new_f[0], 0, new_c[0],
+ 0, new_f[1], new_c[1],
+ 0, 0, 1)).convertTo(P, P.empty() ? K.type() : P.type());
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::stereoRectify
+
+ void cv::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, double balance, double fov_scale)
+ {
+ CV_Assert((_R.size() == Size(3, 3) || _R.total() * _R.channels() == 3) && (_R.depth() == CV_32F || _R.depth() == CV_64F));
+ CV_Assert(_tvec.total() * _tvec.channels() == 3 && (_tvec.depth() == CV_32F || _tvec.depth() == CV_64F));
+
+
+ cv::Mat aaa = _tvec.getMat().reshape(3, 1);
+
+ Vec3d rvec; // Rodrigues vector
+ if (_R.size() == Size(3, 3))
+ {
+ cv::Matx33d rmat;
+ _R.getMat().convertTo(rmat, CV_64F);
+ rvec = Affine3d(rmat).rvec();
+ }
+ else if (_R.total() * _R.channels() == 3)
+ _R.getMat().convertTo(rvec, CV_64F);
+
+ Vec3d tvec;
+ _tvec.getMat().convertTo(tvec, CV_64F);
+
+ // rectification algorithm
+ rvec *= -0.5; // get average rotation
+
+ Matx33d r_r;
+ Rodrigues(rvec, r_r); // rotate cameras to same orientation by averaging
+
+ Vec3d t = r_r * tvec;
+ Vec3d uu(t[0] > 0 ? 1 : -1, 0, 0);
+
+ // calculate global Z rotation
+ Vec3d ww = t.cross(uu);
+ double nw = norm(ww);
+ if (nw > 0.0)
+ ww *= acos(fabs(t[0])/cv::norm(t))/nw;
+
+ Matx33d wr;
+ Rodrigues(ww, wr);
+
+ // apply to both views
+ Matx33d ri1 = wr * r_r.t();
+ Mat(ri1, false).convertTo(R1, R1.empty() ? CV_64F : R1.type());
+ Matx33d ri2 = wr * r_r;
+ Mat(ri2, false).convertTo(R2, R2.empty() ? CV_64F : R2.type());
+ Vec3d tnew = ri2 * tvec;
+
+ // calculate projection/camera matrices. these contain the relevant rectified image internal params (fx, fy=fx, cx, cy)
+ Matx33d newK1, newK2;
+ estimateNewCameraMatrixForUndistortRectify(K1, D1, imageSize, R1, newK1, balance, newImageSize, fov_scale);
+ estimateNewCameraMatrixForUndistortRectify(K2, D2, imageSize, R2, newK2, balance, newImageSize, fov_scale);
+
+ double fc_new = std::min(newK1(1,1), newK2(1,1));
+ Point2d cc_new[2] = { Vec2d(newK1(0, 2), newK1(1, 2)), Vec2d(newK2(0, 2), newK2(1, 2)) };
+
+ // Vertical focal length must be the same for both images to keep the epipolar constraint use fy for fx also.
+ // For simplicity, set the principal points for both cameras to be the average
+ // of the two principal points (either one of or both x- and y- coordinates)
+ if( flags & cv::CALIB_ZERO_DISPARITY )
+ cc_new[0] = cc_new[1] = (cc_new[0] + cc_new[1]) * 0.5;
+ else
+ cc_new[0].y = cc_new[1].y = (cc_new[0].y + cc_new[1].y)*0.5;
+
+ Mat(Matx34d(fc_new, 0, cc_new[0].x, 0,
+ 0, fc_new, cc_new[0].y, 0,
+ 0, 0, 1, 0), false).convertTo(P1, P1.empty() ? CV_64F : P1.type());
+
+ Mat(Matx34d(fc_new, 0, cc_new[1].x, tnew[0]*fc_new, // baseline * focal length;,
+ 0, fc_new, cc_new[1].y, 0,
+ 0, 0, 1, 0), false).convertTo(P2, P2.empty() ? CV_64F : P2.type());
+
+ if (Q.needed())
+ Mat(Matx44d(1, 0, 0, -cc_new[0].x,
+ 0, 1, 0, -cc_new[0].y,
+ 0, 0, 0, fc_new,
+ 0, 0, -1./tnew[0], (cc_new[0].x - cc_new[1].x)/tnew[0]), false).convertTo(Q, Q.empty() ? CV_64F : Q.depth());
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::calibrate
+
+ double cv::fisheye::calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size,
+ InputOutputArray K, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
+ int flags , cv::TermCriteria criteria)
+ {
+ CV_Assert(!objectPoints.empty() && !imagePoints.empty() && objectPoints.total() == imagePoints.total());
+ CV_Assert(objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3);
+ CV_Assert(imagePoints.type() == CV_32FC2 || imagePoints.type() == CV_64FC2);
+ CV_Assert((!K.empty() && K.size() == Size(3,3)) || K.empty());
+ CV_Assert((!D.empty() && D.total() == 4) || D.empty());
+ CV_Assert((!rvecs.empty() && rvecs.channels() == 3) || rvecs.empty());
+ CV_Assert((!tvecs.empty() && tvecs.channels() == 3) || tvecs.empty());
+
+ CV_Assert(((flags & CALIB_USE_INTRINSIC_GUESS) && !K.empty() && !D.empty()) || !(flags & CALIB_USE_INTRINSIC_GUESS));
+
+ using namespace cv::internal;
+ //-------------------------------Initialization
+ IntrinsicParams finalParam;
+ IntrinsicParams currentParam;
+ IntrinsicParams errors;
+
+ finalParam.isEstimate[0] = 1;
+ finalParam.isEstimate[1] = 1;
+ finalParam.isEstimate[2] = 1;
+ finalParam.isEstimate[3] = 1;
+ finalParam.isEstimate[4] = flags & CALIB_FIX_SKEW ? 0 : 1;
+ finalParam.isEstimate[5] = flags & CALIB_FIX_K1 ? 0 : 1;
+ finalParam.isEstimate[6] = flags & CALIB_FIX_K2 ? 0 : 1;
+ finalParam.isEstimate[7] = flags & CALIB_FIX_K3 ? 0 : 1;
+ finalParam.isEstimate[8] = flags & CALIB_FIX_K4 ? 0 : 1;
+
+ const int recompute_extrinsic = flags & CALIB_RECOMPUTE_EXTRINSIC ? 1: 0;
+ const int check_cond = flags & CALIB_CHECK_COND ? 1 : 0;
+
+ const double alpha_smooth = 0.4;
+ const double thresh_cond = 1e6;
+ double change = 1;
+ Vec2d err_std;
+
+ Matx33d _K;
+ Vec4d _D;
+ if (flags & CALIB_USE_INTRINSIC_GUESS)
+ {
+ K.getMat().convertTo(_K, CV_64FC1);
+ D.getMat().convertTo(_D, CV_64FC1);
+ finalParam.Init(Vec2d(_K(0,0), _K(1, 1)),
+ Vec2d(_K(0,2), _K(1, 2)),
+ Vec4d(flags & CALIB_FIX_K1 ? 0 : _D[0],
+ flags & CALIB_FIX_K2 ? 0 : _D[1],
+ flags & CALIB_FIX_K3 ? 0 : _D[2],
+ flags & CALIB_FIX_K4 ? 0 : _D[3]),
+ _K(0, 1) / _K(0, 0));
+ }
+ else
+ {
+ finalParam.Init(Vec2d(max(image_size.width, image_size.height) / CV_PI, max(image_size.width, image_size.height) / CV_PI),
+ Vec2d(image_size.width / 2.0 - 0.5, image_size.height / 2.0 - 0.5));
+ }
+
+ errors.isEstimate = finalParam.isEstimate;
+
+ std::vector<Vec3d> omc(objectPoints.total()), Tc(objectPoints.total());
+
+ CalibrateExtrinsics(objectPoints, imagePoints, finalParam, check_cond, thresh_cond, omc, Tc);
+
+
+ //-------------------------------Optimization
+ for(int iter = 0; ; ++iter)
+ {
+ if ((criteria.type == 1 && iter >= criteria.maxCount) ||
+ (criteria.type == 2 && change <= criteria.epsilon) ||
+ (criteria.type == 3 && (change <= criteria.epsilon || iter >= criteria.maxCount)))
+ break;
+
+ double alpha_smooth2 = 1 - std::pow(1 - alpha_smooth, iter + 1.0);
+
+ Mat JJ2_inv, ex3;
+ ComputeJacobians(objectPoints, imagePoints, finalParam, omc, Tc, check_cond,thresh_cond, JJ2_inv, ex3);
+
+ Mat G = alpha_smooth2 * JJ2_inv * ex3;
+
+ currentParam = finalParam + G;
+
+ change = norm(Vec4d(currentParam.f[0], currentParam.f[1], currentParam.c[0], currentParam.c[1]) -
+ Vec4d(finalParam.f[0], finalParam.f[1], finalParam.c[0], finalParam.c[1]))
+ / norm(Vec4d(currentParam.f[0], currentParam.f[1], currentParam.c[0], currentParam.c[1]));
+
+ finalParam = currentParam;
+
+ if (recompute_extrinsic)
+ {
+ CalibrateExtrinsics(objectPoints, imagePoints, finalParam, check_cond,
+ thresh_cond, omc, Tc);
+ }
+ }
+
+ //-------------------------------Validation
+ double rms;
+ EstimateUncertainties(objectPoints, imagePoints, finalParam, omc, Tc, errors, err_std, thresh_cond,
+ check_cond, rms);
+
+ //-------------------------------
+ _K = Matx33d(finalParam.f[0], finalParam.f[0] * finalParam.alpha, finalParam.c[0],
+ 0, finalParam.f[1], finalParam.c[1],
+ 0, 0, 1);
+
+ if (K.needed()) cv::Mat(_K).convertTo(K, K.empty() ? CV_64FC1 : K.type());
+ if (D.needed()) cv::Mat(finalParam.k).convertTo(D, D.empty() ? CV_64FC1 : D.type());
+ if (rvecs.needed()) cv::Mat(omc).convertTo(rvecs, rvecs.empty() ? CV_64FC3 : rvecs.type());
+ if (tvecs.needed()) cv::Mat(Tc).convertTo(tvecs, tvecs.empty() ? CV_64FC3 : tvecs.type());
+
+ return rms;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// cv::fisheye::stereoCalibrate
+
+ double cv::fisheye::stereoCalibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2,
+ InputOutputArray K1, InputOutputArray D1, InputOutputArray K2, InputOutputArray D2, Size imageSize,
+ OutputArray R, OutputArray T, int flags, TermCriteria criteria)
+ {
+ CV_Assert(!objectPoints.empty() && !imagePoints1.empty() && !imagePoints2.empty());
+ CV_Assert(objectPoints.total() == imagePoints1.total() || imagePoints1.total() == imagePoints2.total());
+ CV_Assert(objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3);
+ CV_Assert(imagePoints1.type() == CV_32FC2 || imagePoints1.type() == CV_64FC2);
+ CV_Assert(imagePoints2.type() == CV_32FC2 || imagePoints2.type() == CV_64FC2);
+
+ CV_Assert((!K1.empty() && K1.size() == Size(3,3)) || K1.empty());
+ CV_Assert((!D1.empty() && D1.total() == 4) || D1.empty());
+ CV_Assert((!K2.empty() && K1.size() == Size(3,3)) || K2.empty());
+ CV_Assert((!D2.empty() && D1.total() == 4) || D2.empty());
+
+ CV_Assert(((flags & CALIB_FIX_INTRINSIC) && !K1.empty() && !K2.empty() && !D1.empty() && !D2.empty()) || !(flags & CALIB_FIX_INTRINSIC));
+
+ //-------------------------------Initialization
+
+ const int threshold = 50;
+ const double thresh_cond = 1e6;
+ const int check_cond = 1;
+
+ int n_points = (int)objectPoints.getMat(0).total();
+ int n_images = (int)objectPoints.total();
+
+ double change = 1;
+
+ cv::internal::IntrinsicParams intrinsicLeft;
+ cv::internal::IntrinsicParams intrinsicRight;
+
+ cv::internal::IntrinsicParams intrinsicLeft_errors;
+ cv::internal::IntrinsicParams intrinsicRight_errors;
+
+ Matx33d _K1, _K2;
+ Vec4d _D1, _D2;
+ if (!K1.empty()) K1.getMat().convertTo(_K1, CV_64FC1);
+ if (!D1.empty()) D1.getMat().convertTo(_D1, CV_64FC1);
+ if (!K2.empty()) K2.getMat().convertTo(_K2, CV_64FC1);
+ if (!D2.empty()) D2.getMat().convertTo(_D2, CV_64FC1);
+
+ std::vector<Vec3d> rvecs1(n_images), tvecs1(n_images), rvecs2(n_images), tvecs2(n_images);
+
+ if (!(flags & CALIB_FIX_INTRINSIC))
+ {
+ calibrate(objectPoints, imagePoints1, imageSize, _K1, _D1, rvecs1, tvecs1, flags, TermCriteria(3, 20, 1e-6));
+ calibrate(objectPoints, imagePoints2, imageSize, _K2, _D2, rvecs2, tvecs2, flags, TermCriteria(3, 20, 1e-6));
+ }
+
+ intrinsicLeft.Init(Vec2d(_K1(0,0), _K1(1, 1)), Vec2d(_K1(0,2), _K1(1, 2)),
+ Vec4d(_D1[0], _D1[1], _D1[2], _D1[3]), _K1(0, 1) / _K1(0, 0));
+
+ intrinsicRight.Init(Vec2d(_K2(0,0), _K2(1, 1)), Vec2d(_K2(0,2), _K2(1, 2)),
+ Vec4d(_D2[0], _D2[1], _D2[2], _D2[3]), _K2(0, 1) / _K2(0, 0));
+
+ if ((flags & CALIB_FIX_INTRINSIC))
+ {
+ internal::CalibrateExtrinsics(objectPoints, imagePoints1, intrinsicLeft, check_cond, thresh_cond, rvecs1, tvecs1);
+ internal::CalibrateExtrinsics(objectPoints, imagePoints2, intrinsicRight, check_cond, thresh_cond, rvecs2, tvecs2);
+ }
+
+ intrinsicLeft.isEstimate[0] = flags & CALIB_FIX_INTRINSIC ? 0 : 1;
+ intrinsicLeft.isEstimate[1] = flags & CALIB_FIX_INTRINSIC ? 0 : 1;
+ intrinsicLeft.isEstimate[2] = flags & CALIB_FIX_INTRINSIC ? 0 : 1;
+ intrinsicLeft.isEstimate[3] = flags & CALIB_FIX_INTRINSIC ? 0 : 1;
+ intrinsicLeft.isEstimate[4] = flags & (CALIB_FIX_SKEW | CALIB_FIX_INTRINSIC) ? 0 : 1;
+ intrinsicLeft.isEstimate[5] = flags & (CALIB_FIX_K1 | CALIB_FIX_INTRINSIC) ? 0 : 1;
+ intrinsicLeft.isEstimate[6] = flags & (CALIB_FIX_K2 | CALIB_FIX_INTRINSIC) ? 0 : 1;
+ intrinsicLeft.isEstimate[7] = flags & (CALIB_FIX_K3 | CALIB_FIX_INTRINSIC) ? 0 : 1;
+ intrinsicLeft.isEstimate[8] = flags & (CALIB_FIX_K4 | CALIB_FIX_INTRINSIC) ? 0 : 1;
+
+ intrinsicRight.isEstimate[0] = flags & CALIB_FIX_INTRINSIC ? 0 : 1;
+ intrinsicRight.isEstimate[1] = flags & CALIB_FIX_INTRINSIC ? 0 : 1;
+ intrinsicRight.isEstimate[2] = flags & CALIB_FIX_INTRINSIC ? 0 : 1;
+ intrinsicRight.isEstimate[3] = flags & CALIB_FIX_INTRINSIC ? 0 : 1;
+ intrinsicRight.isEstimate[4] = flags & (CALIB_FIX_SKEW | CALIB_FIX_INTRINSIC) ? 0 : 1;
+ intrinsicRight.isEstimate[5] = flags & (CALIB_FIX_K1 | CALIB_FIX_INTRINSIC) ? 0 : 1;
+ intrinsicRight.isEstimate[6] = flags & (CALIB_FIX_K2 | CALIB_FIX_INTRINSIC) ? 0 : 1;
+ intrinsicRight.isEstimate[7] = flags & (CALIB_FIX_K3 | CALIB_FIX_INTRINSIC) ? 0 : 1;
+ intrinsicRight.isEstimate[8] = flags & (CALIB_FIX_K4 | CALIB_FIX_INTRINSIC) ? 0 : 1;
+
+ intrinsicLeft_errors.isEstimate = intrinsicLeft.isEstimate;
+ intrinsicRight_errors.isEstimate = intrinsicRight.isEstimate;
+
+ std::vector<int> selectedParams;
+ std::vector<int> tmp(6 * (n_images + 1), 1);
+ selectedParams.insert(selectedParams.end(), intrinsicLeft.isEstimate.begin(), intrinsicLeft.isEstimate.end());
+ selectedParams.insert(selectedParams.end(), intrinsicRight.isEstimate.begin(), intrinsicRight.isEstimate.end());
+ selectedParams.insert(selectedParams.end(), tmp.begin(), tmp.end());
+
+ //Init values for rotation and translation between two views
+ cv::Mat om_list(1, n_images, CV_64FC3), T_list(1, n_images, CV_64FC3);
+ cv::Mat om_ref, R_ref, T_ref, R1, R2;
+ for (int image_idx = 0; image_idx < n_images; ++image_idx)
+ {
+ cv::Rodrigues(rvecs1[image_idx], R1);
+ cv::Rodrigues(rvecs2[image_idx], R2);
+ R_ref = R2 * R1.t();
+ T_ref = cv::Mat(tvecs2[image_idx]) - R_ref * cv::Mat(tvecs1[image_idx]);
+ cv::Rodrigues(R_ref, om_ref);
+ om_ref.reshape(3, 1).copyTo(om_list.col(image_idx));
+ T_ref.reshape(3, 1).copyTo(T_list.col(image_idx));
+ }
+ cv::Vec3d omcur = internal::median3d(om_list);
+ cv::Vec3d Tcur = internal::median3d(T_list);
+
+ cv::Mat J = cv::Mat::zeros(4 * n_points * n_images, 18 + 6 * (n_images + 1), CV_64FC1),
+ e = cv::Mat::zeros(4 * n_points * n_images, 1, CV_64FC1), Jkk, ekk;
+ cv::Mat J2_inv;
+
+ for(int iter = 0; ; ++iter)
+ {
+ if ((criteria.type == 1 && iter >= criteria.maxCount) ||
+ (criteria.type == 2 && change <= criteria.epsilon) ||
+ (criteria.type == 3 && (change <= criteria.epsilon || iter >= criteria.maxCount)))
+ break;
+
+ J.create(4 * n_points * n_images, 18 + 6 * (n_images + 1), CV_64FC1);
+ e.create(4 * n_points * n_images, 1, CV_64FC1);
+ Jkk.create(4 * n_points, 18 + 6 * (n_images + 1), CV_64FC1);
+ ekk.create(4 * n_points, 1, CV_64FC1);
+
+ cv::Mat omr, Tr, domrdomckk, domrdTckk, domrdom, domrdT, dTrdomckk, dTrdTckk, dTrdom, dTrdT;
+
+ for (int image_idx = 0; image_idx < n_images; ++image_idx)
+ {
+ Jkk = cv::Mat::zeros(4 * n_points, 18 + 6 * (n_images + 1), CV_64FC1);
+
+ cv::Mat object = objectPoints.getMat(image_idx).clone();
+ cv::Mat imageLeft = imagePoints1.getMat(image_idx).clone();
+ cv::Mat imageRight = imagePoints2.getMat(image_idx).clone();
+ cv::Mat jacobians, projected;
+
+ //left camera jacobian
+ cv::Mat rvec = cv::Mat(rvecs1[image_idx]);
+ cv::Mat tvec = cv::Mat(tvecs1[image_idx]);
+ cv::internal::projectPoints(object, projected, rvec, tvec, intrinsicLeft, jacobians);
+ cv::Mat(cv::Mat((imageLeft - projected).t()).reshape(1, 1).t()).copyTo(ekk.rowRange(0, 2 * n_points));
+ jacobians.colRange(8, 11).copyTo(Jkk.colRange(24 + image_idx * 6, 27 + image_idx * 6).rowRange(0, 2 * n_points));
+ jacobians.colRange(11, 14).copyTo(Jkk.colRange(27 + image_idx * 6, 30 + image_idx * 6).rowRange(0, 2 * n_points));
+ jacobians.colRange(0, 2).copyTo(Jkk.colRange(0, 2).rowRange(0, 2 * n_points));
+ jacobians.colRange(2, 4).copyTo(Jkk.colRange(2, 4).rowRange(0, 2 * n_points));
+ jacobians.colRange(4, 8).copyTo(Jkk.colRange(5, 9).rowRange(0, 2 * n_points));
+ jacobians.col(14).copyTo(Jkk.col(4).rowRange(0, 2 * n_points));
+
+ //right camera jacobian
+ internal::compose_motion(rvec, tvec, omcur, Tcur, omr, Tr, domrdomckk, domrdTckk, domrdom, domrdT, dTrdomckk, dTrdTckk, dTrdom, dTrdT);
+ rvec = cv::Mat(rvecs2[image_idx]);
+ tvec = cv::Mat(tvecs2[image_idx]);
+
+ cv::internal::projectPoints(object, projected, omr, Tr, intrinsicRight, jacobians);
+ cv::Mat(cv::Mat((imageRight - projected).t()).reshape(1, 1).t()).copyTo(ekk.rowRange(2 * n_points, 4 * n_points));
+ cv::Mat dxrdom = jacobians.colRange(8, 11) * domrdom + jacobians.colRange(11, 14) * dTrdom;
+ cv::Mat dxrdT = jacobians.colRange(8, 11) * domrdT + jacobians.colRange(11, 14)* dTrdT;
+ cv::Mat dxrdomckk = jacobians.colRange(8, 11) * domrdomckk + jacobians.colRange(11, 14) * dTrdomckk;
+ cv::Mat dxrdTckk = jacobians.colRange(8, 11) * domrdTckk + jacobians.colRange(11, 14) * dTrdTckk;
+
+ dxrdom.copyTo(Jkk.colRange(18, 21).rowRange(2 * n_points, 4 * n_points));
+ dxrdT.copyTo(Jkk.colRange(21, 24).rowRange(2 * n_points, 4 * n_points));
+ dxrdomckk.copyTo(Jkk.colRange(24 + image_idx * 6, 27 + image_idx * 6).rowRange(2 * n_points, 4 * n_points));
+ dxrdTckk.copyTo(Jkk.colRange(27 + image_idx * 6, 30 + image_idx * 6).rowRange(2 * n_points, 4 * n_points));
+ jacobians.colRange(0, 2).copyTo(Jkk.colRange(9 + 0, 9 + 2).rowRange(2 * n_points, 4 * n_points));
+ jacobians.colRange(2, 4).copyTo(Jkk.colRange(9 + 2, 9 + 4).rowRange(2 * n_points, 4 * n_points));
+ jacobians.colRange(4, 8).copyTo(Jkk.colRange(9 + 5, 9 + 9).rowRange(2 * n_points, 4 * n_points));
+ jacobians.col(14).copyTo(Jkk.col(9 + 4).rowRange(2 * n_points, 4 * n_points));
+
+ //check goodness of sterepair
+ double abs_max = 0;
+ for (int i = 0; i < 4 * n_points; i++)
+ {
+ if (fabs(ekk.at<double>(i)) > abs_max)
+ {
+ abs_max = fabs(ekk.at<double>(i));
+ }
+ }
+
+ CV_Assert(abs_max < threshold); // bad stereo pair
+
+ Jkk.copyTo(J.rowRange(image_idx * 4 * n_points, (image_idx + 1) * 4 * n_points));
+ ekk.copyTo(e.rowRange(image_idx * 4 * n_points, (image_idx + 1) * 4 * n_points));
+ }
+
+ cv::Vec6d oldTom(Tcur[0], Tcur[1], Tcur[2], omcur[0], omcur[1], omcur[2]);
+
+ //update all parameters
+ cv::subMatrix(J, J, selectedParams, std::vector<int>(J.rows, 1));
+ cv::Mat J2 = J.t() * J;
+ J2_inv = J2.inv();
+ int a = cv::countNonZero(intrinsicLeft.isEstimate);
+ int b = cv::countNonZero(intrinsicRight.isEstimate);
+ cv::Mat deltas = J2_inv * J.t() * e;
+ intrinsicLeft = intrinsicLeft + deltas.rowRange(0, a);
+ intrinsicRight = intrinsicRight + deltas.rowRange(a, a + b);
+ omcur = omcur + cv::Vec3d(deltas.rowRange(a + b, a + b + 3));
+ Tcur = Tcur + cv::Vec3d(deltas.rowRange(a + b + 3, a + b + 6));
+ for (int image_idx = 0; image_idx < n_images; ++image_idx)
+ {
+ rvecs1[image_idx] = cv::Mat(cv::Mat(rvecs1[image_idx]) + deltas.rowRange(a + b + 6 + image_idx * 6, a + b + 9 + image_idx * 6));
+ tvecs1[image_idx] = cv::Mat(cv::Mat(tvecs1[image_idx]) + deltas.rowRange(a + b + 9 + image_idx * 6, a + b + 12 + image_idx * 6));
+ }
+
+ cv::Vec6d newTom(Tcur[0], Tcur[1], Tcur[2], omcur[0], omcur[1], omcur[2]);
+ change = cv::norm(newTom - oldTom) / cv::norm(newTom);
+ }
+
+ double rms = 0;
+ const Vec2d* ptr_e = e.ptr<Vec2d>();
+ for (size_t i = 0; i < e.total() / 2; i++)
+ {
+ rms += ptr_e[i][0] * ptr_e[i][0] + ptr_e[i][1] * ptr_e[i][1];
+ }
+
+ rms /= ((double)e.total() / 2.0);
+ rms = sqrt(rms);
+
+ _K1 = Matx33d(intrinsicLeft.f[0], intrinsicLeft.f[0] * intrinsicLeft.alpha, intrinsicLeft.c[0],
+ 0, intrinsicLeft.f[1], intrinsicLeft.c[1],
+ 0, 0, 1);
+
+ _K2 = Matx33d(intrinsicRight.f[0], intrinsicRight.f[0] * intrinsicRight.alpha, intrinsicRight.c[0],
+ 0, intrinsicRight.f[1], intrinsicRight.c[1],
+ 0, 0, 1);
+
+ Mat _R;
+ Rodrigues(omcur, _R);
+
+ if (K1.needed()) cv::Mat(_K1).convertTo(K1, K1.empty() ? CV_64FC1 : K1.type());
+ if (K2.needed()) cv::Mat(_K2).convertTo(K2, K2.empty() ? CV_64FC1 : K2.type());
+ if (D1.needed()) cv::Mat(intrinsicLeft.k).convertTo(D1, D1.empty() ? CV_64FC1 : D1.type());
+ if (D2.needed()) cv::Mat(intrinsicRight.k).convertTo(D2, D2.empty() ? CV_64FC1 : D2.type());
+ if (R.needed()) _R.convertTo(R, R.empty() ? CV_64FC1 : R.type());
+ if (T.needed()) cv::Mat(Tcur).convertTo(T, T.empty() ? CV_64FC1 : T.type());
+
+ return rms;
+ }
+
+ namespace cv{ namespace {
- calcCovarMatrix(objectPoints, covObjectPoints, objectPointsMean, CV_COVAR_NORMAL | CV_COVAR_COLS);
++void subMatrix(const Mat& src, Mat& dst, const std::vector<int>& cols, const std::vector<int>& rows)
+ {
+ CV_Assert(src.type() == CV_64FC1);
+
+ int nonzeros_cols = cv::countNonZero(cols);
+ Mat tmp(src.rows, nonzeros_cols, CV_64FC1);
+
+ for (int i = 0, j = 0; i < (int)cols.size(); i++)
+ {
+ if (cols[i])
+ {
+ src.col(i).copyTo(tmp.col(j++));
+ }
+ }
+
+ int nonzeros_rows = cv::countNonZero(rows);
+ Mat tmp1(nonzeros_rows, nonzeros_cols, CV_64FC1);
+ for (int i = 0, j = 0; i < (int)rows.size(); i++)
+ {
+ if (rows[i])
+ {
+ tmp.row(i).copyTo(tmp1.row(j++));
+ }
+ }
+
+ dst = tmp1.clone();
+ }
+
+ }}
+
+ cv::internal::IntrinsicParams::IntrinsicParams():
+ f(Vec2d::all(0)), c(Vec2d::all(0)), k(Vec4d::all(0)), alpha(0), isEstimate(9,0)
+ {
+ }
+
+ cv::internal::IntrinsicParams::IntrinsicParams(Vec2d _f, Vec2d _c, Vec4d _k, double _alpha):
+ f(_f), c(_c), k(_k), alpha(_alpha), isEstimate(9,0)
+ {
+ }
+
+ cv::internal::IntrinsicParams cv::internal::IntrinsicParams::operator+(const Mat& a)
+ {
+ CV_Assert(a.type() == CV_64FC1);
+ IntrinsicParams tmp;
+ const double* ptr = a.ptr<double>();
+
+ int j = 0;
+ tmp.f[0] = this->f[0] + (isEstimate[0] ? ptr[j++] : 0);
+ tmp.f[1] = this->f[1] + (isEstimate[1] ? ptr[j++] : 0);
+ tmp.c[0] = this->c[0] + (isEstimate[2] ? ptr[j++] : 0);
+ tmp.alpha = this->alpha + (isEstimate[4] ? ptr[j++] : 0);
+ tmp.c[1] = this->c[1] + (isEstimate[3] ? ptr[j++] : 0);
+ tmp.k[0] = this->k[0] + (isEstimate[5] ? ptr[j++] : 0);
+ tmp.k[1] = this->k[1] + (isEstimate[6] ? ptr[j++] : 0);
+ tmp.k[2] = this->k[2] + (isEstimate[7] ? ptr[j++] : 0);
+ tmp.k[3] = this->k[3] + (isEstimate[8] ? ptr[j++] : 0);
+
+ tmp.isEstimate = isEstimate;
+ return tmp;
+ }
+
+ cv::internal::IntrinsicParams& cv::internal::IntrinsicParams::operator =(const Mat& a)
+ {
+ CV_Assert(a.type() == CV_64FC1);
+ const double* ptr = a.ptr<double>();
+
+ int j = 0;
+
+ this->f[0] = isEstimate[0] ? ptr[j++] : 0;
+ this->f[1] = isEstimate[1] ? ptr[j++] : 0;
+ this->c[0] = isEstimate[2] ? ptr[j++] : 0;
+ this->c[1] = isEstimate[3] ? ptr[j++] : 0;
+ this->alpha = isEstimate[4] ? ptr[j++] : 0;
+ this->k[0] = isEstimate[5] ? ptr[j++] : 0;
+ this->k[1] = isEstimate[6] ? ptr[j++] : 0;
+ this->k[2] = isEstimate[7] ? ptr[j++] : 0;
+ this->k[3] = isEstimate[8] ? ptr[j++] : 0;
+
+ return *this;
+ }
+
+ void cv::internal::IntrinsicParams::Init(const cv::Vec2d& _f, const cv::Vec2d& _c, const cv::Vec4d& _k, const double& _alpha)
+ {
+ this->c = _c;
+ this->f = _f;
+ this->k = _k;
+ this->alpha = _alpha;
+ }
+
+ void cv::internal::projectPoints(cv::InputArray objectPoints, cv::OutputArray imagePoints,
+ cv::InputArray _rvec,cv::InputArray _tvec,
+ const IntrinsicParams& param, cv::OutputArray jacobian)
+ {
+ CV_Assert(!objectPoints.empty() && objectPoints.type() == CV_64FC3);
+ Matx33d K(param.f[0], param.f[0] * param.alpha, param.c[0],
+ 0, param.f[1], param.c[1],
+ 0, 0, 1);
+ fisheye::projectPoints(objectPoints, imagePoints, _rvec, _tvec, K, param.k, param.alpha, jacobian);
+ }
+
+ void cv::internal::ComputeExtrinsicRefine(const Mat& imagePoints, const Mat& objectPoints, Mat& rvec,
+ Mat& tvec, Mat& J, const int MaxIter,
+ const IntrinsicParams& param, const double thresh_cond)
+ {
+ CV_Assert(!objectPoints.empty() && objectPoints.type() == CV_64FC3);
+ CV_Assert(!imagePoints.empty() && imagePoints.type() == CV_64FC2);
+ Vec6d extrinsics(rvec.at<double>(0), rvec.at<double>(1), rvec.at<double>(2),
+ tvec.at<double>(0), tvec.at<double>(1), tvec.at<double>(2));
+ double change = 1;
+ int iter = 0;
+
+ while (change > 1e-10 && iter < MaxIter)
+ {
+ std::vector<Point2d> x;
+ Mat jacobians;
+ projectPoints(objectPoints, x, rvec, tvec, param, jacobians);
+
+ Mat ex = imagePoints - Mat(x).t();
+ ex = ex.reshape(1, 2);
+
+ J = jacobians.colRange(8, 14).clone();
+
+ SVD svd(J, SVD::NO_UV);
+ double condJJ = svd.w.at<double>(0)/svd.w.at<double>(5);
+
+ if (condJJ > thresh_cond)
+ change = 0;
+ else
+ {
+ Vec6d param_innov;
+ solve(J, ex.reshape(1, (int)ex.total()), param_innov, DECOMP_SVD + DECOMP_NORMAL);
+
+ Vec6d param_up = extrinsics + param_innov;
+ change = norm(param_innov)/norm(param_up);
+ extrinsics = param_up;
+ iter = iter + 1;
+
+ rvec = Mat(Vec3d(extrinsics.val));
+ tvec = Mat(Vec3d(extrinsics.val+3));
+ }
+ }
+ }
+
+ cv::Mat cv::internal::ComputeHomography(Mat m, Mat M)
+ {
+ int Np = m.cols;
+
+ if (m.rows < 3)
+ {
+ vconcat(m, Mat::ones(1, Np, CV_64FC1), m);
+ }
+ if (M.rows < 3)
+ {
+ vconcat(M, Mat::ones(1, Np, CV_64FC1), M);
+ }
+
+ divide(m, Mat::ones(3, 1, CV_64FC1) * m.row(2), m);
+ divide(M, Mat::ones(3, 1, CV_64FC1) * M.row(2), M);
+
+ Mat ax = m.row(0).clone();
+ Mat ay = m.row(1).clone();
+
+ double mxx = mean(ax)[0];
+ double myy = mean(ay)[0];
+
+ ax = ax - mxx;
+ ay = ay - myy;
+
+ double scxx = mean(abs(ax))[0];
+ double scyy = mean(abs(ay))[0];
+
+ Mat Hnorm (Matx33d( 1/scxx, 0.0, -mxx/scxx,
+ 0.0, 1/scyy, -myy/scyy,
+ 0.0, 0.0, 1.0 ));
+
+ Mat inv_Hnorm (Matx33d( scxx, 0, mxx,
+ 0, scyy, myy,
+ 0, 0, 1 ));
+ Mat mn = Hnorm * m;
+
+ Mat L = Mat::zeros(2*Np, 9, CV_64FC1);
+
+ for (int i = 0; i < Np; ++i)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ L.at<double>(2 * i, j) = M.at<double>(j, i);
+ L.at<double>(2 * i + 1, j + 3) = M.at<double>(j, i);
+ L.at<double>(2 * i, j + 6) = -mn.at<double>(0,i) * M.at<double>(j, i);
+ L.at<double>(2 * i + 1, j + 6) = -mn.at<double>(1,i) * M.at<double>(j, i);
+ }
+ }
+
+ if (Np > 4) L = L.t() * L;
+ SVD svd(L);
+ Mat hh = svd.vt.row(8) / svd.vt.row(8).at<double>(8);
+ Mat Hrem = hh.reshape(1, 3);
+ Mat H = inv_Hnorm * Hrem;
+
+ if (Np > 4)
+ {
+ Mat hhv = H.reshape(1, 9)(Rect(0, 0, 1, 8)).clone();
+ for (int iter = 0; iter < 10; iter++)
+ {
+ Mat mrep = H * M;
+ Mat J = Mat::zeros(2 * Np, 8, CV_64FC1);
+ Mat MMM;
+ divide(M, Mat::ones(3, 1, CV_64FC1) * mrep(Rect(0, 2, mrep.cols, 1)), MMM);
+ divide(mrep, Mat::ones(3, 1, CV_64FC1) * mrep(Rect(0, 2, mrep.cols, 1)), mrep);
+ Mat m_err = m(Rect(0,0, m.cols, 2)) - mrep(Rect(0,0, mrep.cols, 2));
+ m_err = Mat(m_err.t()).reshape(1, m_err.cols * m_err.rows);
+ Mat MMM2, MMM3;
+ multiply(Mat::ones(3, 1, CV_64FC1) * mrep(Rect(0, 0, mrep.cols, 1)), MMM, MMM2);
+ multiply(Mat::ones(3, 1, CV_64FC1) * mrep(Rect(0, 1, mrep.cols, 1)), MMM, MMM3);
+
+ for (int i = 0; i < Np; ++i)
+ {
+ for (int j = 0; j < 3; ++j)
+ {
+ J.at<double>(2 * i, j) = -MMM.at<double>(j, i);
+ J.at<double>(2 * i + 1, j + 3) = -MMM.at<double>(j, i);
+ }
+
+ for (int j = 0; j < 2; ++j)
+ {
+ J.at<double>(2 * i, j + 6) = MMM2.at<double>(j, i);
+ J.at<double>(2 * i + 1, j + 6) = MMM3.at<double>(j, i);
+ }
+ }
+ divide(M, Mat::ones(3, 1, CV_64FC1) * mrep(Rect(0,2,mrep.cols,1)), MMM);
+ Mat hh_innov = (J.t() * J).inv() * (J.t()) * m_err;
+ Mat hhv_up = hhv - hh_innov;
+ Mat tmp;
+ vconcat(hhv_up, Mat::ones(1,1,CV_64FC1), tmp);
+ Mat H_up = tmp.reshape(1,3);
+ hhv = hhv_up;
+ H = H_up;
+ }
+ }
+ return H;
+ }
+
+ cv::Mat cv::internal::NormalizePixels(const Mat& imagePoints, const IntrinsicParams& param)
+ {
+ CV_Assert(!imagePoints.empty() && imagePoints.type() == CV_64FC2);
+
+ Mat distorted((int)imagePoints.total(), 1, CV_64FC2), undistorted;
+ const Vec2d* ptr = imagePoints.ptr<Vec2d>(0);
+ Vec2d* ptr_d = distorted.ptr<Vec2d>(0);
+ for (size_t i = 0; i < imagePoints.total(); ++i)
+ {
+ ptr_d[i] = (ptr[i] - param.c).mul(Vec2d(1.0 / param.f[0], 1.0 / param.f[1]));
+ ptr_d[i][0] = ptr_d[i][0] - param.alpha * ptr_d[i][1];
+ }
+ cv::fisheye::undistortPoints(distorted, undistorted, Matx33d::eye(), param.k);
+ return undistorted;
+ }
+
+ void cv::internal::InitExtrinsics(const Mat& _imagePoints, const Mat& _objectPoints, const IntrinsicParams& param, Mat& omckk, Mat& Tckk)
+ {
+
+ CV_Assert(!_objectPoints.empty() && _objectPoints.type() == CV_64FC3);
+ CV_Assert(!_imagePoints.empty() && _imagePoints.type() == CV_64FC2);
+
+ Mat imagePointsNormalized = NormalizePixels(_imagePoints.t(), param).reshape(1).t();
+ Mat objectPoints = Mat(_objectPoints.t()).reshape(1).t();
+ Mat objectPointsMean, covObjectPoints;
+ Mat Rckk;
+ int Np = imagePointsNormalized.cols;
- vector<int> idxs(param.isEstimate);
++ calcCovarMatrix(objectPoints, covObjectPoints, objectPointsMean, COVAR_NORMAL | COVAR_COLS);
+ SVD svd(covObjectPoints);
+ Mat R(svd.vt);
+ if (norm(R(Rect(2, 0, 1, 2))) < 1e-6)
+ R = Mat::eye(3,3, CV_64FC1);
+ if (determinant(R) < 0)
+ R = -R;
+ Mat T = -R * objectPointsMean;
+ Mat X_new = R * objectPoints + T * Mat::ones(1, Np, CV_64FC1);
+ Mat H = ComputeHomography(imagePointsNormalized, X_new(Rect(0,0,X_new.cols,2)));
+ double sc = .5 * (norm(H.col(0)) + norm(H.col(1)));
+ H = H / sc;
+ Mat u1 = H.col(0).clone();
+ u1 = u1 / norm(u1);
+ Mat u2 = H.col(1).clone() - u1.dot(H.col(1).clone()) * u1;
+ u2 = u2 / norm(u2);
+ Mat u3 = u1.cross(u2);
+ Mat RRR;
+ hconcat(u1, u2, RRR);
+ hconcat(RRR, u3, RRR);
+ Rodrigues(RRR, omckk);
+ Rodrigues(omckk, Rckk);
+ Tckk = H.col(2).clone();
+ Tckk = Tckk + Rckk * T;
+ Rckk = Rckk * R;
+ Rodrigues(Rckk, omckk);
+ }
+
+ void cv::internal::CalibrateExtrinsics(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints,
+ const IntrinsicParams& param, const int check_cond,
+ const double thresh_cond, InputOutputArray omc, InputOutputArray Tc)
+ {
+ CV_Assert(!objectPoints.empty() && (objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3));
+ CV_Assert(!imagePoints.empty() && (imagePoints.type() == CV_32FC2 || imagePoints.type() == CV_64FC2));
+ CV_Assert(omc.type() == CV_64FC3 || Tc.type() == CV_64FC3);
+
+ if (omc.empty()) omc.create(1, (int)objectPoints.total(), CV_64FC3);
+ if (Tc.empty()) Tc.create(1, (int)objectPoints.total(), CV_64FC3);
+
+ const int maxIter = 20;
+
+ for(int image_idx = 0; image_idx < (int)imagePoints.total(); ++image_idx)
+ {
+ Mat omckk, Tckk, JJ_kk;
+ Mat image, object;
+
+ objectPoints.getMat(image_idx).convertTo(object, CV_64FC3);
+ imagePoints.getMat (image_idx).convertTo(image, CV_64FC2);
+
+ InitExtrinsics(image, object, param, omckk, Tckk);
+
+ ComputeExtrinsicRefine(image, object, omckk, Tckk, JJ_kk, maxIter, param, thresh_cond);
+ if (check_cond)
+ {
+ SVD svd(JJ_kk, SVD::NO_UV);
+ CV_Assert(svd.w.at<double>(0) / svd.w.at<double>((int)svd.w.total() - 1) < thresh_cond);
+ }
+ omckk.reshape(3,1).copyTo(omc.getMat().col(image_idx));
+ Tckk.reshape(3,1).copyTo(Tc.getMat().col(image_idx));
+ }
+ }
+
+
+ void cv::internal::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_Assert(!objectPoints.empty() && (objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3));
+ CV_Assert(!imagePoints.empty() && (imagePoints.type() == CV_32FC2 || imagePoints.type() == CV_64FC2));
+
+ CV_Assert(!omc.empty() && omc.type() == CV_64FC3);
+ CV_Assert(!Tc.empty() && Tc.type() == CV_64FC3);
+
+ int n = (int)objectPoints.total();
+
+ Mat JJ3 = Mat::zeros(9 + 6 * n, 9 + 6 * n, CV_64FC1);
+ ex3 = Mat::zeros(9 + 6 * n, 1, CV_64FC1 );
+
+ for (int image_idx = 0; image_idx < n; ++image_idx)
+ {
+ Mat image, object;
+ objectPoints.getMat(image_idx).convertTo(object, CV_64FC3);
+ imagePoints.getMat (image_idx).convertTo(image, CV_64FC2);
+
+ Mat om(omc.getMat().col(image_idx)), T(Tc.getMat().col(image_idx));
+
+ std::vector<Point2d> x;
+ Mat jacobians;
+ projectPoints(object, x, om, T, param, jacobians);
+ Mat exkk = image.t() - Mat(x);
+
+ Mat A(jacobians.rows, 9, CV_64FC1);
+ jacobians.colRange(0, 4).copyTo(A.colRange(0, 4));
+ jacobians.col(14).copyTo(A.col(4));
+ jacobians.colRange(4, 8).copyTo(A.colRange(5, 9));
+
+ A = A.t();
+
+ Mat B = jacobians.colRange(8, 14).clone();
+ B = B.t();
+
+ JJ3(Rect(0, 0, 9, 9)) = JJ3(Rect(0, 0, 9, 9)) + A * A.t();
+ JJ3(Rect(9 + 6 * image_idx, 9 + 6 * image_idx, 6, 6)) = B * B.t();
+
+ Mat AB = A * B.t();
+ AB.copyTo(JJ3(Rect(9 + 6 * image_idx, 0, 6, 9)));
+
+ JJ3(Rect(0, 9 + 6 * image_idx, 9, 6)) = AB.t();
+ ex3(Rect(0,0,1,9)) = ex3(Rect(0,0,1,9)) + A * exkk.reshape(1, 2 * exkk.rows);
+
+ ex3(Rect(0, 9 + 6 * image_idx, 1, 6)) = B * exkk.reshape(1, 2 * exkk.rows);
+
+ if (check_cond)
+ {
+ Mat JJ_kk = B.t();
+ SVD svd(JJ_kk, SVD::NO_UV);
+ CV_Assert(svd.w.at<double>(0) / svd.w.at<double>(svd.w.rows - 1) < thresh_cond);
+ }
+ }
+
++ std::vector<int> idxs(param.isEstimate);
+ idxs.insert(idxs.end(), 6 * n, 1);
+
+ subMatrix(JJ3, JJ3, idxs, idxs);
+ subMatrix(ex3, ex3, std::vector<int>(1, 1), idxs);
+ JJ2_inv = JJ3.inv();
+ }
+
+ void cv::internal::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)
+ {
+ CV_Assert(!objectPoints.empty() && (objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3));
+ CV_Assert(!imagePoints.empty() && (imagePoints.type() == CV_32FC2 || imagePoints.type() == CV_64FC2));
+
+ CV_Assert(!omc.empty() && omc.type() == CV_64FC3);
+ CV_Assert(!Tc.empty() && Tc.type() == CV_64FC3);
+
+ Mat ex((int)(objectPoints.getMat(0).total() * objectPoints.total()), 1, CV_64FC2);
+
+ for (int image_idx = 0; image_idx < (int)objectPoints.total(); ++image_idx)
+ {
+ Mat image, object;
+ objectPoints.getMat(image_idx).convertTo(object, CV_64FC3);
+ imagePoints.getMat (image_idx).convertTo(image, CV_64FC2);
+
+ Mat om(omc.getMat().col(image_idx)), T(Tc.getMat().col(image_idx));
+
+ std::vector<Point2d> x;
+ projectPoints(object, x, om, T, params, noArray());
+ Mat ex_ = image.t() - Mat(x);
+ ex_.copyTo(ex.rowRange(ex_.rows * image_idx, ex_.rows * (image_idx + 1)));
+ }
+
+ meanStdDev(ex, noArray(), std_err);
+ std_err *= sqrt((double)ex.total()/((double)ex.total() - 1.0));
+
+ Mat sigma_x;
+ meanStdDev(ex.reshape(1, 1), noArray(), sigma_x);
+ sigma_x *= sqrt(2.0 * (double)ex.total()/(2.0 * (double)ex.total() - 1.0));
+
+ Mat _JJ2_inv, ex3;
+ ComputeJacobians(objectPoints, imagePoints, params, omc, Tc, check_cond, thresh_cond, _JJ2_inv, ex3);
+
+ Mat_<double>& JJ2_inv = (Mat_<double>&)_JJ2_inv;
+
+ sqrt(JJ2_inv, JJ2_inv);
+
+ double s = sigma_x.at<double>(0);
+ Mat r = 3 * s * JJ2_inv.diag();
+ errors = r;
+
+ rms = 0;
+ const Vec2d* ptr_ex = ex.ptr<Vec2d>();
+ for (size_t i = 0; i < ex.total(); i++)
+ {
+ rms += ptr_ex[i][0] * ptr_ex[i][0] + ptr_ex[i][1] * ptr_ex[i][1];
+ }
+
+ rms /= (double)ex.total();
+ rms = sqrt(rms);
+ }
+
+ void cv::internal::dAB(InputArray A, InputArray B, OutputArray dABdA, OutputArray dABdB)
+ {
+ CV_Assert(A.getMat().cols == B.getMat().rows);
+ CV_Assert(A.type() == CV_64FC1 && B.type() == CV_64FC1);
+
+ int p = A.getMat().rows;
+ int n = A.getMat().cols;
+ int q = B.getMat().cols;
+
+ dABdA.create(p * q, p * n, CV_64FC1);
+ dABdB.create(p * q, q * n, CV_64FC1);
+
+ dABdA.getMat() = Mat::zeros(p * q, p * n, CV_64FC1);
+ dABdB.getMat() = Mat::zeros(p * q, q * n, CV_64FC1);
+
+ for (int i = 0; i < q; ++i)
+ {
+ for (int j = 0; j < p; ++j)
+ {
+ int ij = j + i * p;
+ for (int k = 0; k < n; ++k)
+ {
+ int kj = j + k * p;
+ dABdA.getMat().at<double>(ij, kj) = B.getMat().at<double>(k, i);
+ }
+ }
+ }
+
+ for (int i = 0; i < q; ++i)
+ {
+ A.getMat().copyTo(dABdB.getMat().rowRange(i * p, i * p + p).colRange(i * n, i * n + n));
+ }
+ }
+
+ void cv::internal::JRodriguesMatlab(const Mat& src, Mat& dst)
+ {
+ Mat tmp(src.cols, src.rows, src.type());
+ if (src.rows == 9)
+ {
+ Mat(src.row(0).t()).copyTo(tmp.col(0));
+ Mat(src.row(1).t()).copyTo(tmp.col(3));
+ Mat(src.row(2).t()).copyTo(tmp.col(6));
+ Mat(src.row(3).t()).copyTo(tmp.col(1));
+ Mat(src.row(4).t()).copyTo(tmp.col(4));
+ Mat(src.row(5).t()).copyTo(tmp.col(7));
+ Mat(src.row(6).t()).copyTo(tmp.col(2));
+ Mat(src.row(7).t()).copyTo(tmp.col(5));
+ Mat(src.row(8).t()).copyTo(tmp.col(8));
+ }
+ else
+ {
+ Mat(src.col(0).t()).copyTo(tmp.row(0));
+ Mat(src.col(1).t()).copyTo(tmp.row(3));
+ Mat(src.col(2).t()).copyTo(tmp.row(6));
+ Mat(src.col(3).t()).copyTo(tmp.row(1));
+ Mat(src.col(4).t()).copyTo(tmp.row(4));
+ Mat(src.col(5).t()).copyTo(tmp.row(7));
+ Mat(src.col(6).t()).copyTo(tmp.row(2));
+ Mat(src.col(7).t()).copyTo(tmp.row(5));
+ Mat(src.col(8).t()).copyTo(tmp.row(8));
+ }
+ dst = tmp.clone();
+ }
+
+ void cv::internal::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)
+ {
+ Mat om1 = _om1.getMat();
+ Mat om2 = _om2.getMat();
+ Mat T1 = _T1.getMat().reshape(1, 3);
+ Mat T2 = _T2.getMat().reshape(1, 3);
+
+ //% Rotations:
+ Mat R1, R2, R3, dR1dom1(9, 3, CV_64FC1), dR2dom2;
+ Rodrigues(om1, R1, dR1dom1);
+ Rodrigues(om2, R2, dR2dom2);
+ JRodriguesMatlab(dR1dom1, dR1dom1);
+ JRodriguesMatlab(dR2dom2, dR2dom2);
+ R3 = R2 * R1;
+ Mat dR3dR2, dR3dR1;
+ dAB(R2, R1, dR3dR2, dR3dR1);
+ Mat dom3dR3;
+ Rodrigues(R3, om3, dom3dR3);
+ JRodriguesMatlab(dom3dR3, dom3dR3);
+ dom3dom1 = dom3dR3 * dR3dR1 * dR1dom1;
+ dom3dom2 = dom3dR3 * dR3dR2 * dR2dom2;
+ dom3dT1 = Mat::zeros(3, 3, CV_64FC1);
+ dom3dT2 = Mat::zeros(3, 3, CV_64FC1);
+
+ //% Translations:
+ Mat T3t = R2 * T1;
+ Mat dT3tdR2, dT3tdT1;
+ dAB(R2, T1, dT3tdR2, dT3tdT1);
+ Mat dT3tdom2 = dT3tdR2 * dR2dom2;
+ T3 = T3t + T2;
+ dT3dT1 = dT3tdT1;
+ dT3dT2 = Mat::eye(3, 3, CV_64FC1);
+ dT3dom2 = dT3tdom2;
+ dT3dom1 = Mat::zeros(3, 3, CV_64FC1);
+ }
+
+ double cv::internal::median(const Mat& row)
+ {
+ CV_Assert(row.type() == CV_64FC1);
+ CV_Assert(!row.empty() && row.rows == 1);
+ Mat tmp = row.clone();
+ sort(tmp, tmp, 0);
+ if ((int)tmp.total() % 2) return tmp.at<double>((int)tmp.total() / 2);
+ else return 0.5 *(tmp.at<double>((int)tmp.total() / 2) + tmp.at<double>((int)tmp.total() / 2 - 1));
+ }
+
+ cv::Vec3d cv::internal::median3d(InputArray m)
+ {
+ CV_Assert(m.depth() == CV_64F && m.getMat().rows == 1);
+ Mat M = Mat(m.getMat().t()).reshape(1).t();
+ return Vec3d(median(M.row(0)), median(M.row(1)), median(M.row(2)));
+ }
--- /dev/null
-#include <opencv2/ts/gpu_test.hpp>
+ /*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"
- datasets_repository_path = combine(cvtest::TS::ptr()->get_data_path(), "cameracalibration/fisheye");
++#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() {
- cv::calcCovarMatrix(_objectPoints, covObjectPoints, objectPointsMean, CV_COVAR_NORMAL | CV_COVAR_COLS);
++ 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, 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::rectangle(l, cv::Rect(255, 0, 829, l.rows-1), CV_RGB(255, 0, 0));
- cv::rectangle(r, cv::Rect(255, 0, 829, l.rows-1), CV_RGB(255, 0, 0));
- cv::rectangle(r, cv::Rect(255-ndisp, 0, 829+ndisp ,l.rows-1), CV_RGB(255, 0, 0));
++ 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::line(merged, cv::Point(0, i), cv::Point(merged.cols, i), CV_RGB(0, 255, 0));
++ 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;
+ }
--- /dev/null
- size.p[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, 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*/
+
+#ifndef __OPENCV_CORE_MATRIX_OPERATIONS_HPP__
+#define __OPENCV_CORE_MATRIX_OPERATIONS_HPP__
+
+#ifndef __cplusplus
+# error mat.inl.hpp header must be compiled as C++
+#endif
+
+namespace cv
+{
+
+//////////////////////// Input/Output Arrays ////////////////////////
+
+inline void _InputArray::init(int _flags, const void* _obj)
+{ flags = _flags; obj = (void*)_obj; }
+
+inline void _InputArray::init(int _flags, const void* _obj, Size _sz)
+{ flags = _flags; obj = (void*)_obj; sz = _sz; }
+
+inline void* _InputArray::getObj() const { return obj; }
+
+inline _InputArray::_InputArray() { init(NONE, 0); }
+inline _InputArray::_InputArray(int _flags, void* _obj) { init(_flags, _obj); }
+inline _InputArray::_InputArray(const Mat& m) { init(MAT+ACCESS_READ, &m); }
+inline _InputArray::_InputArray(const std::vector<Mat>& vec) { init(STD_VECTOR_MAT+ACCESS_READ, &vec); }
+inline _InputArray::_InputArray(const UMat& m) { init(UMAT+ACCESS_READ, &m); }
+inline _InputArray::_InputArray(const std::vector<UMat>& vec) { init(STD_VECTOR_UMAT+ACCESS_READ, &vec); }
+
+template<typename _Tp> inline
+_InputArray::_InputArray(const std::vector<_Tp>& vec)
+{ init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); }
+
+template<typename _Tp> inline
+_InputArray::_InputArray(const std::vector<std::vector<_Tp> >& vec)
+{ init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); }
+
+template<typename _Tp> inline
+_InputArray::_InputArray(const std::vector<Mat_<_Tp> >& vec)
+{ init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_READ, &vec); }
+
+template<typename _Tp, int m, int n> inline
+_InputArray::_InputArray(const Matx<_Tp, m, n>& mtx)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_READ, &mtx, Size(n, m)); }
+
+template<typename _Tp> inline
+_InputArray::_InputArray(const _Tp* vec, int n)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_READ, vec, Size(n, 1)); }
+
+template<typename _Tp> inline
+_InputArray::_InputArray(const Mat_<_Tp>& m)
+{ init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_READ, &m); }
+
+inline _InputArray::_InputArray(const double& val)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + CV_64F + ACCESS_READ, &val, Size(1,1)); }
+
+inline _InputArray::_InputArray(const MatExpr& expr)
+{ init(FIXED_TYPE + FIXED_SIZE + EXPR + ACCESS_READ, &expr); }
+
+inline _InputArray::_InputArray(const cuda::GpuMat& d_mat)
+{ init(GPU_MAT + ACCESS_READ, &d_mat); }
+
+inline _InputArray::_InputArray(const ogl::Buffer& buf)
+{ init(OPENGL_BUFFER + ACCESS_READ, &buf); }
+
+inline _InputArray::_InputArray(const cuda::CudaMem& cuda_mem)
+{ init(CUDA_MEM + ACCESS_READ, &cuda_mem); }
+
+inline _InputArray::~_InputArray() {}
+
+inline bool _InputArray::isMat() const { return kind() == _InputArray::MAT; }
+inline bool _InputArray::isUMat() const { return kind() == _InputArray::UMAT; }
+inline bool _InputArray::isMatVector() const { return kind() == _InputArray::STD_VECTOR_MAT; }
+inline bool _InputArray::isUMatVector() const { return kind() == _InputArray::STD_VECTOR_UMAT; }
+inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; }
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+inline _OutputArray::_OutputArray() { init(ACCESS_WRITE, 0); }
+inline _OutputArray::_OutputArray(int _flags, void* _obj) { init(_flags|ACCESS_WRITE, _obj); }
+inline _OutputArray::_OutputArray(Mat& m) { init(MAT+ACCESS_WRITE, &m); }
+inline _OutputArray::_OutputArray(std::vector<Mat>& vec) { init(STD_VECTOR_MAT+ACCESS_WRITE, &vec); }
+inline _OutputArray::_OutputArray(UMat& m) { init(UMAT+ACCESS_WRITE, &m); }
+inline _OutputArray::_OutputArray(std::vector<UMat>& vec) { init(STD_VECTOR_UMAT+ACCESS_WRITE, &vec); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(std::vector<_Tp>& vec)
+{ init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(std::vector<std::vector<_Tp> >& vec)
+{ init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(std::vector<Mat_<_Tp> >& vec)
+{ init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_WRITE, &vec); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(Mat_<_Tp>& m)
+{ init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_WRITE, &m); }
+
+template<typename _Tp, int m, int n> inline
+_OutputArray::_OutputArray(Matx<_Tp, m, n>& mtx)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, &mtx, Size(n, m)); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(_Tp* vec, int n)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, vec, Size(n, 1)); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(const std::vector<_Tp>& vec)
+{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(const std::vector<std::vector<_Tp> >& vec)
+{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(const std::vector<Mat_<_Tp> >& vec)
+{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_WRITE, &vec); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(const Mat_<_Tp>& m)
+{ init(FIXED_TYPE + FIXED_SIZE + MAT + DataType<_Tp>::type + ACCESS_WRITE, &m); }
+
+template<typename _Tp, int m, int n> inline
+_OutputArray::_OutputArray(const Matx<_Tp, m, n>& mtx)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, &mtx, Size(n, m)); }
+
+template<typename _Tp> inline
+_OutputArray::_OutputArray(const _Tp* vec, int n)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, vec, Size(n, 1)); }
+
+inline _OutputArray::_OutputArray(cuda::GpuMat& d_mat)
+{ init(GPU_MAT + ACCESS_WRITE, &d_mat); }
+
+inline _OutputArray::_OutputArray(ogl::Buffer& buf)
+{ init(OPENGL_BUFFER + ACCESS_WRITE, &buf); }
+
+inline _OutputArray::_OutputArray(cuda::CudaMem& cuda_mem)
+{ init(CUDA_MEM + ACCESS_WRITE, &cuda_mem); }
+
+inline _OutputArray::_OutputArray(const Mat& m)
+{ init(FIXED_TYPE + FIXED_SIZE + MAT + ACCESS_WRITE, &m); }
+
+inline _OutputArray::_OutputArray(const std::vector<Mat>& vec)
+{ init(FIXED_SIZE + STD_VECTOR_MAT + ACCESS_WRITE, &vec); }
+
+inline _OutputArray::_OutputArray(const UMat& m)
+{ init(FIXED_TYPE + FIXED_SIZE + UMAT + ACCESS_WRITE, &m); }
+
+inline _OutputArray::_OutputArray(const std::vector<UMat>& vec)
+{ init(FIXED_SIZE + STD_VECTOR_UMAT + ACCESS_WRITE, &vec); }
+
+inline _OutputArray::_OutputArray(const cuda::GpuMat& d_mat)
+{ init(FIXED_TYPE + FIXED_SIZE + GPU_MAT + ACCESS_WRITE, &d_mat); }
+
+inline _OutputArray::_OutputArray(const ogl::Buffer& buf)
+{ init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_WRITE, &buf); }
+
+inline _OutputArray::_OutputArray(const cuda::CudaMem& cuda_mem)
+{ init(FIXED_TYPE + FIXED_SIZE + CUDA_MEM + ACCESS_WRITE, &cuda_mem); }
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+inline _InputOutputArray::_InputOutputArray() { init(ACCESS_RW, 0); }
+inline _InputOutputArray::_InputOutputArray(int _flags, void* _obj) { init(_flags|ACCESS_RW, _obj); }
+inline _InputOutputArray::_InputOutputArray(Mat& m) { init(MAT+ACCESS_RW, &m); }
+inline _InputOutputArray::_InputOutputArray(std::vector<Mat>& vec) { init(STD_VECTOR_MAT+ACCESS_RW, &vec); }
+inline _InputOutputArray::_InputOutputArray(UMat& m) { init(UMAT+ACCESS_RW, &m); }
+inline _InputOutputArray::_InputOutputArray(std::vector<UMat>& vec) { init(STD_VECTOR_UMAT+ACCESS_RW, &vec); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(std::vector<_Tp>& vec)
+{ init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(std::vector<std::vector<_Tp> >& vec)
+{ init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(std::vector<Mat_<_Tp> >& vec)
+{ init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_RW, &vec); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(Mat_<_Tp>& m)
+{ init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_RW, &m); }
+
+template<typename _Tp, int m, int n> inline
+_InputOutputArray::_InputOutputArray(Matx<_Tp, m, n>& mtx)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, &mtx, Size(n, m)); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(_Tp* vec, int n)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, vec, Size(n, 1)); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(const std::vector<_Tp>& vec)
+{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(const std::vector<std::vector<_Tp> >& vec)
+{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(const std::vector<Mat_<_Tp> >& vec)
+{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_RW, &vec); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(const Mat_<_Tp>& m)
+{ init(FIXED_TYPE + FIXED_SIZE + MAT + DataType<_Tp>::type + ACCESS_RW, &m); }
+
+template<typename _Tp, int m, int n> inline
+_InputOutputArray::_InputOutputArray(const Matx<_Tp, m, n>& mtx)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, &mtx, Size(n, m)); }
+
+template<typename _Tp> inline
+_InputOutputArray::_InputOutputArray(const _Tp* vec, int n)
+{ init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, vec, Size(n, 1)); }
+
+inline _InputOutputArray::_InputOutputArray(cuda::GpuMat& d_mat)
+{ init(GPU_MAT + ACCESS_RW, &d_mat); }
+
+inline _InputOutputArray::_InputOutputArray(ogl::Buffer& buf)
+{ init(OPENGL_BUFFER + ACCESS_RW, &buf); }
+
+inline _InputOutputArray::_InputOutputArray(cuda::CudaMem& cuda_mem)
+{ init(CUDA_MEM + ACCESS_RW, &cuda_mem); }
+
+inline _InputOutputArray::_InputOutputArray(const Mat& m)
+{ init(FIXED_TYPE + FIXED_SIZE + MAT + ACCESS_RW, &m); }
+
+inline _InputOutputArray::_InputOutputArray(const std::vector<Mat>& vec)
+{ init(FIXED_SIZE + STD_VECTOR_MAT + ACCESS_RW, &vec); }
+
+inline _InputOutputArray::_InputOutputArray(const UMat& m)
+{ init(FIXED_TYPE + FIXED_SIZE + UMAT + ACCESS_RW, &m); }
+
+inline _InputOutputArray::_InputOutputArray(const std::vector<UMat>& vec)
+{ init(FIXED_SIZE + STD_VECTOR_UMAT + ACCESS_RW, &vec); }
+
+inline _InputOutputArray::_InputOutputArray(const cuda::GpuMat& d_mat)
+{ init(FIXED_TYPE + FIXED_SIZE + GPU_MAT + ACCESS_RW, &d_mat); }
+
+inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf)
+{ init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_RW, &buf); }
+
+inline _InputOutputArray::_InputOutputArray(const cuda::CudaMem& cuda_mem)
+{ init(FIXED_TYPE + FIXED_SIZE + CUDA_MEM + ACCESS_RW, &cuda_mem); }
+
+//////////////////////////////////////////// Mat //////////////////////////////////////////
+
+inline
+Mat::Mat()
+ : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+ datalimit(0), allocator(0), u(0), size(&rows)
+{}
+
+inline
+Mat::Mat(int _rows, int _cols, int _type)
+ : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+ datalimit(0), allocator(0), u(0), size(&rows)
+{
+ create(_rows, _cols, _type);
+}
+
+inline
+Mat::Mat(int _rows, int _cols, int _type, const Scalar& _s)
+ : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+ datalimit(0), allocator(0), u(0), size(&rows)
+{
+ create(_rows, _cols, _type);
+ *this = _s;
+}
+
+inline
+Mat::Mat(Size _sz, int _type)
+ : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+ datalimit(0), allocator(0), u(0), size(&rows)
+{
+ create( _sz.height, _sz.width, _type );
+}
+
+inline
+Mat::Mat(Size _sz, int _type, const Scalar& _s)
+ : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+ datalimit(0), allocator(0), u(0), size(&rows)
+{
+ create(_sz.height, _sz.width, _type);
+ *this = _s;
+}
+
+inline
+Mat::Mat(int _dims, const int* _sz, int _type)
+ : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+ datalimit(0), allocator(0), u(0), size(&rows)
+{
+ create(_dims, _sz, _type);
+}
+
+inline
+Mat::Mat(int _dims, const int* _sz, int _type, const Scalar& _s)
+ : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+ datalimit(0), allocator(0), u(0), size(&rows)
+{
+ create(_dims, _sz, _type);
+ *this = _s;
+}
+
+inline
+Mat::Mat(const Mat& m)
+ : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data),
+ datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), allocator(m.allocator),
+ u(m.u), size(&rows)
+{
+ if( u )
+ CV_XADD(&u->refcount, 1);
+ if( m.dims <= 2 )
+ {
+ step[0] = m.step[0]; step[1] = m.step[1];
+ }
+ else
+ {
+ dims = 0;
+ copySize(m);
+ }
+}
+
+inline
+Mat::Mat(int _rows, int _cols, int _type, void* _data, size_t _step)
+ : flags(MAGIC_VAL + (_type & TYPE_MASK)), dims(2), rows(_rows), cols(_cols),
+ data((uchar*)_data), datastart((uchar*)_data), dataend(0), datalimit(0),
+ allocator(0), u(0), size(&rows)
+{
+ size_t esz = CV_ELEM_SIZE(_type), esz1 = CV_ELEM_SIZE1(_type);
+ size_t minstep = cols * esz;
+ if( _step == AUTO_STEP )
+ {
+ _step = minstep;
+ flags |= CONTINUOUS_FLAG;
+ }
+ else
+ {
+ if( rows == 1 ) _step = minstep;
+ CV_DbgAssert( _step >= minstep );
+
+ if (_step % esz1 != 0)
+ {
+ CV_Error(Error::BadStep, "Step must be a multiple of esz1");
+ }
+
+ flags |= _step == minstep ? CONTINUOUS_FLAG : 0;
+ }
+ step[0] = _step;
+ step[1] = esz;
+ datalimit = datastart + _step * rows;
+ dataend = datalimit - _step + minstep;
+}
+
+inline
+Mat::Mat(Size _sz, int _type, void* _data, size_t _step)
+ : flags(MAGIC_VAL + (_type & TYPE_MASK)), dims(2), rows(_sz.height), cols(_sz.width),
+ data((uchar*)_data), datastart((uchar*)_data), dataend(0), datalimit(0),
+ allocator(0), u(0), size(&rows)
+{
+ size_t esz = CV_ELEM_SIZE(_type), esz1 = CV_ELEM_SIZE1(_type);
+ size_t minstep = cols*esz;
+ if( _step == AUTO_STEP )
+ {
+ _step = minstep;
+ flags |= CONTINUOUS_FLAG;
+ }
+ else
+ {
+ if( rows == 1 ) _step = minstep;
+ CV_DbgAssert( _step >= minstep );
+
+ if (_step % esz1 != 0)
+ {
+ CV_Error(Error::BadStep, "Step must be a multiple of esz1");
+ }
+
+ flags |= _step == minstep ? CONTINUOUS_FLAG : 0;
+ }
+ step[0] = _step;
+ step[1] = esz;
+ datalimit = datastart + _step*rows;
+ dataend = datalimit - _step + minstep;
+}
+
+template<typename _Tp> inline
+Mat::Mat(const std::vector<_Tp>& vec, bool copyData)
+ : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()),
+ cols(1), data(0), datastart(0), dataend(0), allocator(0), u(0), size(&rows)
+{
+ if(vec.empty())
+ return;
+ if( !copyData )
+ {
+ step[0] = step[1] = sizeof(_Tp);
+ data = datastart = (uchar*)&vec[0];
+ datalimit = dataend = datastart + rows * step[0];
+ }
+ else
+ Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this);
+}
+
+template<typename _Tp, int n> inline
+Mat::Mat(const Vec<_Tp, n>& vec, bool copyData)
+ : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(n), cols(1), data(0),
+ datastart(0), dataend(0), allocator(0), u(0), size(&rows)
+{
+ if( !copyData )
+ {
+ step[0] = step[1] = sizeof(_Tp);
+ data = datastart = (uchar*)vec.val;
+ datalimit = dataend = datastart + rows * step[0];
+ }
+ else
+ Mat(n, 1, DataType<_Tp>::type, (void*)vec.val).copyTo(*this);
+}
+
+
+template<typename _Tp, int m, int n> inline
+Mat::Mat(const Matx<_Tp,m,n>& M, bool copyData)
+ : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(m), cols(n), data(0),
+ datastart(0), dataend(0), allocator(0), u(0), size(&rows)
+{
+ if( !copyData )
+ {
+ step[0] = cols * sizeof(_Tp);
+ step[1] = sizeof(_Tp);
+ data = datastart = (uchar*)M.val;
+ datalimit = dataend = datastart + rows * step[0];
+ }
+ else
+ Mat(m, n, DataType<_Tp>::type, (uchar*)M.val).copyTo(*this);
+}
+
+template<typename _Tp> inline
+Mat::Mat(const Point_<_Tp>& pt, bool copyData)
+ : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(2), cols(1), data(0),
+ datastart(0), dataend(0), allocator(0), u(0), size(&rows)
+{
+ if( !copyData )
+ {
+ step[0] = step[1] = sizeof(_Tp);
+ data = datastart = (uchar*)&pt.x;
+ datalimit = dataend = datastart + rows * step[0];
+ }
+ else
+ {
+ create(2, 1, DataType<_Tp>::type);
+ ((_Tp*)data)[0] = pt.x;
+ ((_Tp*)data)[1] = pt.y;
+ }
+}
+
+template<typename _Tp> inline
+Mat::Mat(const Point3_<_Tp>& pt, bool copyData)
+ : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows(3), cols(1), data(0),
+ datastart(0), dataend(0), allocator(0), u(0), size(&rows)
+{
+ if( !copyData )
+ {
+ step[0] = step[1] = sizeof(_Tp);
+ data = datastart = (uchar*)&pt.x;
+ datalimit = dataend = datastart + rows * step[0];
+ }
+ else
+ {
+ create(3, 1, DataType<_Tp>::type);
+ ((_Tp*)data)[0] = pt.x;
+ ((_Tp*)data)[1] = pt.y;
+ ((_Tp*)data)[2] = pt.z;
+ }
+}
+
+template<typename _Tp> inline
+Mat::Mat(const MatCommaInitializer_<_Tp>& commaInitializer)
+ : flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(0), rows(0), cols(0), data(0),
+ datastart(0), dataend(0), allocator(0), u(0), size(&rows)
+{
+ *this = commaInitializer.operator Mat_<_Tp>();
+}
+
+inline
+Mat::~Mat()
+{
+ release();
+ if( step.p != step.buf )
+ fastFree(step.p);
+}
+
+inline
+Mat& Mat::operator = (const Mat& m)
+{
+ if( this != &m )
+ {
+ if( m.u )
+ CV_XADD(&m.u->refcount, 1);
+ release();
+ flags = m.flags;
+ if( dims <= 2 && m.dims <= 2 )
+ {
+ dims = m.dims;
+ rows = m.rows;
+ cols = m.cols;
+ step[0] = m.step[0];
+ step[1] = m.step[1];
+ }
+ else
+ copySize(m);
+ data = m.data;
+ datastart = m.datastart;
+ dataend = m.dataend;
+ datalimit = m.datalimit;
+ allocator = m.allocator;
+ u = m.u;
+ }
+ return *this;
+}
+
+inline
+Mat Mat::row(int y) const
+{
+ return Mat(*this, Range(y, y + 1), Range::all());
+}
+
+inline
+Mat Mat::col(int x) const
+{
+ return Mat(*this, Range::all(), Range(x, x + 1));
+}
+
+inline
+Mat Mat::rowRange(int startrow, int endrow) const
+{
+ return Mat(*this, Range(startrow, endrow), Range::all());
+}
+
+inline
+Mat Mat::rowRange(const Range& r) const
+{
+ return Mat(*this, r, Range::all());
+}
+
+inline
+Mat Mat::colRange(int startcol, int endcol) const
+{
+ return Mat(*this, Range::all(), Range(startcol, endcol));
+}
+
+inline
+Mat Mat::colRange(const Range& r) const
+{
+ return Mat(*this, Range::all(), r);
+}
+
+inline
+Mat Mat::clone() const
+{
+ Mat m;
+ copyTo(m);
+ return m;
+}
+
+inline
+void Mat::assignTo( Mat& m, int _type ) const
+{
+ if( _type < 0 )
+ m = *this;
+ else
+ convertTo(m, _type);
+}
+
+inline
+void Mat::create(int _rows, int _cols, int _type)
+{
+ _type &= TYPE_MASK;
+ if( dims <= 2 && rows == _rows && cols == _cols && type() == _type && data )
+ return;
+ int sz[] = {_rows, _cols};
+ create(2, sz, _type);
+}
+
+inline
+void Mat::create(Size _sz, int _type)
+{
+ create(_sz.height, _sz.width, _type);
+}
+
+inline
+void Mat::addref()
+{
+ if( u )
+ CV_XADD(&u->refcount, 1);
+}
+
+inline void Mat::release()
+{
+ if( u && CV_XADD(&u->refcount, -1) == 1 )
+ deallocate();
+ u = NULL;
+ data = datastart = dataend = datalimit = 0;
- SparseMatConstIterator it = *this;
++ for(int i = 0; i < dims; i++)
++ size.p[i] = 0;
+}
+
+inline
+Mat Mat::operator()( Range _rowRange, Range _colRange ) const
+{
+ return Mat(*this, _rowRange, _colRange);
+}
+
+inline
+Mat Mat::operator()( const Rect& roi ) const
+{
+ return Mat(*this, roi);
+}
+
+inline
+Mat Mat::operator()(const Range* ranges) const
+{
+ return Mat(*this, ranges);
+}
+
+inline
+bool Mat::isContinuous() const
+{
+ return (flags & CONTINUOUS_FLAG) != 0;
+}
+
+inline
+bool Mat::isSubmatrix() const
+{
+ return (flags & SUBMATRIX_FLAG) != 0;
+}
+
+inline
+size_t Mat::elemSize() const
+{
+ return dims > 0 ? step.p[dims - 1] : 0;
+}
+
+inline
+size_t Mat::elemSize1() const
+{
+ return CV_ELEM_SIZE1(flags);
+}
+
+inline
+int Mat::type() const
+{
+ return CV_MAT_TYPE(flags);
+}
+
+inline
+int Mat::depth() const
+{
+ return CV_MAT_DEPTH(flags);
+}
+
+inline
+int Mat::channels() const
+{
+ return CV_MAT_CN(flags);
+}
+
+inline
+size_t Mat::step1(int i) const
+{
+ return step.p[i] / elemSize1();
+}
+
+inline
+bool Mat::empty() const
+{
+ return data == 0 || total() == 0;
+}
+
+inline
+size_t Mat::total() const
+{
+ if( dims <= 2 )
+ return (size_t)rows * cols;
+ size_t p = 1;
+ for( int i = 0; i < dims; i++ )
+ p *= size[i];
+ return p;
+}
+
+inline
+uchar* Mat::ptr(int y)
+{
+ CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) );
+ return data + step.p[0] * y;
+}
+
+inline
+const uchar* Mat::ptr(int y) const
+{
+ CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) );
+ return data + step.p[0] * y;
+}
+
+template<typename _Tp> inline
+_Tp* Mat::ptr(int y)
+{
+ CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) );
+ return (_Tp*)(data + step.p[0] * y);
+}
+
+template<typename _Tp> inline
+const _Tp* Mat::ptr(int y) const
+{
+ CV_DbgAssert( y == 0 || (data && dims >= 1 && data && (unsigned)y < (unsigned)size.p[0]) );
+ return (const _Tp*)(data + step.p[0] * y);
+}
+
+inline
+uchar* Mat::ptr(int i0, int i1)
+{
+ CV_DbgAssert( dims >= 2 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] );
+ return data + i0 * step.p[0] + i1 * step.p[1];
+}
+
+inline
+const uchar* Mat::ptr(int i0, int i1) const
+{
+ CV_DbgAssert( dims >= 2 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] );
+ return data + i0 * step.p[0] + i1 * step.p[1];
+}
+
+template<typename _Tp> inline
+_Tp* Mat::ptr(int i0, int i1)
+{
+ CV_DbgAssert( dims >= 2 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] );
+ return (_Tp*)(data + i0 * step.p[0] + i1 * step.p[1]);
+}
+
+template<typename _Tp> inline
+const _Tp* Mat::ptr(int i0, int i1) const
+{
+ CV_DbgAssert( dims >= 2 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] );
+ return (const _Tp*)(data + i0 * step.p[0] + i1 * step.p[1]);
+}
+
+inline
+uchar* Mat::ptr(int i0, int i1, int i2)
+{
+ CV_DbgAssert( dims >= 3 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] &&
+ (unsigned)i2 < (unsigned)size.p[2] );
+ return data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2];
+}
+
+inline
+const uchar* Mat::ptr(int i0, int i1, int i2) const
+{
+ CV_DbgAssert( dims >= 3 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] &&
+ (unsigned)i2 < (unsigned)size.p[2] );
+ return data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2];
+}
+
+template<typename _Tp> inline
+_Tp* Mat::ptr(int i0, int i1, int i2)
+{
+ CV_DbgAssert( dims >= 3 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] &&
+ (unsigned)i2 < (unsigned)size.p[2] );
+ return (_Tp*)(data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]);
+}
+
+template<typename _Tp> inline
+const _Tp* Mat::ptr(int i0, int i1, int i2) const
+{
+ CV_DbgAssert( dims >= 3 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] &&
+ (unsigned)i2 < (unsigned)size.p[2] );
+ return (const _Tp*)(data + i0 * step.p[0] + i1 * step.p[1] + i2 * step.p[2]);
+}
+
+inline
+uchar* Mat::ptr(const int* idx)
+{
+ int i, d = dims;
+ uchar* p = data;
+ CV_DbgAssert( d >= 1 && p );
+ for( i = 0; i < d; i++ )
+ {
+ CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] );
+ p += idx[i] * step.p[i];
+ }
+ return p;
+}
+
+inline
+const uchar* Mat::ptr(const int* idx) const
+{
+ int i, d = dims;
+ uchar* p = data;
+ CV_DbgAssert( d >= 1 && p );
+ for( i = 0; i < d; i++ )
+ {
+ CV_DbgAssert( (unsigned)idx[i] < (unsigned)size.p[i] );
+ p += idx[i] * step.p[i];
+ }
+ return p;
+}
+
+template<typename _Tp> inline
+_Tp& Mat::at(int i0, int i1)
+{
+ CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) &&
+ CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());
+ return ((_Tp*)(data + step.p[0] * i0))[i1];
+}
+
+template<typename _Tp> inline
+const _Tp& Mat::at(int i0, int i1) const
+{
+ CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)(i1 * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) &&
+ CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());
+ return ((const _Tp*)(data + step.p[0] * i0))[i1];
+}
+
+template<typename _Tp> inline
+_Tp& Mat::at(Point pt)
+{
+ CV_DbgAssert( dims <= 2 && data && (unsigned)pt.y < (unsigned)size.p[0] &&
+ (unsigned)(pt.x * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) &&
+ CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());
+ return ((_Tp*)(data + step.p[0] * pt.y))[pt.x];
+}
+
+template<typename _Tp> inline
+const _Tp& Mat::at(Point pt) const
+{
+ CV_DbgAssert( dims <= 2 && data && (unsigned)pt.y < (unsigned)size.p[0] &&
+ (unsigned)(pt.x * DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels()) &&
+ CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());
+ return ((const _Tp*)(data + step.p[0] * pt.y))[pt.x];
+}
+
+template<typename _Tp> inline
+_Tp& Mat::at(int i0)
+{
+ CV_DbgAssert( dims <= 2 && data &&
+ (unsigned)i0 < (unsigned)(size.p[0] * size.p[1]) &&
+ elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) );
+ if( isContinuous() || size.p[0] == 1 )
+ return ((_Tp*)data)[i0];
+ if( size.p[1] == 1 )
+ return *(_Tp*)(data + step.p[0] * i0);
+ int i = i0 / cols, j = i0 - i * cols;
+ return ((_Tp*)(data + step.p[0] * i))[j];
+}
+
+template<typename _Tp> inline
+const _Tp& Mat::at(int i0) const
+{
+ CV_DbgAssert( dims <= 2 && data &&
+ (unsigned)i0 < (unsigned)(size.p[0] * size.p[1]) &&
+ elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) );
+ if( isContinuous() || size.p[0] == 1 )
+ return ((const _Tp*)data)[i0];
+ if( size.p[1] == 1 )
+ return *(const _Tp*)(data + step.p[0] * i0);
+ int i = i0 / cols, j = i0 - i * cols;
+ return ((const _Tp*)(data + step.p[0] * i))[j];
+}
+
+template<typename _Tp> inline
+_Tp& Mat::at(int i0, int i1, int i2)
+{
+ CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) );
+ return *(_Tp*)ptr(i0, i1, i2);
+}
+
+template<typename _Tp> inline
+const _Tp& Mat::at(int i0, int i1, int i2) const
+{
+ CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) );
+ return *(const _Tp*)ptr(i0, i1, i2);
+}
+
+template<typename _Tp> inline
+_Tp& Mat::at(const int* idx)
+{
+ CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) );
+ return *(_Tp*)ptr(idx);
+}
+
+template<typename _Tp> inline
+const _Tp& Mat::at(const int* idx) const
+{
+ CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) );
+ return *(const _Tp*)ptr(idx);
+}
+
+template<typename _Tp, int n> inline
+_Tp& Mat::at(const Vec<int, n>& idx)
+{
+ CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) );
+ return *(_Tp*)ptr(idx.val);
+}
+
+template<typename _Tp, int n> inline
+const _Tp& Mat::at(const Vec<int, n>& idx) const
+{
+ CV_DbgAssert( elemSize() == CV_ELEM_SIZE(DataType<_Tp>::type) );
+ return *(const _Tp*)ptr(idx.val);
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp> Mat::begin() const
+{
+ CV_DbgAssert( elemSize() == sizeof(_Tp) );
+ return MatConstIterator_<_Tp>((const Mat_<_Tp>*)this);
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp> Mat::end() const
+{
+ CV_DbgAssert( elemSize() == sizeof(_Tp) );
+ MatConstIterator_<_Tp> it((const Mat_<_Tp>*)this);
+ it += total();
+ return it;
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp> Mat::begin()
+{
+ CV_DbgAssert( elemSize() == sizeof(_Tp) );
+ return MatIterator_<_Tp>((Mat_<_Tp>*)this);
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp> Mat::end()
+{
+ CV_DbgAssert( elemSize() == sizeof(_Tp) );
+ MatIterator_<_Tp> it((Mat_<_Tp>*)this);
+ it += total();
+ return it;
+}
+
+template<typename _Tp> inline
+Mat::operator std::vector<_Tp>() const
+{
+ std::vector<_Tp> v;
+ copyTo(v);
+ return v;
+}
+
+template<typename _Tp, int n> inline
+Mat::operator Vec<_Tp, n>() const
+{
+ CV_Assert( data && dims <= 2 && (rows == 1 || cols == 1) &&
+ rows + cols - 1 == n && channels() == 1 );
+
+ if( isContinuous() && type() == DataType<_Tp>::type )
+ return Vec<_Tp, n>((_Tp*)data);
+ Vec<_Tp, n> v;
+ Mat tmp(rows, cols, DataType<_Tp>::type, v.val);
+ convertTo(tmp, tmp.type());
+ return v;
+}
+
+template<typename _Tp, int m, int n> inline
+Mat::operator Matx<_Tp, m, n>() const
+{
+ CV_Assert( data && dims <= 2 && rows == m && cols == n && channels() == 1 );
+
+ if( isContinuous() && type() == DataType<_Tp>::type )
+ return Matx<_Tp, m, n>((_Tp*)data);
+ Matx<_Tp, m, n> mtx;
+ Mat tmp(rows, cols, DataType<_Tp>::type, mtx.val);
+ convertTo(tmp, tmp.type());
+ return mtx;
+}
+
+template<typename _Tp> inline
+void Mat::push_back(const _Tp& elem)
+{
+ if( !data )
+ {
+ *this = Mat(1, 1, DataType<_Tp>::type, (void*)&elem).clone();
+ return;
+ }
+ CV_Assert(DataType<_Tp>::type == type() && cols == 1
+ /* && dims == 2 (cols == 1 implies dims == 2) */);
+ uchar* tmp = dataend + step[0];
+ if( !isSubmatrix() && isContinuous() && tmp <= datalimit )
+ {
+ *(_Tp*)(data + (size.p[0]++) * step.p[0]) = elem;
+ dataend = tmp;
+ }
+ else
+ push_back_(&elem);
+}
+
+template<typename _Tp> inline
+void Mat::push_back(const Mat_<_Tp>& m)
+{
+ push_back((const Mat&)m);
+}
+
+///////////////////////////// MatSize ////////////////////////////
+
+inline
+MatSize::MatSize(int* _p)
+ : p(_p) {}
+
+inline
+Size MatSize::operator()() const
+{
+ CV_DbgAssert(p[-1] <= 2);
+ return Size(p[1], p[0]);
+}
+
+inline
+const int& MatSize::operator[](int i) const
+{
+ return p[i];
+}
+
+inline
+int& MatSize::operator[](int i)
+{
+ return p[i];
+}
+
+inline
+MatSize::operator const int*() const
+{
+ return p;
+}
+
+inline
+bool MatSize::operator == (const MatSize& sz) const
+{
+ int d = p[-1];
+ int dsz = sz.p[-1];
+ if( d != dsz )
+ return false;
+ if( d == 2 )
+ return p[0] == sz.p[0] && p[1] == sz.p[1];
+
+ for( int i = 0; i < d; i++ )
+ if( p[i] != sz.p[i] )
+ return false;
+ return true;
+}
+
+inline
+bool MatSize::operator != (const MatSize& sz) const
+{
+ return !(*this == sz);
+}
+
+
+
+///////////////////////////// MatStep ////////////////////////////
+
+inline
+MatStep::MatStep()
+{
+ p = buf; p[0] = p[1] = 0;
+}
+
+inline
+MatStep::MatStep(size_t s)
+{
+ p = buf; p[0] = s; p[1] = 0;
+}
+
+inline
+const size_t& MatStep::operator[](int i) const
+{
+ return p[i];
+}
+
+inline
+size_t& MatStep::operator[](int i)
+{
+ return p[i];
+}
+
+inline MatStep::operator size_t() const
+{
+ CV_DbgAssert( p == buf );
+ return buf[0];
+}
+
+inline MatStep& MatStep::operator = (size_t s)
+{
+ CV_DbgAssert( p == buf );
+ buf[0] = s;
+ return *this;
+}
+
+
+
+////////////////////////////// Mat_<_Tp> ////////////////////////////
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_()
+ : Mat()
+{
+ flags = (flags & ~CV_MAT_TYPE_MASK) | DataType<_Tp>::type;
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(int _rows, int _cols)
+ : Mat(_rows, _cols, DataType<_Tp>::type)
+{
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(int _rows, int _cols, const _Tp& value)
+ : Mat(_rows, _cols, DataType<_Tp>::type)
+{
+ *this = value;
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(Size _sz)
+ : Mat(_sz.height, _sz.width, DataType<_Tp>::type)
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(Size _sz, const _Tp& value)
+ : Mat(_sz.height, _sz.width, DataType<_Tp>::type)
+{
+ *this = value;
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(int _dims, const int* _sz)
+ : Mat(_dims, _sz, DataType<_Tp>::type)
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(int _dims, const int* _sz, const _Tp& _s)
+ : Mat(_dims, _sz, DataType<_Tp>::type, Scalar(_s))
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const Range* ranges)
+ : Mat(m, ranges)
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const Mat& m)
+ : Mat()
+{
+ flags = (flags & ~CV_MAT_TYPE_MASK) | DataType<_Tp>::type;
+ *this = m;
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const Mat_& m)
+ : Mat(m)
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(int _rows, int _cols, _Tp* _data, size_t steps)
+ : Mat(_rows, _cols, DataType<_Tp>::type, _data, steps)
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const Mat_& m, const Range& _rowRange, const Range& _colRange)
+ : Mat(m, _rowRange, _colRange)
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const Mat_& m, const Rect& roi)
+ : Mat(m, roi)
+{}
+
+template<typename _Tp> template<int n> inline
+Mat_<_Tp>::Mat_(const Vec<typename DataType<_Tp>::channel_type, n>& vec, bool copyData)
+ : Mat(n / DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&vec)
+{
+ CV_Assert(n%DataType<_Tp>::channels == 0);
+ if( copyData )
+ *this = clone();
+}
+
+template<typename _Tp> template<int m, int n> inline
+Mat_<_Tp>::Mat_(const Matx<typename DataType<_Tp>::channel_type, m, n>& M, bool copyData)
+ : Mat(m, n / DataType<_Tp>::channels, DataType<_Tp>::type, (void*)&M)
+{
+ CV_Assert(n % DataType<_Tp>::channels == 0);
+ if( copyData )
+ *this = clone();
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const Point_<typename DataType<_Tp>::channel_type>& pt, bool copyData)
+ : Mat(2 / DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&pt)
+{
+ CV_Assert(2 % DataType<_Tp>::channels == 0);
+ if( copyData )
+ *this = clone();
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const Point3_<typename DataType<_Tp>::channel_type>& pt, bool copyData)
+ : Mat(3 / DataType<_Tp>::channels, 1, DataType<_Tp>::type, (void*)&pt)
+{
+ CV_Assert(3 % DataType<_Tp>::channels == 0);
+ if( copyData )
+ *this = clone();
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const MatCommaInitializer_<_Tp>& commaInitializer)
+ : Mat(commaInitializer)
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const std::vector<_Tp>& vec, bool copyData)
+ : Mat(vec, copyData)
+{}
+
+template<typename _Tp> inline
+Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat& m)
+{
+ if( DataType<_Tp>::type == m.type() )
+ {
+ Mat::operator = (m);
+ return *this;
+ }
+ if( DataType<_Tp>::depth == m.depth() )
+ {
+ return (*this = m.reshape(DataType<_Tp>::channels, m.dims, 0));
+ }
+ CV_DbgAssert(DataType<_Tp>::channels == m.channels());
+ m.convertTo(*this, type());
+ return *this;
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat_& m)
+{
+ Mat::operator=(m);
+ return *this;
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>& Mat_<_Tp>::operator = (const _Tp& s)
+{
+ typedef typename DataType<_Tp>::vec_type VT;
+ Mat::operator=(Scalar((const VT&)s));
+ return *this;
+}
+
+template<typename _Tp> inline
+void Mat_<_Tp>::create(int _rows, int _cols)
+{
+ Mat::create(_rows, _cols, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+void Mat_<_Tp>::create(Size _sz)
+{
+ Mat::create(_sz, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+void Mat_<_Tp>::create(int _dims, const int* _sz)
+{
+ Mat::create(_dims, _sz, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::cross(const Mat_& m) const
+{
+ return Mat_<_Tp>(Mat::cross(m));
+}
+
+template<typename _Tp> template<typename T2> inline
+Mat_<_Tp>::operator Mat_<T2>() const
+{
+ return Mat_<T2>(*this);
+}
+
+template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::row(int y) const
+{
+ return Mat_(*this, Range(y, y+1), Range::all());
+}
+
+template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::col(int x) const
+{
+ return Mat_(*this, Range::all(), Range(x, x+1));
+}
+
+template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::diag(int d) const
+{
+ return Mat_(Mat::diag(d));
+}
+
+template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::clone() const
+{
+ return Mat_(Mat::clone());
+}
+
+template<typename _Tp> inline
+size_t Mat_<_Tp>::elemSize() const
+{
+ CV_DbgAssert( Mat::elemSize() == sizeof(_Tp) );
+ return sizeof(_Tp);
+}
+
+template<typename _Tp> inline
+size_t Mat_<_Tp>::elemSize1() const
+{
+ CV_DbgAssert( Mat::elemSize1() == sizeof(_Tp) / DataType<_Tp>::channels );
+ return sizeof(_Tp) / DataType<_Tp>::channels;
+}
+
+template<typename _Tp> inline
+int Mat_<_Tp>::type() const
+{
+ CV_DbgAssert( Mat::type() == DataType<_Tp>::type );
+ return DataType<_Tp>::type;
+}
+
+template<typename _Tp> inline
+int Mat_<_Tp>::depth() const
+{
+ CV_DbgAssert( Mat::depth() == DataType<_Tp>::depth );
+ return DataType<_Tp>::depth;
+}
+
+template<typename _Tp> inline
+int Mat_<_Tp>::channels() const
+{
+ CV_DbgAssert( Mat::channels() == DataType<_Tp>::channels );
+ return DataType<_Tp>::channels;
+}
+
+template<typename _Tp> inline
+size_t Mat_<_Tp>::stepT(int i) const
+{
+ return step.p[i] / elemSize();
+}
+
+template<typename _Tp> inline
+size_t Mat_<_Tp>::step1(int i) const
+{
+ return step.p[i] / elemSize1();
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>& Mat_<_Tp>::adjustROI( int dtop, int dbottom, int dleft, int dright )
+{
+ return (Mat_<_Tp>&)(Mat::adjustROI(dtop, dbottom, dleft, dright));
+}
+
+template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::operator()( const Range& _rowRange, const Range& _colRange ) const
+{
+ return Mat_<_Tp>(*this, _rowRange, _colRange);
+}
+
+template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::operator()( const Rect& roi ) const
+{
+ return Mat_<_Tp>(*this, roi);
+}
+
+template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::operator()( const Range* ranges ) const
+{
+ return Mat_<_Tp>(*this, ranges);
+}
+
+template<typename _Tp> inline
+_Tp* Mat_<_Tp>::operator [](int y)
+{
+ return (_Tp*)ptr(y);
+}
+
+template<typename _Tp> inline
+const _Tp* Mat_<_Tp>::operator [](int y) const
+{
+ return (const _Tp*)ptr(y);
+}
+
+template<typename _Tp> inline
+_Tp& Mat_<_Tp>::operator ()(int i0, int i1)
+{
+ CV_DbgAssert( dims <= 2 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] &&
+ type() == DataType<_Tp>::type );
+ return ((_Tp*)(data + step.p[0] * i0))[i1];
+}
+
+template<typename _Tp> inline
+const _Tp& Mat_<_Tp>::operator ()(int i0, int i1) const
+{
+ CV_DbgAssert( dims <= 2 && data &&
+ (unsigned)i0 < (unsigned)size.p[0] &&
+ (unsigned)i1 < (unsigned)size.p[1] &&
+ type() == DataType<_Tp>::type );
+ return ((const _Tp*)(data + step.p[0] * i0))[i1];
+}
+
+template<typename _Tp> inline
+_Tp& Mat_<_Tp>::operator ()(Point pt)
+{
+ CV_DbgAssert( dims <= 2 && data &&
+ (unsigned)pt.y < (unsigned)size.p[0] &&
+ (unsigned)pt.x < (unsigned)size.p[1] &&
+ type() == DataType<_Tp>::type );
+ return ((_Tp*)(data + step.p[0] * pt.y))[pt.x];
+}
+
+template<typename _Tp> inline
+const _Tp& Mat_<_Tp>::operator ()(Point pt) const
+{
+ CV_DbgAssert( dims <= 2 && data &&
+ (unsigned)pt.y < (unsigned)size.p[0] &&
+ (unsigned)pt.x < (unsigned)size.p[1] &&
+ type() == DataType<_Tp>::type );
+ return ((const _Tp*)(data + step.p[0] * pt.y))[pt.x];
+}
+
+template<typename _Tp> inline
+_Tp& Mat_<_Tp>::operator ()(const int* idx)
+{
+ return Mat::at<_Tp>(idx);
+}
+
+template<typename _Tp> inline
+const _Tp& Mat_<_Tp>::operator ()(const int* idx) const
+{
+ return Mat::at<_Tp>(idx);
+}
+
+template<typename _Tp> template<int n> inline
+_Tp& Mat_<_Tp>::operator ()(const Vec<int, n>& idx)
+{
+ return Mat::at<_Tp>(idx);
+}
+
+template<typename _Tp> template<int n> inline
+const _Tp& Mat_<_Tp>::operator ()(const Vec<int, n>& idx) const
+{
+ return Mat::at<_Tp>(idx);
+}
+
+template<typename _Tp> inline
+_Tp& Mat_<_Tp>::operator ()(int i0)
+{
+ return this->at<_Tp>(i0);
+}
+
+template<typename _Tp> inline
+const _Tp& Mat_<_Tp>::operator ()(int i0) const
+{
+ return this->at<_Tp>(i0);
+}
+
+template<typename _Tp> inline
+_Tp& Mat_<_Tp>::operator ()(int i0, int i1, int i2)
+{
+ return this->at<_Tp>(i0, i1, i2);
+}
+
+template<typename _Tp> inline
+const _Tp& Mat_<_Tp>::operator ()(int i0, int i1, int i2) const
+{
+ return this->at<_Tp>(i0, i1, i2);
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::operator std::vector<_Tp>() const
+{
+ std::vector<_Tp> v;
+ copyTo(v);
+ return v;
+}
+
+template<typename _Tp> template<int n> inline
+Mat_<_Tp>::operator Vec<typename DataType<_Tp>::channel_type, n>() const
+{
+ CV_Assert(n % DataType<_Tp>::channels == 0);
+ return this->Mat::operator Vec<typename DataType<_Tp>::channel_type, n>();
+}
+
+template<typename _Tp> template<int m, int n> inline
+Mat_<_Tp>::operator Matx<typename DataType<_Tp>::channel_type, m, n>() const
+{
+ CV_Assert(n % DataType<_Tp>::channels == 0);
+
+ Matx<typename DataType<_Tp>::channel_type, m, n> res = this->Mat::operator Matx<typename DataType<_Tp>::channel_type, m, n>();
+ return res;
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp> Mat_<_Tp>::begin() const
+{
+ return Mat::begin<_Tp>();
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp> Mat_<_Tp>::end() const
+{
+ return Mat::end<_Tp>();
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp> Mat_<_Tp>::begin()
+{
+ return Mat::begin<_Tp>();
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp> Mat_<_Tp>::end()
+{
+ return Mat::end<_Tp>();
+}
+
+
+///////////////////////////// SparseMat /////////////////////////////
+
+inline
+SparseMat::SparseMat()
+ : flags(MAGIC_VAL), hdr(0)
+{}
+
+inline
+SparseMat::SparseMat(int _dims, const int* _sizes, int _type)
+ : flags(MAGIC_VAL), hdr(0)
+{
+ create(_dims, _sizes, _type);
+}
+
+inline
+SparseMat::SparseMat(const SparseMat& m)
+ : flags(m.flags), hdr(m.hdr)
+{
+ addref();
+}
+
+inline
+SparseMat::~SparseMat()
+{
+ release();
+}
+
+inline
+SparseMat& SparseMat::operator = (const SparseMat& m)
+{
+ if( this != &m )
+ {
+ if( m.hdr )
+ CV_XADD(&m.hdr->refcount, 1);
+ release();
+ flags = m.flags;
+ hdr = m.hdr;
+ }
+ return *this;
+}
+
+inline
+SparseMat& SparseMat::operator = (const Mat& m)
+{
+ return (*this = SparseMat(m));
+}
+
+inline
+SparseMat SparseMat::clone() const
+{
+ SparseMat temp;
+ this->copyTo(temp);
+ return temp;
+}
+
+inline
+void SparseMat::assignTo( SparseMat& m, int _type ) const
+{
+ if( _type < 0 )
+ m = *this;
+ else
+ convertTo(m, _type);
+}
+
+inline
+void SparseMat::addref()
+{
+ if( hdr )
+ CV_XADD(&hdr->refcount, 1);
+}
+
+inline
+void SparseMat::release()
+{
+ if( hdr && CV_XADD(&hdr->refcount, -1) == 1 )
+ delete hdr;
+ hdr = 0;
+}
+
+inline
+size_t SparseMat::elemSize() const
+{
+ return CV_ELEM_SIZE(flags);
+}
+
+inline
+size_t SparseMat::elemSize1() const
+{
+ return CV_ELEM_SIZE1(flags);
+}
+
+inline
+int SparseMat::type() const
+{
+ return CV_MAT_TYPE(flags);
+}
+
+inline
+int SparseMat::depth() const
+{
+ return CV_MAT_DEPTH(flags);
+}
+
+inline
+int SparseMat::channels() const
+{
+ return CV_MAT_CN(flags);
+}
+
+inline
+const int* SparseMat::size() const
+{
+ return hdr ? hdr->size : 0;
+}
+
+inline
+int SparseMat::size(int i) const
+{
+ if( hdr )
+ {
+ CV_DbgAssert((unsigned)i < (unsigned)hdr->dims);
+ return hdr->size[i];
+ }
+ return 0;
+}
+
+inline
+int SparseMat::dims() const
+{
+ return hdr ? hdr->dims : 0;
+}
+
+inline
+size_t SparseMat::nzcount() const
+{
+ return hdr ? hdr->nodeCount : 0;
+}
+
+inline
+size_t SparseMat::hash(int i0) const
+{
+ return (size_t)i0;
+}
+
+inline
+size_t SparseMat::hash(int i0, int i1) const
+{
+ return (size_t)(unsigned)i0 * HASH_SCALE + (unsigned)i1;
+}
+
+inline
+size_t SparseMat::hash(int i0, int i1, int i2) const
+{
+ return ((size_t)(unsigned)i0 * HASH_SCALE + (unsigned)i1) * HASH_SCALE + (unsigned)i2;
+}
+
+inline
+size_t SparseMat::hash(const int* idx) const
+{
+ size_t h = (unsigned)idx[0];
+ if( !hdr )
+ return 0;
+ int d = hdr->dims;
+ for(int i = 1; i < d; i++ )
+ h = h * HASH_SCALE + (unsigned)idx[i];
+ return h;
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat::ref(int i0, size_t* hashval)
+{
+ return *(_Tp*)((SparseMat*)this)->ptr(i0, true, hashval);
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat::ref(int i0, int i1, size_t* hashval)
+{
+ return *(_Tp*)((SparseMat*)this)->ptr(i0, i1, true, hashval);
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat::ref(int i0, int i1, int i2, size_t* hashval)
+{
+ return *(_Tp*)((SparseMat*)this)->ptr(i0, i1, i2, true, hashval);
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat::ref(const int* idx, size_t* hashval)
+{
+ return *(_Tp*)((SparseMat*)this)->ptr(idx, true, hashval);
+}
+
+template<typename _Tp> inline
+_Tp SparseMat::value(int i0, size_t* hashval) const
+{
+ const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, false, hashval);
+ return p ? *p : _Tp();
+}
+
+template<typename _Tp> inline
+_Tp SparseMat::value(int i0, int i1, size_t* hashval) const
+{
+ const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, i1, false, hashval);
+ return p ? *p : _Tp();
+}
+
+template<typename _Tp> inline
+_Tp SparseMat::value(int i0, int i1, int i2, size_t* hashval) const
+{
+ const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(i0, i1, i2, false, hashval);
+ return p ? *p : _Tp();
+}
+
+template<typename _Tp> inline
+_Tp SparseMat::value(const int* idx, size_t* hashval) const
+{
+ const _Tp* p = (const _Tp*)((SparseMat*)this)->ptr(idx, false, hashval);
+ return p ? *p : _Tp();
+}
+
+template<typename _Tp> inline
+const _Tp* SparseMat::find(int i0, size_t* hashval) const
+{
+ return (const _Tp*)((SparseMat*)this)->ptr(i0, false, hashval);
+}
+
+template<typename _Tp> inline
+const _Tp* SparseMat::find(int i0, int i1, size_t* hashval) const
+{
+ return (const _Tp*)((SparseMat*)this)->ptr(i0, i1, false, hashval);
+}
+
+template<typename _Tp> inline
+const _Tp* SparseMat::find(int i0, int i1, int i2, size_t* hashval) const
+{
+ return (const _Tp*)((SparseMat*)this)->ptr(i0, i1, i2, false, hashval);
+}
+
+template<typename _Tp> inline
+const _Tp* SparseMat::find(const int* idx, size_t* hashval) const
+{
+ return (const _Tp*)((SparseMat*)this)->ptr(idx, false, hashval);
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat::value(Node* n)
+{
+ return *(_Tp*)((uchar*)n + hdr->valueOffset);
+}
+
+template<typename _Tp> inline
+const _Tp& SparseMat::value(const Node* n) const
+{
+ return *(const _Tp*)((const uchar*)n + hdr->valueOffset);
+}
+
+inline
+SparseMat::Node* SparseMat::node(size_t nidx)
+{
+ return (Node*)(void*)&hdr->pool[nidx];
+}
+
+inline
+const SparseMat::Node* SparseMat::node(size_t nidx) const
+{
+ return (const Node*)(const void*)&hdr->pool[nidx];
+}
+
+inline
+SparseMatIterator SparseMat::begin()
+{
+ return SparseMatIterator(this);
+}
+
+inline
+SparseMatConstIterator SparseMat::begin() const
+{
+ return SparseMatConstIterator(this);
+}
+
+inline
+SparseMatIterator SparseMat::end()
+{
+ SparseMatIterator it(this);
+ it.seekEnd();
+ return it;
+}
+
+inline
+SparseMatConstIterator SparseMat::end() const
+{
+ SparseMatConstIterator it(this);
+ it.seekEnd();
+ return it;
+}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp> SparseMat::begin()
+{
+ return SparseMatIterator_<_Tp>(this);
+}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp> SparseMat::begin() const
+{
+ return SparseMatConstIterator_<_Tp>(this);
+}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp> SparseMat::end()
+{
+ SparseMatIterator_<_Tp> it(this);
+ it.seekEnd();
+ return it;
+}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp> SparseMat::end() const
+{
+ SparseMatConstIterator_<_Tp> it(this);
+ it.seekEnd();
+ return it;
+}
+
+
+
+///////////////////////////// SparseMat_ ////////////////////////////
+
+template<typename _Tp> inline
+SparseMat_<_Tp>::SparseMat_()
+{
+ flags = MAGIC_VAL | DataType<_Tp>::type;
+}
+
+template<typename _Tp> inline
+SparseMat_<_Tp>::SparseMat_(int _dims, const int* _sizes)
+ : SparseMat(_dims, _sizes, DataType<_Tp>::type)
+{}
+
+template<typename _Tp> inline
+SparseMat_<_Tp>::SparseMat_(const SparseMat& m)
+{
+ if( m.type() == DataType<_Tp>::type )
+ *this = (const SparseMat_<_Tp>&)m;
+ else
+ m.convertTo(*this, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+SparseMat_<_Tp>::SparseMat_(const SparseMat_<_Tp>& m)
+{
+ this->flags = m.flags;
+ this->hdr = m.hdr;
+ if( this->hdr )
+ CV_XADD(&this->hdr->refcount, 1);
+}
+
+template<typename _Tp> inline
+SparseMat_<_Tp>::SparseMat_(const Mat& m)
+{
+ SparseMat sm(m);
+ *this = sm;
+}
+
+template<typename _Tp> inline
+SparseMat_<_Tp>& SparseMat_<_Tp>::operator = (const SparseMat_<_Tp>& m)
+{
+ if( this != &m )
+ {
+ if( m.hdr ) CV_XADD(&m.hdr->refcount, 1);
+ release();
+ flags = m.flags;
+ hdr = m.hdr;
+ }
+ return *this;
+}
+
+template<typename _Tp> inline
+SparseMat_<_Tp>& SparseMat_<_Tp>::operator = (const SparseMat& m)
+{
+ if( m.type() == DataType<_Tp>::type )
+ return (*this = (const SparseMat_<_Tp>&)m);
+ m.convertTo(*this, DataType<_Tp>::type);
+ return *this;
+}
+
+template<typename _Tp> inline
+SparseMat_<_Tp>& SparseMat_<_Tp>::operator = (const Mat& m)
+{
+ return (*this = SparseMat(m));
+}
+
+template<typename _Tp> inline
+SparseMat_<_Tp> SparseMat_<_Tp>::clone() const
+{
+ SparseMat_<_Tp> m;
+ this->copyTo(m);
+ return m;
+}
+
+template<typename _Tp> inline
+void SparseMat_<_Tp>::create(int _dims, const int* _sizes)
+{
+ SparseMat::create(_dims, _sizes, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+int SparseMat_<_Tp>::type() const
+{
+ return DataType<_Tp>::type;
+}
+
+template<typename _Tp> inline
+int SparseMat_<_Tp>::depth() const
+{
+ return DataType<_Tp>::depth;
+}
+
+template<typename _Tp> inline
+int SparseMat_<_Tp>::channels() const
+{
+ return DataType<_Tp>::channels;
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat_<_Tp>::ref(int i0, size_t* hashval)
+{
+ return SparseMat::ref<_Tp>(i0, hashval);
+}
+
+template<typename _Tp> inline
+_Tp SparseMat_<_Tp>::operator()(int i0, size_t* hashval) const
+{
+ return SparseMat::value<_Tp>(i0, hashval);
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat_<_Tp>::ref(int i0, int i1, size_t* hashval)
+{
+ return SparseMat::ref<_Tp>(i0, i1, hashval);
+}
+
+template<typename _Tp> inline
+_Tp SparseMat_<_Tp>::operator()(int i0, int i1, size_t* hashval) const
+{
+ return SparseMat::value<_Tp>(i0, i1, hashval);
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat_<_Tp>::ref(int i0, int i1, int i2, size_t* hashval)
+{
+ return SparseMat::ref<_Tp>(i0, i1, i2, hashval);
+}
+
+template<typename _Tp> inline
+_Tp SparseMat_<_Tp>::operator()(int i0, int i1, int i2, size_t* hashval) const
+{
+ return SparseMat::value<_Tp>(i0, i1, i2, hashval);
+}
+
+template<typename _Tp> inline
+_Tp& SparseMat_<_Tp>::ref(const int* idx, size_t* hashval)
+{
+ return SparseMat::ref<_Tp>(idx, hashval);
+}
+
+template<typename _Tp> inline
+_Tp SparseMat_<_Tp>::operator()(const int* idx, size_t* hashval) const
+{
+ return SparseMat::value<_Tp>(idx, hashval);
+}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp> SparseMat_<_Tp>::begin()
+{
+ return SparseMatIterator_<_Tp>(this);
+}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp> SparseMat_<_Tp>::begin() const
+{
+ return SparseMatConstIterator_<_Tp>(this);
+}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp> SparseMat_<_Tp>::end()
+{
+ SparseMatIterator_<_Tp> it(this);
+ it.seekEnd();
+ return it;
+}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp> SparseMat_<_Tp>::end() const
+{
+ SparseMatConstIterator_<_Tp> it(this);
+ it.seekEnd();
+ return it;
+}
+
+
+
+////////////////////////// MatConstIterator /////////////////////////
+
+inline
+MatConstIterator::MatConstIterator()
+ : m(0), elemSize(0), ptr(0), sliceStart(0), sliceEnd(0)
+{}
+
+inline
+MatConstIterator::MatConstIterator(const Mat* _m)
+ : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0)
+{
+ if( m && m->isContinuous() )
+ {
+ sliceStart = m->data;
+ sliceEnd = sliceStart + m->total()*elemSize;
+ }
+ seek((const int*)0);
+}
+
+inline
+MatConstIterator::MatConstIterator(const Mat* _m, int _row, int _col)
+ : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0)
+{
+ CV_Assert(m && m->dims <= 2);
+ if( m->isContinuous() )
+ {
+ sliceStart = m->data;
+ sliceEnd = sliceStart + m->total()*elemSize;
+ }
+ int idx[] = {_row, _col};
+ seek(idx);
+}
+
+inline
+MatConstIterator::MatConstIterator(const Mat* _m, Point _pt)
+ : m(_m), elemSize(_m->elemSize()), ptr(0), sliceStart(0), sliceEnd(0)
+{
+ CV_Assert(m && m->dims <= 2);
+ if( m->isContinuous() )
+ {
+ sliceStart = m->data;
+ sliceEnd = sliceStart + m->total()*elemSize;
+ }
+ int idx[] = {_pt.y, _pt.x};
+ seek(idx);
+}
+
+inline
+MatConstIterator::MatConstIterator(const MatConstIterator& it)
+ : m(it.m), elemSize(it.elemSize), ptr(it.ptr), sliceStart(it.sliceStart), sliceEnd(it.sliceEnd)
+{}
+
+inline
+MatConstIterator& MatConstIterator::operator = (const MatConstIterator& it )
+{
+ m = it.m; elemSize = it.elemSize; ptr = it.ptr;
+ sliceStart = it.sliceStart; sliceEnd = it.sliceEnd;
+ return *this;
+}
+
+inline
+uchar* MatConstIterator::operator *() const
+{
+ return ptr;
+}
+
+inline MatConstIterator& MatConstIterator::operator += (ptrdiff_t ofs)
+{
+ if( !m || ofs == 0 )
+ return *this;
+ ptrdiff_t ofsb = ofs*elemSize;
+ ptr += ofsb;
+ if( ptr < sliceStart || sliceEnd <= ptr )
+ {
+ ptr -= ofsb;
+ seek(ofs, true);
+ }
+ return *this;
+}
+
+inline
+MatConstIterator& MatConstIterator::operator -= (ptrdiff_t ofs)
+{
+ return (*this += -ofs);
+}
+
+inline
+MatConstIterator& MatConstIterator::operator --()
+{
+ if( m && (ptr -= elemSize) < sliceStart )
+ {
+ ptr += elemSize;
+ seek(-1, true);
+ }
+ return *this;
+}
+
+inline
+MatConstIterator MatConstIterator::operator --(int)
+{
+ MatConstIterator b = *this;
+ *this += -1;
+ return b;
+}
+
+inline
+MatConstIterator& MatConstIterator::operator ++()
+{
+ if( m && (ptr += elemSize) >= sliceEnd )
+ {
+ ptr -= elemSize;
+ seek(1, true);
+ }
+ return *this;
+}
+
+inline MatConstIterator MatConstIterator::operator ++(int)
+{
+ MatConstIterator b = *this;
+ *this += 1;
+ return b;
+}
+
+
+static inline
+bool operator == (const MatConstIterator& a, const MatConstIterator& b)
+{
+ return a.m == b.m && a.ptr == b.ptr;
+}
+
+static inline
+bool operator != (const MatConstIterator& a, const MatConstIterator& b)
+{
+ return !(a == b);
+}
+
+static inline
+bool operator < (const MatConstIterator& a, const MatConstIterator& b)
+{
+ return a.ptr < b.ptr;
+}
+
+static inline
+bool operator > (const MatConstIterator& a, const MatConstIterator& b)
+{
+ return a.ptr > b.ptr;
+}
+
+static inline
+bool operator <= (const MatConstIterator& a, const MatConstIterator& b)
+{
+ return a.ptr <= b.ptr;
+}
+
+static inline
+bool operator >= (const MatConstIterator& a, const MatConstIterator& b)
+{
+ return a.ptr >= b.ptr;
+}
+
+static inline
+ptrdiff_t operator - (const MatConstIterator& b, const MatConstIterator& a)
+{
+ if( a.m != b.m )
+ return ((size_t)(-1) >> 1);
+ if( a.sliceEnd == b.sliceEnd )
+ return (b.ptr - a.ptr)/b.elemSize;
+
+ return b.lpos() - a.lpos();
+}
+
+static inline
+MatConstIterator operator + (const MatConstIterator& a, ptrdiff_t ofs)
+{
+ MatConstIterator b = a;
+ return b += ofs;
+}
+
+static inline
+MatConstIterator operator + (ptrdiff_t ofs, const MatConstIterator& a)
+{
+ MatConstIterator b = a;
+ return b += ofs;
+}
+
+static inline
+MatConstIterator operator - (const MatConstIterator& a, ptrdiff_t ofs)
+{
+ MatConstIterator b = a;
+ return b += -ofs;
+}
+
+
+inline
+uchar* MatConstIterator::operator [](ptrdiff_t i) const
+{
+ return *(*this + i);
+}
+
+
+
+///////////////////////// MatConstIterator_ /////////////////////////
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>::MatConstIterator_()
+{}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>::MatConstIterator_(const Mat_<_Tp>* _m)
+ : MatConstIterator(_m)
+{}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>::MatConstIterator_(const Mat_<_Tp>* _m, int _row, int _col)
+ : MatConstIterator(_m, _row, _col)
+{}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>::MatConstIterator_(const Mat_<_Tp>* _m, Point _pt)
+ : MatConstIterator(_m, _pt)
+{}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>::MatConstIterator_(const MatConstIterator_& it)
+ : MatConstIterator(it)
+{}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator = (const MatConstIterator_& it )
+{
+ MatConstIterator::operator = (it);
+ return *this;
+}
+
+template<typename _Tp> inline
+_Tp MatConstIterator_<_Tp>::operator *() const
+{
+ return *(_Tp*)(this->ptr);
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator += (ptrdiff_t ofs)
+{
+ MatConstIterator::operator += (ofs);
+ return *this;
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator -= (ptrdiff_t ofs)
+{
+ return (*this += -ofs);
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator --()
+{
+ MatConstIterator::operator --();
+ return *this;
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp> MatConstIterator_<_Tp>::operator --(int)
+{
+ MatConstIterator_ b = *this;
+ MatConstIterator::operator --();
+ return b;
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator ++()
+{
+ MatConstIterator::operator ++();
+ return *this;
+}
+
+template<typename _Tp> inline
+MatConstIterator_<_Tp> MatConstIterator_<_Tp>::operator ++(int)
+{
+ MatConstIterator_ b = *this;
+ MatConstIterator::operator ++();
+ return b;
+}
+
+
+template<typename _Tp> inline
+Point MatConstIterator_<_Tp>::pos() const
+{
+ if( !m )
+ return Point();
+ CV_DbgAssert( m->dims <= 2 );
+ if( m->isContinuous() )
+ {
+ ptrdiff_t ofs = (const _Tp*)ptr - (const _Tp*)m->data;
+ int y = (int)(ofs / m->cols);
+ int x = (int)(ofs - (ptrdiff_t)y * m->cols);
+ return Point(x, y);
+ }
+ else
+ {
+ ptrdiff_t ofs = (uchar*)ptr - m->data;
+ int y = (int)(ofs / m->step);
+ int x = (int)((ofs - y * m->step)/sizeof(_Tp));
+ return Point(x, y);
+ }
+}
+
+
+template<typename _Tp> static inline
+bool operator == (const MatConstIterator_<_Tp>& a, const MatConstIterator_<_Tp>& b)
+{
+ return a.m == b.m && a.ptr == b.ptr;
+}
+
+template<typename _Tp> static inline
+bool operator != (const MatConstIterator_<_Tp>& a, const MatConstIterator_<_Tp>& b)
+{
+ return a.m != b.m || a.ptr != b.ptr;
+}
+
+template<typename _Tp> static inline
+MatConstIterator_<_Tp> operator + (const MatConstIterator_<_Tp>& a, ptrdiff_t ofs)
+{
+ MatConstIterator t = (const MatConstIterator&)a + ofs;
+ return (MatConstIterator_<_Tp>&)t;
+}
+
+template<typename _Tp> static inline
+MatConstIterator_<_Tp> operator + (ptrdiff_t ofs, const MatConstIterator_<_Tp>& a)
+{
+ MatConstIterator t = (const MatConstIterator&)a + ofs;
+ return (MatConstIterator_<_Tp>&)t;
+}
+
+template<typename _Tp> static inline
+MatConstIterator_<_Tp> operator - (const MatConstIterator_<_Tp>& a, ptrdiff_t ofs)
+{
+ MatConstIterator t = (const MatConstIterator&)a - ofs;
+ return (MatConstIterator_<_Tp>&)t;
+}
+
+template<typename _Tp> inline
+_Tp MatConstIterator_<_Tp>::operator [](ptrdiff_t i) const
+{
+ return *(_Tp*)MatConstIterator::operator [](i);
+}
+
+
+
+//////////////////////////// MatIterator_ ///////////////////////////
+
+template<typename _Tp> inline
+MatIterator_<_Tp>::MatIterator_()
+ : MatConstIterator_<_Tp>()
+{}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m)
+ : MatConstIterator_<_Tp>(_m)
+{}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>::MatIterator_(Mat_<_Tp>* _m, int _row, int _col)
+ : MatConstIterator_<_Tp>(_m, _row, _col)
+{}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>::MatIterator_(const Mat_<_Tp>* _m, Point _pt)
+ : MatConstIterator_<_Tp>(_m, _pt)
+{}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>::MatIterator_(const Mat_<_Tp>* _m, const int* _idx)
+ : MatConstIterator_<_Tp>(_m, _idx)
+{}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>::MatIterator_(const MatIterator_& it)
+ : MatConstIterator_<_Tp>(it)
+{}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>& MatIterator_<_Tp>::operator = (const MatIterator_<_Tp>& it )
+{
+ MatConstIterator::operator = (it);
+ return *this;
+}
+
+template<typename _Tp> inline
+_Tp& MatIterator_<_Tp>::operator *() const
+{
+ return *(_Tp*)(this->ptr);
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>& MatIterator_<_Tp>::operator += (ptrdiff_t ofs)
+{
+ MatConstIterator::operator += (ofs);
+ return *this;
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>& MatIterator_<_Tp>::operator -= (ptrdiff_t ofs)
+{
+ MatConstIterator::operator += (-ofs);
+ return *this;
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>& MatIterator_<_Tp>::operator --()
+{
+ MatConstIterator::operator --();
+ return *this;
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp> MatIterator_<_Tp>::operator --(int)
+{
+ MatIterator_ b = *this;
+ MatConstIterator::operator --();
+ return b;
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp>& MatIterator_<_Tp>::operator ++()
+{
+ MatConstIterator::operator ++();
+ return *this;
+}
+
+template<typename _Tp> inline
+MatIterator_<_Tp> MatIterator_<_Tp>::operator ++(int)
+{
+ MatIterator_ b = *this;
+ MatConstIterator::operator ++();
+ return b;
+}
+
+template<typename _Tp> inline
+_Tp& MatIterator_<_Tp>::operator [](ptrdiff_t i) const
+{
+ return *(*this + i);
+}
+
+
+template<typename _Tp> static inline
+bool operator == (const MatIterator_<_Tp>& a, const MatIterator_<_Tp>& b)
+{
+ return a.m == b.m && a.ptr == b.ptr;
+}
+
+template<typename _Tp> static inline
+bool operator != (const MatIterator_<_Tp>& a, const MatIterator_<_Tp>& b)
+{
+ return a.m != b.m || a.ptr != b.ptr;
+}
+
+template<typename _Tp> static inline
+MatIterator_<_Tp> operator + (const MatIterator_<_Tp>& a, ptrdiff_t ofs)
+{
+ MatConstIterator t = (const MatConstIterator&)a + ofs;
+ return (MatIterator_<_Tp>&)t;
+}
+
+template<typename _Tp> static inline
+MatIterator_<_Tp> operator + (ptrdiff_t ofs, const MatIterator_<_Tp>& a)
+{
+ MatConstIterator t = (const MatConstIterator&)a + ofs;
+ return (MatIterator_<_Tp>&)t;
+}
+
+template<typename _Tp> static inline
+MatIterator_<_Tp> operator - (const MatIterator_<_Tp>& a, ptrdiff_t ofs)
+{
+ MatConstIterator t = (const MatConstIterator&)a - ofs;
+ return (MatIterator_<_Tp>&)t;
+}
+
+
+
+/////////////////////// SparseMatConstIterator //////////////////////
+
+inline
+SparseMatConstIterator::SparseMatConstIterator()
+ : m(0), hashidx(0), ptr(0)
+{}
+
+inline
+SparseMatConstIterator::SparseMatConstIterator(const SparseMatConstIterator& it)
+ : m(it.m), hashidx(it.hashidx), ptr(it.ptr)
+{}
+
+inline SparseMatConstIterator& SparseMatConstIterator::operator = (const SparseMatConstIterator& it)
+{
+ if( this != &it )
+ {
+ m = it.m;
+ hashidx = it.hashidx;
+ ptr = it.ptr;
+ }
+ return *this;
+}
+
+template<typename _Tp> inline
+const _Tp& SparseMatConstIterator::value() const
+{
+ return *(_Tp*)ptr;
+}
+
+inline
+const SparseMat::Node* SparseMatConstIterator::node() const
+{
+ return (ptr && m && m->hdr) ? (const SparseMat::Node*)(const void*)(ptr - m->hdr->valueOffset) : 0;
+}
+
+inline
+SparseMatConstIterator SparseMatConstIterator::operator ++(int)
+{
+ SparseMatConstIterator it = *this;
+ ++*this;
+ return it;
+}
+
+inline
+void SparseMatConstIterator::seekEnd()
+{
+ if( m && m->hdr )
+ {
+ hashidx = m->hdr->hashtab.size();
+ ptr = 0;
+ }
+}
+
+
+static inline
+bool operator == (const SparseMatConstIterator& it1, const SparseMatConstIterator& it2)
+{
+ return it1.m == it2.m && it1.ptr == it2.ptr;
+}
+
+static inline
+bool operator != (const SparseMatConstIterator& it1, const SparseMatConstIterator& it2)
+{
+ return !(it1 == it2);
+}
+
+
+
+///////////////////////// SparseMatIterator /////////////////////////
+
+inline
+SparseMatIterator::SparseMatIterator()
+{}
+
+inline
+SparseMatIterator::SparseMatIterator(SparseMat* _m)
+ : SparseMatConstIterator(_m)
+{}
+
+inline
+SparseMatIterator::SparseMatIterator(const SparseMatIterator& it)
+ : SparseMatConstIterator(it)
+{}
+
+inline
+SparseMatIterator& SparseMatIterator::operator = (const SparseMatIterator& it)
+{
+ (SparseMatConstIterator&)*this = it;
+ return *this;
+}
+
+template<typename _Tp> inline
+_Tp& SparseMatIterator::value() const
+{
+ return *(_Tp*)ptr;
+}
+
+inline
+SparseMat::Node* SparseMatIterator::node() const
+{
+ return (SparseMat::Node*)SparseMatConstIterator::node();
+}
+
+inline
+SparseMatIterator& SparseMatIterator::operator ++()
+{
+ SparseMatConstIterator::operator ++();
+ return *this;
+}
+
+inline
+SparseMatIterator SparseMatIterator::operator ++(int)
+{
+ SparseMatIterator it = *this;
+ ++*this;
+ return it;
+}
+
+
+
+////////////////////// SparseMatConstIterator_ //////////////////////
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp>::SparseMatConstIterator_()
+{}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMat_<_Tp>* _m)
+ : SparseMatConstIterator(_m)
+{}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMat* _m)
+ : SparseMatConstIterator(_m)
+{
+ CV_Assert( _m->type() == DataType<_Tp>::type );
+}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp>::SparseMatConstIterator_(const SparseMatConstIterator_<_Tp>& it)
+ : SparseMatConstIterator(it)
+{}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp>& SparseMatConstIterator_<_Tp>::operator = (const SparseMatConstIterator_<_Tp>& it)
+{
+ return reinterpret_cast<SparseMatConstIterator_<_Tp>&>
+ (*reinterpret_cast<SparseMatConstIterator*>(this) =
+ reinterpret_cast<const SparseMatConstIterator&>(it));
+}
+
+template<typename _Tp> inline
+const _Tp& SparseMatConstIterator_<_Tp>::operator *() const
+{
+ return *(const _Tp*)this->ptr;
+}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp>& SparseMatConstIterator_<_Tp>::operator ++()
+{
+ SparseMatConstIterator::operator ++();
+ return *this;
+}
+
+template<typename _Tp> inline
+SparseMatConstIterator_<_Tp> SparseMatConstIterator_<_Tp>::operator ++(int)
+{
- SparseMatIterator it = *this;
++ SparseMatConstIterator_<_Tp> it = *this;
+ SparseMatConstIterator::operator ++();
+ return it;
+}
+
+
+
+///////////////////////// SparseMatIterator_ ////////////////////////
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp>::SparseMatIterator_()
+{}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp>::SparseMatIterator_(SparseMat_<_Tp>* _m)
+ : SparseMatConstIterator_<_Tp>(_m)
+{}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp>::SparseMatIterator_(SparseMat* _m)
+ : SparseMatConstIterator_<_Tp>(_m)
+{}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp>::SparseMatIterator_(const SparseMatIterator_<_Tp>& it)
+ : SparseMatConstIterator_<_Tp>(it)
+{}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp>& SparseMatIterator_<_Tp>::operator = (const SparseMatIterator_<_Tp>& it)
+{
+ return reinterpret_cast<SparseMatIterator_<_Tp>&>
+ (*reinterpret_cast<SparseMatConstIterator*>(this) =
+ reinterpret_cast<const SparseMatConstIterator&>(it));
+}
+
+template<typename _Tp> inline
+_Tp& SparseMatIterator_<_Tp>::operator *() const
+{
+ return *(_Tp*)this->ptr;
+}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp>& SparseMatIterator_<_Tp>::operator ++()
+{
+ SparseMatConstIterator::operator ++();
+ return *this;
+}
+
+template<typename _Tp> inline
+SparseMatIterator_<_Tp> SparseMatIterator_<_Tp>::operator ++(int)
+{
++ SparseMatIterator_<_Tp> it = *this;
+ SparseMatConstIterator::operator ++();
+ return it;
+}
+
+
+
+//////////////////////// MatCommaInitializer_ ///////////////////////
+
+template<typename _Tp> inline
+MatCommaInitializer_<_Tp>::MatCommaInitializer_(Mat_<_Tp>* _m)
+ : it(_m)
+{}
+
+template<typename _Tp> template<typename T2> inline
+MatCommaInitializer_<_Tp>& MatCommaInitializer_<_Tp>::operator , (T2 v)
+{
+ CV_DbgAssert( this->it < ((const Mat_<_Tp>*)this->it.m)->end() );
+ *this->it = _Tp(v);
+ ++this->it;
+ return *this;
+}
+
+template<typename _Tp> inline
+MatCommaInitializer_<_Tp>::operator Mat_<_Tp>() const
+{
+ CV_DbgAssert( this->it == ((const Mat_<_Tp>*)this->it.m)->end() );
+ return Mat_<_Tp>(*this->it.m);
+}
+
+
+template<typename _Tp, typename T2> static inline
+MatCommaInitializer_<_Tp> operator << (const Mat_<_Tp>& m, T2 val)
+{
+ MatCommaInitializer_<_Tp> commaInitializer((Mat_<_Tp>*)&m);
+ return (commaInitializer, val);
+}
+
+
+
+///////////////////////// Matrix Expressions ////////////////////////
+
+inline
+Mat& Mat::operator = (const MatExpr& e)
+{
+ e.op->assign(e, *this);
+ return *this;
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const MatExpr& e)
+{
+ e.op->assign(e, *this, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+Mat_<_Tp>& Mat_<_Tp>::operator = (const MatExpr& e)
+{
+ e.op->assign(e, *this, DataType<_Tp>::type);
+ return *this;
+}
+
+template<typename _Tp> inline
+MatExpr Mat_<_Tp>::zeros(int rows, int cols)
+{
+ return Mat::zeros(rows, cols, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+MatExpr Mat_<_Tp>::zeros(Size sz)
+{
+ return Mat::zeros(sz, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+MatExpr Mat_<_Tp>::ones(int rows, int cols)
+{
+ return Mat::ones(rows, cols, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+MatExpr Mat_<_Tp>::ones(Size sz)
+{
+ return Mat::ones(sz, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+MatExpr Mat_<_Tp>::eye(int rows, int cols)
+{
+ return Mat::eye(rows, cols, DataType<_Tp>::type);
+}
+
+template<typename _Tp> inline
+MatExpr Mat_<_Tp>::eye(Size sz)
+{
+ return Mat::eye(sz, DataType<_Tp>::type);
+}
+
+inline
+MatExpr::MatExpr()
+ : op(0), flags(0), a(Mat()), b(Mat()), c(Mat()), alpha(0), beta(0), s()
+{}
+
+inline
+MatExpr::MatExpr(const MatOp* _op, int _flags, const Mat& _a, const Mat& _b,
+ const Mat& _c, double _alpha, double _beta, const Scalar& _s)
+ : op(_op), flags(_flags), a(_a), b(_b), c(_c), alpha(_alpha), beta(_beta), s(_s)
+{}
+
+inline
+MatExpr::operator Mat() const
+{
+ Mat m;
+ op->assign(*this, m);
+ return m;
+}
+
+template<typename _Tp> inline
+MatExpr::operator Mat_<_Tp>() const
+{
+ Mat_<_Tp> m;
+ op->assign(*this, m, DataType<_Tp>::type);
+ return m;
+}
+
+
+template<typename _Tp> static inline
+MatExpr min(const Mat_<_Tp>& a, const Mat_<_Tp>& b)
+{
+ return cv::min((const Mat&)a, (const Mat&)b);
+}
+
+template<typename _Tp> static inline
+MatExpr min(const Mat_<_Tp>& a, double s)
+{
+ return cv::min((const Mat&)a, s);
+}
+
+template<typename _Tp> static inline
+MatExpr min(double s, const Mat_<_Tp>& a)
+{
+ return cv::min((const Mat&)a, s);
+}
+
+template<typename _Tp> static inline
+MatExpr max(const Mat_<_Tp>& a, const Mat_<_Tp>& b)
+{
+ return cv::max((const Mat&)a, (const Mat&)b);
+}
+
+template<typename _Tp> static inline
+MatExpr max(const Mat_<_Tp>& a, double s)
+{
+ return cv::max((const Mat&)a, s);
+}
+
+template<typename _Tp> static inline
+MatExpr max(double s, const Mat_<_Tp>& a)
+{
+ return cv::max((const Mat&)a, s);
+}
+
+template<typename _Tp> static inline
+MatExpr abs(const Mat_<_Tp>& m)
+{
+ return cv::abs((const Mat&)m);
+}
+
+
+static inline
+Mat& operator += (Mat& a, const MatExpr& b)
+{
+ b.op->augAssignAdd(b, a);
+ return a;
+}
+
+static inline
+const Mat& operator += (const Mat& a, const MatExpr& b)
+{
+ b.op->augAssignAdd(b, (Mat&)a);
+ return a;
+}
+
+template<typename _Tp> static inline
+Mat_<_Tp>& operator += (Mat_<_Tp>& a, const MatExpr& b)
+{
+ b.op->augAssignAdd(b, a);
+ return a;
+}
+
+template<typename _Tp> static inline
+const Mat_<_Tp>& operator += (const Mat_<_Tp>& a, const MatExpr& b)
+{
+ b.op->augAssignAdd(b, (Mat&)a);
+ return a;
+}
+
+static inline
+Mat& operator -= (Mat& a, const MatExpr& b)
+{
+ b.op->augAssignSubtract(b, a);
+ return a;
+}
+
+static inline
+const Mat& operator -= (const Mat& a, const MatExpr& b)
+{
+ b.op->augAssignSubtract(b, (Mat&)a);
+ return a;
+}
+
+template<typename _Tp> static inline
+Mat_<_Tp>& operator -= (Mat_<_Tp>& a, const MatExpr& b)
+{
+ b.op->augAssignSubtract(b, a);
+ return a;
+}
+
+template<typename _Tp> static inline
+const Mat_<_Tp>& operator -= (const Mat_<_Tp>& a, const MatExpr& b)
+{
+ b.op->augAssignSubtract(b, (Mat&)a);
+ return a;
+}
+
+static inline
+Mat& operator *= (Mat& a, const MatExpr& b)
+{
+ b.op->augAssignMultiply(b, a);
+ return a;
+}
+
+static inline
+const Mat& operator *= (const Mat& a, const MatExpr& b)
+{
+ b.op->augAssignMultiply(b, (Mat&)a);
+ return a;
+}
+
+template<typename _Tp> static inline
+Mat_<_Tp>& operator *= (Mat_<_Tp>& a, const MatExpr& b)
+{
+ b.op->augAssignMultiply(b, a);
+ return a;
+}
+
+template<typename _Tp> static inline
+const Mat_<_Tp>& operator *= (const Mat_<_Tp>& a, const MatExpr& b)
+{
+ b.op->augAssignMultiply(b, (Mat&)a);
+ return a;
+}
+
+static inline
+Mat& operator /= (Mat& a, const MatExpr& b)
+{
+ b.op->augAssignDivide(b, a);
+ return a;
+}
+
+static inline
+const Mat& operator /= (const Mat& a, const MatExpr& b)
+{
+ b.op->augAssignDivide(b, (Mat&)a);
+ return a;
+}
+
+template<typename _Tp> static inline
+Mat_<_Tp>& operator /= (Mat_<_Tp>& a, const MatExpr& b)
+{
+ b.op->augAssignDivide(b, a);
+ return a;
+}
+
+template<typename _Tp> static inline
+const Mat_<_Tp>& operator /= (const Mat_<_Tp>& a, const MatExpr& b)
+{
+ b.op->augAssignDivide(b, (Mat&)a);
+ return a;
+}
+
+
+//////////////////////////////// UMat ////////////////////////////////
+
+inline
+UMat::UMat(UMatUsageFlags _usageFlags)
+: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
+{}
+
+inline
+UMat::UMat(int _rows, int _cols, int _type, UMatUsageFlags _usageFlags)
+: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
+{
+ create(_rows, _cols, _type);
+}
+
+inline
+UMat::UMat(int _rows, int _cols, int _type, const Scalar& _s, UMatUsageFlags _usageFlags)
+: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
+{
+ create(_rows, _cols, _type);
+ *this = _s;
+}
+
+inline
+UMat::UMat(Size _sz, int _type, UMatUsageFlags _usageFlags)
+: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
+{
+ create( _sz.height, _sz.width, _type );
+}
+
+inline
+UMat::UMat(Size _sz, int _type, const Scalar& _s, UMatUsageFlags _usageFlags)
+: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
+{
+ create(_sz.height, _sz.width, _type);
+ *this = _s;
+}
+
+inline
+UMat::UMat(int _dims, const int* _sz, int _type, UMatUsageFlags _usageFlags)
+: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
+{
+ create(_dims, _sz, _type);
+}
+
+inline
+UMat::UMat(int _dims, const int* _sz, int _type, const Scalar& _s, UMatUsageFlags _usageFlags)
+: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
+{
+ create(_dims, _sz, _type);
+ *this = _s;
+}
+
+inline
+UMat::UMat(const UMat& m)
+: flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), allocator(m.allocator),
+ usageFlags(m.usageFlags), u(m.u), offset(m.offset), size(&rows)
+{
+ addref();
+ if( m.dims <= 2 )
+ {
+ step[0] = m.step[0]; step[1] = m.step[1];
+ }
+ else
+ {
+ dims = 0;
+ copySize(m);
+ }
+}
+
+
+template<typename _Tp> inline
+UMat::UMat(const std::vector<_Tp>& vec, bool copyData)
+: flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()),
+cols(1), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows)
+{
+ if(vec.empty())
+ return;
+ if( !copyData )
+ {
+ // !!!TODO!!!
+ CV_Error(Error::StsNotImplemented, "");
+ }
+ else
+ Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this);
+}
+
+
+inline
+UMat& UMat::operator = (const UMat& m)
+{
+ if( this != &m )
+ {
+ const_cast<UMat&>(m).addref();
+ release();
+ flags = m.flags;
+ if( dims <= 2 && m.dims <= 2 )
+ {
+ dims = m.dims;
+ rows = m.rows;
+ cols = m.cols;
+ step[0] = m.step[0];
+ step[1] = m.step[1];
+ }
+ else
+ copySize(m);
+ allocator = m.allocator;
+ if (usageFlags == USAGE_DEFAULT)
+ usageFlags = m.usageFlags;
+ u = m.u;
+ offset = m.offset;
+ }
+ return *this;
+}
+
+inline
+UMat UMat::row(int y) const
+{
+ return UMat(*this, Range(y, y + 1), Range::all());
+}
+
+inline
+UMat UMat::col(int x) const
+{
+ return UMat(*this, Range::all(), Range(x, x + 1));
+}
+
+inline
+UMat UMat::rowRange(int startrow, int endrow) const
+{
+ return UMat(*this, Range(startrow, endrow), Range::all());
+}
+
+inline
+UMat UMat::rowRange(const Range& r) const
+{
+ return UMat(*this, r, Range::all());
+}
+
+inline
+UMat UMat::colRange(int startcol, int endcol) const
+{
+ return UMat(*this, Range::all(), Range(startcol, endcol));
+}
+
+inline
+UMat UMat::colRange(const Range& r) const
+{
+ return UMat(*this, Range::all(), r);
+}
+
+inline
+UMat UMat::clone() const
+{
+ UMat m;
+ copyTo(m);
+ return m;
+}
+
+inline
+void UMat::assignTo( UMat& m, int _type ) const
+{
+ if( _type < 0 )
+ m = *this;
+ else
+ convertTo(m, _type);
+}
+
+inline
+void UMat::create(int _rows, int _cols, int _type, UMatUsageFlags _usageFlags)
+{
+ _type &= TYPE_MASK;
+ if( dims <= 2 && rows == _rows && cols == _cols && type() == _type && u )
+ return;
+ int sz[] = {_rows, _cols};
+ create(2, sz, _type, _usageFlags);
+}
+
+inline
+void UMat::create(Size _sz, int _type, UMatUsageFlags _usageFlags)
+{
+ create(_sz.height, _sz.width, _type, _usageFlags);
+}
+
+inline
+void UMat::addref()
+{
+ if( u )
+ CV_XADD(&(u->urefcount), 1);
+}
+
+inline void UMat::release()
+{
+ if( u && CV_XADD(&(u->urefcount), -1) == 1 )
+ deallocate();
+ size.p[0] = 0;
+ u = 0;
+}
+
+inline
+UMat UMat::operator()( Range _rowRange, Range _colRange ) const
+{
+ return UMat(*this, _rowRange, _colRange);
+}
+
+inline
+UMat UMat::operator()( const Rect& roi ) const
+{
+ return UMat(*this, roi);
+}
+
+inline
+UMat UMat::operator()(const Range* ranges) const
+{
+ return UMat(*this, ranges);
+}
+
+inline
+bool UMat::isContinuous() const
+{
+ return (flags & CONTINUOUS_FLAG) != 0;
+}
+
+inline
+bool UMat::isSubmatrix() const
+{
+ return (flags & SUBMATRIX_FLAG) != 0;
+}
+
+inline
+size_t UMat::elemSize() const
+{
+ return dims > 0 ? step.p[dims - 1] : 0;
+}
+
+inline
+size_t UMat::elemSize1() const
+{
+ return CV_ELEM_SIZE1(flags);
+}
+
+inline
+int UMat::type() const
+{
+ return CV_MAT_TYPE(flags);
+}
+
+inline
+int UMat::depth() const
+{
+ return CV_MAT_DEPTH(flags);
+}
+
+inline
+int UMat::channels() const
+{
+ return CV_MAT_CN(flags);
+}
+
+inline
+size_t UMat::step1(int i) const
+{
+ return step.p[i] / elemSize1();
+}
+
+inline
+bool UMat::empty() const
+{
+ return u == 0 || total() == 0;
+}
+
+inline
+size_t UMat::total() const
+{
+ if( dims <= 2 )
+ return (size_t)rows * cols;
+ size_t p = 1;
+ for( int i = 0; i < dims; i++ )
+ p *= size[i];
+ return p;
+}
+
+inline bool UMatData::hostCopyObsolete() const { return (flags & HOST_COPY_OBSOLETE) != 0; }
+inline bool UMatData::deviceCopyObsolete() const { return (flags & DEVICE_COPY_OBSOLETE) != 0; }
+inline bool UMatData::copyOnMap() const { return (flags & COPY_ON_MAP) != 0; }
+inline bool UMatData::tempUMat() const { return (flags & TEMP_UMAT) != 0; }
+inline bool UMatData::tempCopiedUMat() const { return (flags & TEMP_COPIED_UMAT) == TEMP_COPIED_UMAT; }
+
+inline void UMatData::markHostCopyObsolete(bool flag)
+{
+ if(flag)
+ flags |= HOST_COPY_OBSOLETE;
+ else
+ flags &= ~HOST_COPY_OBSOLETE;
+}
+inline void UMatData::markDeviceCopyObsolete(bool flag)
+{
+ if(flag)
+ flags |= DEVICE_COPY_OBSOLETE;
+ else
+ flags &= ~DEVICE_COPY_OBSOLETE;
+}
+
+inline UMatDataAutoLock::UMatDataAutoLock(UMatData* _u) : u(_u) { u->lock(); }
+inline UMatDataAutoLock::~UMatDataAutoLock() { u->unlock(); }
+
+} //cv
+
+#endif
--- /dev/null
- class CV_EXPORTS BOWTrainer
+/*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, 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*/
+
+#ifndef __OPENCV_FEATURES_2D_HPP__
+#define __OPENCV_FEATURES_2D_HPP__
+
+#include "opencv2/core.hpp"
+#include "opencv2/flann/miniflann.hpp"
+
+namespace cv
+{
+
+CV_EXPORTS bool initModule_features2d();
+
+// //! writes vector of keypoints to the file storage
+// CV_EXPORTS void write(FileStorage& fs, const String& name, const std::vector<KeyPoint>& keypoints);
+// //! reads vector of keypoints from the specified file storage node
+// CV_EXPORTS void read(const FileNode& node, CV_OUT std::vector<KeyPoint>& keypoints);
+
+/*
+ * A class filters a vector of keypoints.
+ * Because now it is difficult to provide a convenient interface for all usage scenarios of the keypoints filter class,
+ * it has only several needed by now static methods.
+ */
+class CV_EXPORTS KeyPointsFilter
+{
+public:
+ KeyPointsFilter(){}
+
+ /*
+ * Remove keypoints within borderPixels of an image edge.
+ */
+ static void runByImageBorder( std::vector<KeyPoint>& keypoints, Size imageSize, int borderSize );
+ /*
+ * Remove keypoints of sizes out of range.
+ */
+ static void runByKeypointSize( std::vector<KeyPoint>& keypoints, float minSize,
+ float maxSize=FLT_MAX );
+ /*
+ * Remove keypoints from some image by mask for pixels of this image.
+ */
+ static void runByPixelsMask( std::vector<KeyPoint>& keypoints, const Mat& mask );
+ /*
+ * Remove duplicated keypoints.
+ */
+ static void removeDuplicated( std::vector<KeyPoint>& keypoints );
+
+ /*
+ * Retain the specified number of the best keypoints (according to the response)
+ */
+ static void retainBest( std::vector<KeyPoint>& keypoints, int npoints );
+};
+
+
+/************************************ Base Classes ************************************/
+
+/*
+ * Abstract base class for 2D image feature detectors.
+ */
+class CV_EXPORTS_W FeatureDetector : public virtual Algorithm
+{
+public:
+ virtual ~FeatureDetector();
+
+ /*
+ * Detect keypoints in an image.
+ * image The image.
+ * keypoints The detected keypoints.
+ * mask Mask specifying where to look for keypoints (optional). Must be a char
+ * matrix with non-zero values in the region of interest.
+ */
+ CV_WRAP void detect( InputArray image, CV_OUT std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+
+ /*
+ * Detect keypoints in an image set.
+ * images Image collection.
+ * keypoints Collection of keypoints detected in an input images. keypoints[i] is a set of keypoints detected in an images[i].
+ * masks Masks for image set. masks[i] is a mask for images[i].
+ */
+ void detect( InputArrayOfArrays images, std::vector<std::vector<KeyPoint> >& keypoints, InputArrayOfArrays masks=noArray() ) const;
+
+ // Return true if detector object is empty
+ CV_WRAP virtual bool empty() const;
+
+ // Create feature detector by detector name.
+ CV_WRAP static Ptr<FeatureDetector> create( const String& detectorType );
+
+protected:
+ virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const = 0;
+
+ /*
+ * Remove keypoints that are not in the mask.
+ * Helper function, useful when wrapping a library call for keypoint detection that
+ * does not support a mask argument.
+ */
+ static void removeInvalidPoints( const Mat & mask, std::vector<KeyPoint>& keypoints );
+};
+
+
+/*
+ * Abstract base class for computing descriptors for image keypoints.
+ *
+ * In this interface we assume a keypoint descriptor can be represented as a
+ * dense, fixed-dimensional vector of some basic type. Most descriptors used
+ * in practice follow this pattern, as it makes it very easy to compute
+ * distances between descriptors. Therefore we represent a collection of
+ * descriptors as a Mat, where each row is one keypoint descriptor.
+ */
+class CV_EXPORTS_W DescriptorExtractor : public virtual Algorithm
+{
+public:
+ virtual ~DescriptorExtractor();
+
+ /*
+ * Compute the descriptors for a set of keypoints in an image.
+ * image The image.
+ * keypoints The input keypoints. Keypoints for which a descriptor cannot be computed are removed.
+ * descriptors Copmputed descriptors. Row i is the descriptor for keypoint i.
+ */
+ CV_WRAP void compute( InputArray image, CV_OUT CV_IN_OUT std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
+
+ /*
+ * Compute the descriptors for a keypoints collection detected in image collection.
+ * images Image collection.
+ * keypoints Input keypoints collection. keypoints[i] is keypoints detected in images[i].
+ * Keypoints for which a descriptor cannot be computed are removed.
+ * descriptors Descriptor collection. descriptors[i] are descriptors computed for set keypoints[i].
+ */
+ void compute( InputArrayOfArrays images, std::vector<std::vector<KeyPoint> >& keypoints, OutputArrayOfArrays descriptors ) const;
+
+ CV_WRAP virtual int descriptorSize() const = 0;
+ CV_WRAP virtual int descriptorType() const = 0;
+ CV_WRAP virtual int defaultNorm() const = 0;
+
+ CV_WRAP virtual bool empty() const;
+
+ CV_WRAP static Ptr<DescriptorExtractor> create( const String& descriptorExtractorType );
+
+protected:
+ virtual void computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const = 0;
+
+ /*
+ * Remove keypoints within borderPixels of an image edge.
+ */
+ static void removeBorderKeypoints( std::vector<KeyPoint>& keypoints,
+ Size imageSize, int borderSize );
+};
+
+
+
+/*
+ * Abstract base class for simultaneous 2D feature detection descriptor extraction.
+ */
+class CV_EXPORTS_W Feature2D : public FeatureDetector, public DescriptorExtractor
+{
+public:
+ /*
+ * Detect keypoints in an image.
+ * image The image.
+ * keypoints The detected keypoints.
+ * mask Mask specifying where to look for keypoints (optional). Must be a char
+ * matrix with non-zero values in the region of interest.
+ * useProvidedKeypoints If true, the method will skip the detection phase and will compute
+ * descriptors for the provided keypoints
+ */
+ CV_WRAP_AS(detectAndCompute) virtual void operator()( InputArray image, InputArray mask,
+ CV_OUT std::vector<KeyPoint>& keypoints,
+ OutputArray descriptors,
+ bool useProvidedKeypoints=false ) const = 0;
+
+ CV_WRAP void compute( InputArray image, CV_OUT CV_IN_OUT std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
+
+ // Create feature detector and descriptor extractor by name.
+ CV_WRAP static Ptr<Feature2D> create( const String& name );
+};
+
+/*!
+ BRISK implementation
+*/
+class CV_EXPORTS_W BRISK : public Feature2D
+{
+public:
+ CV_WRAP explicit BRISK(int thresh=30, int octaves=3, float patternScale=1.0f);
+
+ virtual ~BRISK();
+
+ // returns the descriptor size in bytes
+ int descriptorSize() const;
+ // returns the descriptor type
+ int descriptorType() const;
+ // returns the default norm type
+ int defaultNorm() const;
+
+ // Compute the BRISK features on an image
+ void operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
+
+ // Compute the BRISK features and descriptors on an image
+ void operator()( InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
+ OutputArray descriptors, bool useProvidedKeypoints=false ) const;
+
+ AlgorithmInfo* info() const;
+
+ // custom setup
+ CV_WRAP explicit BRISK(std::vector<float> &radiusList, std::vector<int> &numberList,
+ float dMax=5.85f, float dMin=8.2f, std::vector<int> indexChange=std::vector<int>());
+
+ // call this to generate the kernel:
+ // circle of radius r (pixels), with n points;
+ // short pairings with dMax, long pairings with dMin
+ CV_WRAP void generateKernel(std::vector<float> &radiusList,
+ std::vector<int> &numberList, float dMax=5.85f, float dMin=8.2f,
+ std::vector<int> indexChange=std::vector<int>());
+
+protected:
+
+ void computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
+ void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+
+ void computeKeypointsNoOrientation(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
+ void computeDescriptorsAndOrOrientation(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
+ OutputArray descriptors, bool doDescriptors, bool doOrientation,
+ bool useProvidedKeypoints) const;
+
+ // Feature parameters
+ CV_PROP_RW int threshold;
+ CV_PROP_RW int octaves;
+
+ // some helper structures for the Brisk pattern representation
+ struct BriskPatternPoint{
+ float x; // x coordinate relative to center
+ float y; // x coordinate relative to center
+ float sigma; // Gaussian smoothing sigma
+ };
+ struct BriskShortPair{
+ unsigned int i; // index of the first pattern point
+ unsigned int j; // index of other pattern point
+ };
+ struct BriskLongPair{
+ unsigned int i; // index of the first pattern point
+ unsigned int j; // index of other pattern point
+ int weighted_dx; // 1024.0/dx
+ int weighted_dy; // 1024.0/dy
+ };
+ inline int smoothedIntensity(const cv::Mat& image,
+ const cv::Mat& integral,const float key_x,
+ const float key_y, const unsigned int scale,
+ const unsigned int rot, const unsigned int point) const;
+ // pattern properties
+ BriskPatternPoint* patternPoints_; //[i][rotation][scale]
+ unsigned int points_; // total number of collocation points
+ float* scaleList_; // lists the scaling per scale index [scale]
+ unsigned int* sizeList_; // lists the total pattern size per scale index [scale]
+ static const unsigned int scales_; // scales discretization
+ static const float scalerange_; // span of sizes 40->4 Octaves - else, this needs to be adjusted...
+ static const unsigned int n_rot_; // discretization of the rotation look-up
+
+ // pairs
+ int strings_; // number of uchars the descriptor consists of
+ float dMax_; // short pair maximum distance
+ float dMin_; // long pair maximum distance
+ BriskShortPair* shortPairs_; // d<_dMax
+ BriskLongPair* longPairs_; // d>_dMin
+ unsigned int noShortPairs_; // number of shortParis
+ unsigned int noLongPairs_; // number of longParis
+
+ // general
+ static const float basicSize_;
+};
+
+
+/*!
+ ORB implementation.
+*/
+class CV_EXPORTS_W ORB : public Feature2D
+{
+public:
+ // the size of the signature in bytes
+ enum { kBytes = 32, HARRIS_SCORE=0, FAST_SCORE=1 };
+
+ CV_WRAP explicit ORB(int nfeatures = 500, float scaleFactor = 1.2f, int nlevels = 8, int edgeThreshold = 31,
+ int firstLevel = 0, int WTA_K=2, int scoreType=ORB::HARRIS_SCORE, int patchSize=31 );
+
+ // returns the descriptor size in bytes
+ int descriptorSize() const;
+ // returns the descriptor type
+ int descriptorType() const;
+ // returns the default norm type
+ int defaultNorm() const;
+
+ // Compute the ORB features and descriptors on an image
+ void operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
+
+ // Compute the ORB features and descriptors on an image
+ void operator()( InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
+ OutputArray descriptors, bool useProvidedKeypoints=false ) const;
+
+ AlgorithmInfo* info() const;
+
+protected:
+
+ void computeImpl( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors ) const;
+ void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+
+ CV_PROP_RW int nfeatures;
+ CV_PROP_RW double scaleFactor;
+ CV_PROP_RW int nlevels;
+ CV_PROP_RW int edgeThreshold;
+ CV_PROP_RW int firstLevel;
+ CV_PROP_RW int WTA_K;
+ CV_PROP_RW int scoreType;
+ CV_PROP_RW int patchSize;
+};
+
+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.
+
+ The class implements MSER algorithm introduced by J. Matas.
+ Unlike SIFT, SURF and many other detectors in OpenCV, this is salient region detector,
+ not the salient point detector.
+
+ It returns the regions, each of those is encoded as a contour.
+*/
+class CV_EXPORTS_W MSER : public FeatureDetector
+{
+public:
+ //! the full constructor
+ CV_WRAP explicit MSER( int _delta=5, int _min_area=60, int _max_area=14400,
+ double _max_variation=0.25, double _min_diversity=.2,
+ int _max_evolution=200, double _area_threshold=1.01,
+ double _min_margin=0.003, int _edge_blur_size=5 );
+
+ //! the operator that extracts the MSERs from the image or the specific part of it
+ CV_WRAP_AS(detect) void operator()( InputArray image, CV_OUT std::vector<std::vector<Point> >& msers,
+ InputArray mask=noArray() ) const;
+ AlgorithmInfo* info() const;
+
+protected:
+ void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+
+ int delta;
+ int minArea;
+ int maxArea;
+ double maxVariation;
+ double minDiversity;
+ int maxEvolution;
+ double areaThreshold;
+ double minMargin;
+ int edgeBlurSize;
+};
+
+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 );
+
+CV_EXPORTS void FAST( InputArray image, CV_OUT std::vector<KeyPoint>& keypoints,
+ int threshold, bool nonmaxSuppression, int type );
+
+class CV_EXPORTS_W FastFeatureDetector : public FeatureDetector
+{
+public:
+ enum Type
+ {
+ TYPE_5_8 = 0, TYPE_7_12 = 1, TYPE_9_16 = 2
+ };
+
+ CV_WRAP FastFeatureDetector( int threshold=10, bool nonmaxSuppression=true);
+ CV_WRAP FastFeatureDetector( int threshold, bool nonmaxSuppression, int type);
+ AlgorithmInfo* info() const;
+
+protected:
+ virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+
+ int threshold;
+ bool nonmaxSuppression;
+ int type;
+};
+
+
+class CV_EXPORTS_W GFTTDetector : public FeatureDetector
+{
+public:
+ CV_WRAP GFTTDetector( int maxCorners=1000, double qualityLevel=0.01, double minDistance=1,
+ int blockSize=3, bool useHarrisDetector=false, double k=0.04 );
+ AlgorithmInfo* info() const;
+
+protected:
+ virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+
+ int nfeatures;
+ double qualityLevel;
+ double minDistance;
+ int blockSize;
+ bool useHarrisDetector;
+ double k;
+};
+
+typedef GFTTDetector GoodFeaturesToTrackDetector;
+typedef StarDetector StarFeatureDetector;
+
+class CV_EXPORTS_W SimpleBlobDetector : public FeatureDetector
+{
+public:
+ struct CV_EXPORTS_W_SIMPLE Params
+ {
+ CV_WRAP Params();
+ CV_PROP_RW float thresholdStep;
+ CV_PROP_RW float minThreshold;
+ CV_PROP_RW float maxThreshold;
+ CV_PROP_RW size_t minRepeatability;
+ CV_PROP_RW float minDistBetweenBlobs;
+
+ CV_PROP_RW bool filterByColor;
+ CV_PROP_RW uchar blobColor;
+
+ CV_PROP_RW bool filterByArea;
+ CV_PROP_RW float minArea, maxArea;
+
+ CV_PROP_RW bool filterByCircularity;
+ CV_PROP_RW float minCircularity, maxCircularity;
+
+ CV_PROP_RW bool filterByInertia;
+ CV_PROP_RW float minInertiaRatio, maxInertiaRatio;
+
+ CV_PROP_RW bool filterByConvexity;
+ CV_PROP_RW float minConvexity, maxConvexity;
+
+ void read( const FileNode& fn );
+ void write( FileStorage& fs ) const;
+ };
+
+ CV_WRAP SimpleBlobDetector(const SimpleBlobDetector::Params ¶meters = SimpleBlobDetector::Params());
+
+ virtual void read( const FileNode& fn );
+ virtual void write( FileStorage& fs ) const;
+
+protected:
+ struct CV_EXPORTS Center
+ {
+ Point2d location;
+ double radius;
+ double confidence;
+ };
+
+ virtual void detectImpl( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() ) const;
+ virtual void findBlobs(InputArray image, InputArray binaryImage, std::vector<Center> ¢ers) const;
+
+ Params params;
+ AlgorithmInfo* info() const;
+};
+
+
+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 implementation
+*/
+class CV_EXPORTS_W KAZE : public Feature2D
+{
+public:
+ CV_WRAP KAZE();
+ CV_WRAP explicit KAZE(bool extended, bool upright);
+
+ virtual ~KAZE();
+
+ // returns the descriptor size in bytes
+ int descriptorSize() const;
+ // returns the descriptor type
+ int descriptorType() const;
+ // returns the default norm type
+ int defaultNorm() const;
+
+ AlgorithmInfo* info() const;
+
+ // Compute the KAZE features on an image
+ void operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
+
+ // Compute the KAZE features and descriptors on an image
+ void operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
+ OutputArray descriptors, bool useProvidedKeypoints = false) const;
+
+protected:
+ void detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const;
+ void computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const;
+
+ CV_PROP bool extended;
+ CV_PROP bool upright;
+};
+
+/*!
+AKAZE implementation
+*/
+class CV_EXPORTS_W AKAZE : public Feature2D
+{
+public:
+ /// AKAZE Descriptor Type
+ enum DESCRIPTOR_TYPE {
+ DESCRIPTOR_KAZE_UPRIGHT = 2, ///< Upright descriptors, not invariant to rotation
+ DESCRIPTOR_KAZE = 3,
+ DESCRIPTOR_MLDB_UPRIGHT = 4, ///< Upright descriptors, not invariant to rotation
+ DESCRIPTOR_MLDB = 5
+ };
+
+ CV_WRAP AKAZE();
+ explicit AKAZE(DESCRIPTOR_TYPE descriptor_type, int descriptor_size = 0, int descriptor_channels = 3);
+
+ virtual ~AKAZE();
+
+ // returns the descriptor size in bytes
+ int descriptorSize() const;
+ // returns the descriptor type
+ int descriptorType() const;
+ // returns the default norm type
+ int defaultNorm() const;
+
+ // Compute the AKAZE features on an image
+ void operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
+
+ // Compute the AKAZE features and descriptors on an image
+ void operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
+ OutputArray descriptors, bool useProvidedKeypoints = false) const;
+
+ AlgorithmInfo* info() const;
+
+protected:
+
+ void computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const;
+ void detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask = noArray()) const;
+
+ CV_PROP int descriptor;
+ CV_PROP int descriptor_channels;
+ CV_PROP int descriptor_size;
+
+};
+/****************************************************************************************\
+* Distance *
+\****************************************************************************************/
+
+template<typename T>
+struct CV_EXPORTS Accumulator
+{
+ typedef T Type;
+};
+
+template<> struct Accumulator<unsigned char> { typedef float Type; };
+template<> struct Accumulator<unsigned short> { typedef float Type; };
+template<> struct Accumulator<char> { typedef float Type; };
+template<> struct Accumulator<short> { typedef float Type; };
+
+/*
+ * Squared Euclidean distance functor
+ */
+template<class T>
+struct CV_EXPORTS SL2
+{
+ enum { normType = NORM_L2SQR };
+ typedef T ValueType;
+ typedef typename Accumulator<T>::Type ResultType;
+
+ ResultType operator()( const T* a, const T* b, int size ) const
+ {
+ return normL2Sqr<ValueType, ResultType>(a, b, size);
+ }
+};
+
+/*
+ * Euclidean distance functor
+ */
+template<class T>
+struct CV_EXPORTS L2
+{
+ enum { normType = NORM_L2 };
+ typedef T ValueType;
+ typedef typename Accumulator<T>::Type ResultType;
+
+ ResultType operator()( const T* a, const T* b, int size ) const
+ {
+ return (ResultType)std::sqrt((double)normL2Sqr<ValueType, ResultType>(a, b, size));
+ }
+};
+
+/*
+ * Manhattan distance (city block distance) functor
+ */
+template<class T>
+struct CV_EXPORTS L1
+{
+ enum { normType = NORM_L1 };
+ typedef T ValueType;
+ typedef typename Accumulator<T>::Type ResultType;
+
+ ResultType operator()( const T* a, const T* b, int size ) const
+ {
+ return normL1<ValueType, ResultType>(a, b, size);
+ }
+};
+
+/*
+ * Hamming distance functor - counts the bit differences between two strings - useful for the Brief descriptor
+ * bit count of A exclusive XOR'ed with B
+ */
+struct CV_EXPORTS Hamming
+{
+ enum { normType = NORM_HAMMING };
+ typedef unsigned char ValueType;
+ typedef int ResultType;
+
+ /** this will count the bits in a ^ b
+ */
+ ResultType operator()( const unsigned char* a, const unsigned char* b, int size ) const
+ {
+ return normHamming(a, b, size);
+ }
+};
+
+typedef Hamming HammingLUT;
+
+template<int cellsize> struct HammingMultilevel
+{
+ enum { normType = NORM_HAMMING + (cellsize>1) };
+ typedef unsigned char ValueType;
+ typedef int ResultType;
+
+ ResultType operator()( const unsigned char* a, const unsigned char* b, int size ) const
+ {
+ return normHamming(a, b, size, cellsize);
+ }
+};
+
+/****************************************************************************************\
+* DescriptorMatcher *
+\****************************************************************************************/
+/*
+ * Abstract base class for matching two sets of descriptors.
+ */
+class CV_EXPORTS_W DescriptorMatcher : public Algorithm
+{
+public:
+ virtual ~DescriptorMatcher();
+
+ /*
+ * Add descriptors to train descriptor collection.
+ * descriptors Descriptors to add. Each descriptors[i] is a descriptors set from one image.
+ */
+ CV_WRAP virtual void add( InputArrayOfArrays descriptors );
+ /*
+ * Get train descriptors collection.
+ */
+ CV_WRAP const std::vector<Mat>& getTrainDescriptors() const;
+ /*
+ * Clear train descriptors collection.
+ */
+ CV_WRAP virtual void clear();
+
+ /*
+ * Return true if there are not train descriptors in collection.
+ */
+ CV_WRAP virtual bool empty() const;
+ /*
+ * Return true if the matcher supports mask in match methods.
+ */
+ CV_WRAP virtual bool isMaskSupported() const = 0;
+
+ /*
+ * Train matcher (e.g. train flann index).
+ * In all methods to match the method train() is run every time before matching.
+ * Some descriptor matchers (e.g. BruteForceMatcher) have empty implementation
+ * of this method, other matchers really train their inner structures
+ * (e.g. FlannBasedMatcher trains flann::Index). So nonempty implementation
+ * of train() should check the class object state and do traing/retraining
+ * only if the state requires that (e.g. FlannBasedMatcher trains flann::Index
+ * if it has not trained yet or if new descriptors have been added to the train
+ * collection).
+ */
+ CV_WRAP virtual void train();
+ /*
+ * Group of methods to match descriptors from image pair.
+ * Method train() is run in this methods.
+ */
+ // Find one best match for each query descriptor (if mask is empty).
+ CV_WRAP void match( InputArray queryDescriptors, InputArray trainDescriptors,
+ CV_OUT std::vector<DMatch>& matches, InputArray mask=noArray() ) const;
+ // Find k best matches for each query descriptor (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.
+ CV_WRAP void knnMatch( InputArray queryDescriptors, InputArray trainDescriptors,
+ CV_OUT 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 queryDescriptors, InputArray trainDescriptors,
+ std::vector<std::vector<DMatch> >& matches, float maxDistance,
+ InputArray mask=noArray(), bool compactResult=false ) const;
+ /*
+ * Group of methods to match descriptors from one image to image set.
+ * See description of similar methods for matching image pair above.
+ */
+ CV_WRAP void match( InputArray queryDescriptors, CV_OUT std::vector<DMatch>& matches,
+ InputArrayOfArrays masks=noArray() );
+ CV_WRAP void knnMatch( InputArray queryDescriptors, CV_OUT std::vector<std::vector<DMatch> >& matches, int k,
+ InputArrayOfArrays masks=noArray(), bool compactResult=false );
+ void radiusMatch( InputArray queryDescriptors, 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& );
+ // Writes matcher object to a file storage
+ virtual void write( FileStorage& ) 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<DescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
+
+ CV_WRAP static Ptr<DescriptorMatcher> create( const String& descriptorMatcherType );
+protected:
+ /*
+ * Class to work with descriptors from several images as with one merged matrix.
+ * It is used e.g. in FlannBasedMatcher.
+ */
+ class CV_EXPORTS DescriptorCollection
+ {
+ public:
+ DescriptorCollection();
+ DescriptorCollection( const DescriptorCollection& collection );
+ virtual ~DescriptorCollection();
+
+ // Vector of matrices "descriptors" will be merged to one matrix "mergedDescriptors" here.
+ void set( const std::vector<Mat>& descriptors );
+ virtual void clear();
+
+ const Mat& getDescriptors() const;
+ const Mat getDescriptor( int imgIdx, int localDescIdx ) const;
+ const Mat getDescriptor( int globalDescIdx ) const;
+ void getLocalIdx( int globalDescIdx, int& imgIdx, int& localDescIdx ) const;
+
+ int size() const;
+
+ protected:
+ Mat mergedDescriptors;
+ std::vector<int> startIdxs;
+ };
+
+ // 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 queryDescriptors, std::vector<std::vector<DMatch> >& matches, int k,
+ InputArrayOfArrays masks=noArray(), bool compactResult=false ) = 0;
+ virtual void radiusMatchImpl( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
+ InputArrayOfArrays masks=noArray(), bool compactResult=false ) = 0;
+
+ static bool isPossibleMatch( InputArray mask, int queryIdx, int trainIdx );
+ static bool isMaskedOut( InputArrayOfArrays masks, int queryIdx );
+
+ static Mat clone_op( Mat m ) { return m.clone(); }
+ void checkMasks( InputArrayOfArrays masks, int queryDescriptorsCount ) const;
+
+ // Collection of descriptors from train images.
+ std::vector<Mat> trainDescCollection;
+ std::vector<UMat> utrainDescCollection;
+};
+
+/*
+ * Brute-force descriptor matcher.
+ *
+ * For each descriptor in the first set, this matcher finds the closest
+ * descriptor in the second set by trying each one.
+ *
+ * For efficiency, BruteForceMatcher is templated on the distance metric.
+ * For float descriptors, a common choice would be cv::L2<float>.
+ */
+class CV_EXPORTS_W BFMatcher : public DescriptorMatcher
+{
+public:
+ CV_WRAP BFMatcher( int normType=NORM_L2, bool crossCheck=false );
+ virtual ~BFMatcher() {}
+
+ virtual bool isMaskSupported() const { return true; }
+
+ virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
+
+ AlgorithmInfo* info() const;
+protected:
+ virtual void knnMatchImpl( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, int k,
+ InputArrayOfArrays masks=noArray(), bool compactResult=false );
+ virtual void radiusMatchImpl( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
+ InputArrayOfArrays masks=noArray(), bool compactResult=false );
+
+ int normType;
+ bool crossCheck;
+};
+
+
+/*
+ * Flann based matcher
+ */
+class CV_EXPORTS_W FlannBasedMatcher : public DescriptorMatcher
+{
+public:
+ CV_WRAP FlannBasedMatcher( const Ptr<flann::IndexParams>& indexParams=makePtr<flann::KDTreeIndexParams>(),
+ const Ptr<flann::SearchParams>& searchParams=makePtr<flann::SearchParams>() );
+
+ virtual void add( InputArrayOfArrays descriptors );
+ virtual void clear();
+
+ // Reads matcher object from a file node
+ virtual void read( const FileNode& );
+ // Writes matcher object to a file storage
+ virtual void write( FileStorage& ) const;
+
+ virtual void train();
+ virtual bool isMaskSupported() const;
+
+ virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
+
+ AlgorithmInfo* info() const;
+protected:
+ static void convertToDMatches( const DescriptorCollection& descriptors,
+ const Mat& indices, const Mat& distances,
+ std::vector<std::vector<DMatch> >& matches );
+
+ virtual void knnMatchImpl( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, int k,
+ InputArrayOfArrays masks=noArray(), bool compactResult=false );
+ virtual void radiusMatchImpl( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
+ InputArrayOfArrays masks=noArray(), bool compactResult=false );
+
+ Ptr<flann::IndexParams> indexParams;
+ Ptr<flann::SearchParams> searchParams;
+ Ptr<flann::Index> flannIndex;
+
+ DescriptorCollection mergedDescriptors;
+ 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 ¶msFilename=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 *
+\****************************************************************************************/
+struct CV_EXPORTS DrawMatchesFlags
+{
+ enum{ DEFAULT = 0, // Output image matrix will be created (Mat::create),
+ // i.e. existing memory of output image may be reused.
+ // Two source image, matches and single keypoints will be drawn.
+ // For each keypoint only the center point will be drawn (without
+ // the circle around keypoint with keypoint size and orientation).
+ DRAW_OVER_OUTIMG = 1, // Output image matrix will not be created (Mat::create).
+ // Matches will be drawn on existing content of output image.
+ NOT_DRAW_SINGLE_POINTS = 2, // Single keypoints will not be drawn.
+ DRAW_RICH_KEYPOINTS = 4 // For each keypoint the circle around keypoint with keypoint size and
+ // orientation will be drawn.
+ };
+};
+
+// Draw keypoints.
+CV_EXPORTS_W void drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints, InputOutputArray outImage,
+ const Scalar& color=Scalar::all(-1), int flags=DrawMatchesFlags::DEFAULT );
+
+// Draws matches of keypints from two images on output image.
+CV_EXPORTS_W void drawMatches( InputArray img1, const std::vector<KeyPoint>& keypoints1,
+ InputArray img2, const std::vector<KeyPoint>& keypoints2,
+ const std::vector<DMatch>& matches1to2, InputOutputArray outImg,
+ const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
+ const std::vector<char>& matchesMask=std::vector<char>(), int flags=DrawMatchesFlags::DEFAULT );
+
+CV_EXPORTS_AS(drawMatchesKnn) void drawMatches( InputArray img1, const std::vector<KeyPoint>& keypoints1,
+ InputArray img2, const std::vector<KeyPoint>& keypoints2,
+ const std::vector<std::vector<DMatch> >& matches1to2, InputOutputArray outImg,
+ const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
+ const std::vector<std::vector<char> >& matchesMask=std::vector<std::vector<char> >(), int flags=DrawMatchesFlags::DEFAULT );
+
+/****************************************************************************************\
+* Functions to evaluate the feature detectors and [generic] descriptor extractors *
+\****************************************************************************************/
+
+CV_EXPORTS void evaluateFeatureDetector( const Mat& img1, const Mat& img2, const Mat& H1to2,
+ std::vector<KeyPoint>* keypoints1, std::vector<KeyPoint>* keypoints2,
+ float& repeatability, int& correspCount,
+ const Ptr<FeatureDetector>& fdetector=Ptr<FeatureDetector>() );
+
+CV_EXPORTS void computeRecallPrecisionCurve( const std::vector<std::vector<DMatch> >& matches1to2,
+ const std::vector<std::vector<uchar> >& correctMatches1to2Mask,
+ std::vector<Point2f>& recallPrecisionCurve );
+
+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
+ */
- void add( const Mat& descriptors );
- const std::vector<Mat>& getDescriptors() const;
- int descriptorsCount() const;
++class CV_EXPORTS_W BOWTrainer
+{
+public:
+ BOWTrainer();
+ virtual ~BOWTrainer();
+
- virtual void clear();
++ CV_WRAP void add( const Mat& descriptors );
++ CV_WRAP const std::vector<Mat>& getDescriptors() const;
++ CV_WRAP int descriptorsCount() const;
+
- virtual Mat cluster() const = 0;
- virtual Mat cluster( const Mat& descriptors ) const = 0;
++ CV_WRAP virtual void clear();
+
+ /*
+ * Train visual words vocabulary, that is cluster training descriptors and
+ * compute cluster centers.
+ * Returns cluster centers.
+ *
+ * descriptors Training descriptors computed on images keypoints.
+ */
- class CV_EXPORTS BOWKMeansTrainer : public BOWTrainer
++ CV_WRAP virtual Mat cluster() const = 0;
++ CV_WRAP virtual Mat cluster( const Mat& descriptors ) const = 0;
+
+protected:
+ std::vector<Mat> descriptors;
+ int size;
+};
+
+/*
+ * This is BOWTrainer using cv::kmeans to get vocabulary.
+ */
- BOWKMeansTrainer( int clusterCount, const TermCriteria& termcrit=TermCriteria(),
++class CV_EXPORTS_W BOWKMeansTrainer : public BOWTrainer
+{
+public:
- virtual Mat cluster() const;
- virtual Mat cluster( const Mat& descriptors ) const;
++ 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).
- class CV_EXPORTS BOWImgDescriptorExtractor
++ CV_WRAP virtual Mat cluster() const;
++ CV_WRAP virtual Mat cluster( const Mat& descriptors ) const;
+
+protected:
+
+ int clusterCount;
+ TermCriteria termcrit;
+ int attempts;
+ int flags;
+};
+
+/*
+ * Class to compute image descriptor using bag of visual words.
+ */
- BOWImgDescriptorExtractor( const Ptr<DescriptorExtractor>& dextractor,
++class CV_EXPORTS_W BOWImgDescriptorExtractor
+{
+public:
- void setVocabulary( const Mat& vocabulary );
- const Mat& getVocabulary() const;
++ CV_WRAP BOWImgDescriptorExtractor( const Ptr<DescriptorExtractor>& dextractor,
+ const Ptr<DescriptorMatcher>& dmatcher );
+ BOWImgDescriptorExtractor( const Ptr<DescriptorMatcher>& dmatcher );
+ virtual ~BOWImgDescriptorExtractor();
+
- int descriptorSize() const;
- int descriptorType() 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
+
++ 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;
+ Ptr<DescriptorExtractor> dextractor;
+ Ptr<DescriptorMatcher> dmatcher;
+};
+
+} /* namespace cv */
+
+#endif
maxlen = std::max(maxlen, len);
}
- string signature(maxlen, ' ');
++ String signature(maxlen, ' ');
size_t bufSize = buf.rows*buf.cols*buf.elemSize();
maxlen = std::min(maxlen, bufSize);
- String signature(maxlen, ' ');
- memcpy( &signature[0], buf.data, maxlen );
+ memcpy( (void*)signature.c_str(), buf.data, maxlen );
for( i = 0; i < codecs.decoders.size(); i++ )
{
void cv::pyrDown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
{
+ CV_Assert(borderType != BORDER_CONSTANT);
+
+ CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
+ ocl_pyrDown(_src, _dst, _dsz, borderType))
+
Mat src = _src.getMat();
- Size dsz = _dsz == Size() ? Size((src.cols + 1)/2, (src.rows + 1)/2) : _dsz;
+ Size dsz = _dsz.area() == 0 ? Size((src.cols + 1)/2, (src.rows + 1)/2) : _dsz;
_dst.create( dsz, src.type() );
Mat dst = _dst.getMat();
+ int depth = src.depth();
#ifdef HAVE_TEGRA_OPTIMIZATION
if(borderType == BORDER_DEFAULT && tegra::pyrDown(src, dst))
void cv::pyrUp( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
{
+ CV_Assert(borderType == BORDER_DEFAULT);
+
+ CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
+ ocl_pyrUp(_src, _dst, _dsz, borderType))
+
Mat src = _src.getMat();
- Size dsz = _dsz == Size() ? Size(src.cols*2, src.rows*2) : _dsz;
+ Size dsz = _dsz.area() == 0 ? Size(src.cols*2, src.rows*2) : _dsz;
_dst.create( dsz, src.type() );
Mat dst = _dst.getMat();
+ int depth = src.depth();
#ifdef HAVE_TEGRA_OPTIMIZATION
if(borderType == BORDER_DEFAULT && tegra::pyrUp(src, dst))
void cv::buildPyramid( InputArray _src, OutputArrayOfArrays _dst, int maxlevel, int borderType )
{
+ CV_Assert(borderType != BORDER_CONSTANT);
+
+ if (_src.dims() <= 2 && _dst.isUMatVector())
+ {
+ UMat src = _src.getUMat();
+ _dst.create( maxlevel + 1, 1, 0 );
+ _dst.getUMatRef(0) = src;
+ for( int i = 1; i <= maxlevel; i++ )
+ pyrDown( _dst.getUMatRef(i-1), _dst.getUMatRef(i), Size(), borderType );
+ return;
+ }
+
Mat src = _src.getMat();
_dst.create( maxlevel + 1, 1, 0 );
_dst.getMatRef(0) = src;