diff --git a/modules/geometry/CMakeLists.txt b/modules/geometry/CMakeLists.txt index d280f1a467..d92de297a4 100644 --- a/modules/geometry/CMakeLists.txt +++ b/modules/geometry/CMakeLists.txt @@ -1,12 +1,10 @@ set(the_description "Computational geometry primitives") -ocv_add_dispatched_file(undistort SSE2 AVX2) - set(debug_modules "") if(DEBUG_opencv_geometry) list(APPEND debug_modules opencv_highgui) endif() -ocv_define_module(geometry opencv_imgproc opencv_flann ${debug_modules} +ocv_define_module(geometry opencv_flann ${debug_modules} WRAP java objc python js ) ocv_target_link_libraries(${the_module} ${LAPACK_LIBRARIES}) diff --git a/modules/geometry/include/opencv2/geometry/2d.hpp b/modules/geometry/include/opencv2/geometry/2d.hpp index 2e4d409705..1f8b3a6fbe 100644 --- a/modules/geometry/include/opencv2/geometry/2d.hpp +++ b/modules/geometry/include/opencv2/geometry/2d.hpp @@ -20,12 +20,17 @@ enum RectanglesIntersectTypes { INTERSECT_FULL = 2 //!< One of the rectangle is fully enclosed in the other }; -//! Variants of Line Segment %Detector -enum LineSegmentDetectorModes { - LSD_REFINE_NONE = 0, //!< No refinement applied - LSD_REFINE_STD = 1, //!< Standard refinement is applied. E.g. breaking arches into smaller straighter line approximations. - LSD_REFINE_ADV = 2 //!< Advanced refinement. Number of false alarms is calculated, lines are - //!< refined through increase of precision, decrement in size, etc. +//! Distance types for Distance Transform and M-estimators +//! @see distanceTransform, fitLine +enum DistanceTypes { + DIST_USER = -1, //!< User defined distance + DIST_L1 = 1, //!< distance = |x1-x2| + |y1-y2| + DIST_L2 = 2, //!< the simple euclidean distance + DIST_C = 3, //!< distance = max(|x1-x2|,|y1-y2|) + DIST_L12 = 4, //!< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) + DIST_FAIR = 5, //!< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 + DIST_WELSCH = 6, //!< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 + DIST_HUBER = 7 //!< distance = |x|detect(image(roi), lines, ...); lines += Scalar(roi.x, roi.y, roi.x, roi.y);` - @param lines A vector of Vec4f elements specifying the beginning and ending point of a line. Where - Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end. Returned lines are strictly - oriented depending on the gradient. - @param width Vector of widths of the regions, where the lines are found. E.g. Width of line. - @param prec Vector of precisions with which the lines are found. - @param nfa Vector containing number of false alarms in the line region, with precision of 10%. The - bigger the value, logarithmically better the detection. - - -1 corresponds to 10 mean false alarms - - 0 corresponds to 1 mean false alarm - - 1 corresponds to 0.1 mean false alarms - This vector will be calculated only when the objects type is #LSD_REFINE_ADV. - */ - CV_WRAP virtual void detect(InputArray image, OutputArray lines, - OutputArray width = noArray(), OutputArray prec = noArray(), - OutputArray nfa = noArray()) = 0; - - /** @brief Draws the line segments on a given image. - @param image The image, where the lines will be drawn. Should be bigger or equal to the image, - where the lines were found. - @param lines A vector of the lines that needed to be drawn. - */ - CV_WRAP virtual void drawSegments(InputOutputArray image, InputArray lines) = 0; - - /** @brief Draws two groups of lines in blue and red, counting the non overlapping (mismatching) pixels. - - @param size The size of the image, where lines1 and lines2 were found. - @param lines1 The first group of lines that needs to be drawn. It is visualized in blue color. - @param lines2 The second group of lines. They visualized in red color. - @param image Optional image, where the lines will be drawn. The image should be color(3-channel) - in order for lines1 and lines2 to be drawn in the above mentioned colors. - */ - CV_WRAP virtual int compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray image = noArray()) = 0; - - virtual ~LineSegmentDetector() { } -}; - -/** @brief Creates a smart pointer to a LineSegmentDetector object and initializes it. - -The LineSegmentDetector algorithm is defined using the standard values. Only advanced users may want -to edit those, as to tailor it for their own application. - -@param refine The way found lines will be refined, see #LineSegmentDetectorModes -@param scale The scale of the image that will be used to find the lines. Range (0..1]. -@param sigma_scale Sigma for Gaussian filter. It is computed as sigma = sigma_scale/scale. -@param quant Bound to the quantization error on the gradient norm. -@param ang_th Gradient angle tolerance in degrees. -@param log_eps Detection threshold: -log10(NFA) \> log_eps. Used only when advance refinement is chosen. -@param density_th Minimal density of aligned region points in the enclosing rectangle. -@param n_bins Number of bins in pseudo-ordering of gradient modulus. - */ -CV_EXPORTS_W Ptr createLineSegmentDetector( - LineSegmentDetectorModes refine = LSD_REFINE_STD, double scale = 0.8, - double sigma_scale = 0.6, double quant = 2.0, double ang_th = 22.5, - double log_eps = 0, double density_th = 0.7, int n_bins = 1024); - -//! @} geometry_feature - /** @example samples/python/snippets/squares.py A n example using approxPolyDP function in python. * */ @@ -517,6 +438,59 @@ CV_EXPORTS_W double minEnclosingTriangle( InputArray points, CV_OUT OutputArray CV_EXPORTS_W double minEnclosingConvexPolygon ( InputArray points, OutputArray polygon, int k ); +/** @brief Calculates all of the moments up to the third order of a polygon or rasterized shape. + * + * The function computes moments, up to the 3rd order, of a vector shape or a rasterized shape. The + * results are returned in the structure cv::Moments. + * + * @param array Single channel raster image (CV_8U, CV_16U, CV_16S, CV_32F, CV_64F) or an array ( + * \f$1 \times N\f$ or \f$N \times 1\f$ ) of 2D points (Point or Point2f). + * @param binaryImage If it is true, all non-zero image pixels are treated as 1's. The parameter is + * used for images only. + * @returns moments. + * + * @note Only applicable to contour moments calculations from Python bindings: Note that the numpy + * type for the input array should be either np.int32 or np.float32. + * + * @note For contour-based moments, the zeroth-order moment \c m00 represents + * the contour area. + * + * If the input contour is degenerate (for example, a single point or all points + * are collinear), the area is zero and therefore \c m00 == 0. + * + * In this case, the centroid coordinates (\c m10/m00, \c m01/m00) are undefined + * and must be handled explicitly by the caller. + * + * A common workaround is to compute the center using cv::boundingRect() or by + * averaging the input points. + * + * @sa contourArea, arcLength + */ +CV_EXPORTS_W Moments moments( InputArray array, bool binaryImage = false ); + +/** @brief Calculates seven Hu invariants. + * + * The function calculates seven Hu invariants (introduced in @cite Hu62; see also + * ) defined as: + * + * \f[\begin{array}{l} hu[0]= \eta _{20}+ \eta _{02} \\ hu[1]=( \eta _{20}- \eta _{02})^{2}+4 \eta _{11}^{2} \\ hu[2]=( \eta _{30}-3 \eta _{12})^{2}+ (3 \eta _{21}- \eta _{03})^{2} \\ hu[3]=( \eta _{30}+ \eta _{12})^{2}+ ( \eta _{21}+ \eta _{03})^{2} \\ hu[4]=( \eta _{30}-3 \eta _{12})( \eta _{30}+ \eta _{12})[( \eta _{30}+ \eta _{12})^{2}-3( \eta _{21}+ \eta _{03})^{2}]+(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ hu[5]=( \eta _{20}- \eta _{02})[( \eta _{30}+ \eta _{12})^{2}- ( \eta _{21}+ \eta _{03})^{2}]+4 \eta _{11}( \eta _{30}+ \eta _{12})( \eta _{21}+ \eta _{03}) \\ hu[6]=(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}]-( \eta _{30}-3 \eta _{12})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ \end{array}\f] + * + * where \f$\eta_{ji}\f$ stands for \f$\texttt{Moments::nu}_{ji}\f$ . + * + * These values are proved to be invariants to the image scale, rotation, and reflection except the + * seventh one, whose sign is changed by reflection. This invariance is proved with the assumption of + * infinite image resolution. In case of raster images, the computed Hu invariants for the original and + * transformed images are a bit different. + * + * @param moments Input moments computed with moments . + * @param hu Output Hu invariants. + * + * @sa matchShapes + */ +CV_EXPORTS void HuMoments( const Moments& moments, double hu[7] ); + +/** @overload */ +CV_EXPORTS_W void HuMoments( const Moments& m, OutputArray hu ); /** @brief Compares two shapes. * @@ -856,6 +830,90 @@ CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false ); */ CV_EXPORTS_W Rect boundingRect( InputArray array ); +/** @brief Calculates an affine matrix of 2D rotation. + +The function calculates the following matrix: + +\f[\begin{bmatrix} \alpha & \beta & (1- \alpha ) \cdot \texttt{center.x} - \beta \cdot \texttt{center.y} \\ - \beta & \alpha & \beta \cdot \texttt{center.x} + (1- \alpha ) \cdot \texttt{center.y} \end{bmatrix}\f] + +where + +\f[\begin{array}{l} \alpha = \texttt{scale} \cdot \cos \texttt{angle} , \\ \beta = \texttt{scale} \cdot \sin \texttt{angle} \end{array}\f] + +The transformation maps the rotation center to itself. If this is not the target, adjust the shift. + +@param center Center of the rotation in the source image. +@param angle Rotation angle in degrees. Positive values mean counter-clockwise rotation (the +coordinate origin is assumed to be the top-left corner). +@param scale Isotropic scale factor. + +@sa getAffineTransform, warpAffine, transform + */ +CV_EXPORTS_W Mat getRotationMatrix2D(Point2f center, double angle, double scale); + +/** @sa getRotationMatrix2D */ +CV_EXPORTS Matx23d getRotationMatrix2D_(Point2f center, double angle, double scale); + +inline +Mat getRotationMatrix2D(Point2f center, double angle, double scale) +{ + return Mat(getRotationMatrix2D_(center, angle, scale), true); +} + +/** @brief Calculates an affine transform from three pairs of the corresponding points. + * + * The function calculates the \f$2 \times 3\f$ matrix of an affine transform so that: + * + * \f[\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] + * + * where + * + * \f[dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2\f] + * + * @param src Coordinates of triangle vertices in the source image. + * @param dst Coordinates of the corresponding triangle vertices in the destination image. + * + * @sa warpAffine, transform + */ +CV_EXPORTS Mat getAffineTransform( const Point2f src[], const Point2f dst[] ); + +/** @brief Inverts an affine transformation. + * + * The function computes an inverse affine transformation represented by \f$2 \times 3\f$ matrix M: + * + * \f[\begin{bmatrix} a_{11} & a_{12} & b_1 \\ a_{21} & a_{22} & b_2 \end{bmatrix}\f] + * + * The result is also a \f$2 \times 3\f$ matrix of the same type as M. + * + * @param M Original affine transformation. + * @param iM Output reverse affine transformation. + */ +CV_EXPORTS_W void invertAffineTransform( InputArray M, OutputArray iM ); + +/** @brief Calculates a perspective transform from four pairs of the corresponding points. + * + * The function calculates the \f$3 \times 3\f$ matrix of a perspective transform so that: + * + * \f[\begin{bmatrix} t_i x'_i \\ t_i y'_i \\ t_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] + * + * where + * + * \f[dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2,3\f] + * + * @param src Coordinates of quadrangle vertices in the source image. + * @param dst Coordinates of the corresponding quadrangle vertices in the destination image. + * @param solveMethod method passed to cv::solve (#DecompTypes) + * + * @sa findHomography, warpPerspective, perspectiveTransform + */ +CV_EXPORTS_W Mat getPerspectiveTransform(InputArray src, InputArray dst, int solveMethod = DECOMP_LU); + +/** @overload */ +CV_EXPORTS Mat getPerspectiveTransform(const Point2f src[], const Point2f dst[], int solveMethod = DECOMP_LU); + + +CV_EXPORTS_W Mat getAffineTransform( InputArray src, InputArray dst ); + } // namespace cv #endif // OPENCV_2D_HPP diff --git a/modules/geometry/include/opencv2/geometry/3d.hpp b/modules/geometry/include/opencv2/geometry/3d.hpp index 9e95f23881..64178c3a99 100644 --- a/modules/geometry/include/opencv2/geometry/3d.hpp +++ b/modules/geometry/include/opencv2/geometry/3d.hpp @@ -1280,25 +1280,6 @@ CV_EXPORTS_W int solvePnPGeneric( InputArray objectPoints, InputArray imagePoint InputArray rvec = noArray(), InputArray tvec = noArray(), OutputArray reprojectionError = noArray() ); -/** @brief Draw axes of the world/object coordinate system from pose estimation. @sa solvePnP - -@param image Input/output image. It must have 1 or 3 channels. The number of channels is not altered. -@param cameraMatrix Input 3x3 floating-point matrix of camera intrinsic parameters. -\f$\cameramatrix{A}\f$ -@param distCoeffs Input vector of distortion coefficients -\f$\distcoeffs\f$. If the vector is empty, the zero distortion coefficients are assumed. -@param rvec Rotation vector (see @ref Rodrigues ) that, together with tvec, brings points from -the model coordinate system to the camera coordinate system. -@param tvec Translation vector. -@param length Length of the painted axes in the same unit than tvec (usually in meters). -@param thickness Line thickness of the painted axes. - -This function draws the axes of the world/object coordinate system w.r.t. to the camera frame. -OX is drawn in red, OY in green and OZ in blue. - */ -CV_EXPORTS_W void drawFrameAxes(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs, - InputArray rvec, InputArray tvec, float length, int thickness=3); - /** @brief Converts points from Euclidean to homogeneous space. @param src Input vector of N-dimensional points. @@ -2216,201 +2197,6 @@ CV_EXPORTS_W void filterHomographyDecompByVisibleRefpoints(InputArrayOfArrays ro OutputArray possibleSolutions, InputArray pointsMask = noArray()); -//! cv::undistort mode -enum UndistortTypes -{ - PROJ_SPHERICAL_ORTHO = 0, - PROJ_SPHERICAL_EQRECT = 1 -}; - -/** @brief Transforms an image to compensate for lens distortion. - -The function transforms an image to compensate radial and tangential lens distortion. - -The function is simply a combination of #initUndistortRectifyMap (with unity R ) and #remap -(with bilinear interpolation). See the former function for details of the transformation being -performed. - -Those pixels in the destination image, for which there is no correspondent pixels in the source -image, are filled with zeros (black color). - -A particular subset of the source image that will be visible in the corrected image can be regulated -by newCameraMatrix. You can use #getOptimalNewCameraMatrix to compute the appropriate -newCameraMatrix depending on your requirements. - -The camera matrix and the distortion parameters can be determined using #calibrateCamera. If -the resolution of images is different from the resolution used at the calibration stage, \f$f_x, -f_y, c_x\f$ and \f$c_y\f$ need to be scaled accordingly, while the distortion coefficients remain -the same. - -@param src Input (distorted) image. -@param dst Output (corrected) image that has the same size and type as src . -@param cameraMatrix Input camera matrix \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . -@param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ -of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. -@param newCameraMatrix Camera matrix of the distorted image. By default, it is the same as -cameraMatrix but you may additionally scale and shift the result by using a different matrix. - */ -CV_EXPORTS_W void undistort( InputArray src, OutputArray dst, - InputArray cameraMatrix, - InputArray distCoeffs, - InputArray newCameraMatrix = noArray() ); - -/** @brief Computes the undistortion and rectification transformation map. - -The function computes the joint undistortion and rectification transformation and represents the -result in the form of maps for #remap. The undistorted image looks like original, as if it is -captured with a camera using the camera matrix =newCameraMatrix and zero distortion. In case of a -monocular camera, newCameraMatrix is usually equal to cameraMatrix, or it can be computed by -#getOptimalNewCameraMatrix for a better control over scaling. In case of a stereo camera, -newCameraMatrix is normally set to P1 or P2 computed by #stereoRectify . - -Also, this new camera is oriented differently in the coordinate space, according to R. That, for -example, helps to align two heads of a stereo camera so that the epipolar lines on both images -become horizontal and have the same y- coordinate (in case of a horizontally aligned stereo camera). - -The function actually builds the maps for the inverse mapping algorithm that is used by #remap. That -is, for each pixel \f$(u, v)\f$ in the destination (corrected and rectified) image, the function -computes the corresponding coordinates in the source image (that is, in the original image from -camera). The following process is applied: -\f[ -\begin{array}{l} -x \leftarrow (u - {c'}_x)/{f'}_x \\ -y \leftarrow (v - {c'}_y)/{f'}_y \\ -{[X\,Y\,W]} ^T \leftarrow R^{-1}*[x \, y \, 1]^T \\ -x' \leftarrow X/W \\ -y' \leftarrow Y/W \\ -r^2 \leftarrow x'^2 + y'^2 \\ -x'' \leftarrow x' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} -+ 2p_1 x' y' + p_2(r^2 + 2 x'^2) + s_1 r^2 + s_2 r^4\\ -y'' \leftarrow y' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} -+ p_1 (r^2 + 2 y'^2) + 2 p_2 x' y' + s_3 r^2 + s_4 r^4 \\ -s\vecthree{x'''}{y'''}{1} = -\vecthreethree{R_{33}(\tau_x, \tau_y)}{0}{-R_{13}((\tau_x, \tau_y)} -{0}{R_{33}(\tau_x, \tau_y)}{-R_{23}(\tau_x, \tau_y)} -{0}{0}{1} R(\tau_x, \tau_y) \vecthree{x''}{y''}{1}\\ -map_x(u,v) \leftarrow x''' f_x + c_x \\ -map_y(u,v) \leftarrow y''' f_y + c_y -\end{array} -\f] -where \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ -are the distortion coefficients. - -In case of a stereo camera, this function is called twice: once for each camera head, after -#stereoRectify, which in its turn is called after #stereoCalibrate. But if the stereo camera -was not calibrated, it is still possible to compute the rectification transformations directly from -the fundamental matrix using #stereoRectifyUncalibrated. For each camera, the function computes -homography H as the rectification transformation in a pixel domain, not a rotation matrix R in 3D -space. R can be computed from H as -\f[\texttt{R} = \texttt{cameraMatrix} ^{-1} \cdot \texttt{H} \cdot \texttt{cameraMatrix}\f] -where cameraMatrix can be chosen arbitrarily. - -@param cameraMatrix Input camera matrix \f$A=\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . -@param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ -of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. -@param R Optional rectification transformation in the object space (3x3 matrix). R1 or R2 , -computed by #stereoRectify can be passed here. If the matrix is empty, the identity transformation -is assumed. In #initUndistortRectifyMap R assumed to be an identity matrix. -@param newCameraMatrix New camera matrix \f$A'=\vecthreethree{f_x'}{0}{c_x'}{0}{f_y'}{c_y'}{0}{0}{1}\f$. -@param size Undistorted image size. -@param m1type Type of the first output map that can be CV_32FC1, CV_32FC2 or CV_16SC2, see #convertMaps -@param map1 The first output map. -@param map2 The second output map. - */ -CV_EXPORTS_W -void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, - InputArray R, InputArray newCameraMatrix, - Size size, int m1type, OutputArray map1, OutputArray map2); - -/** @brief Computes the projection and inverse-rectification transformation map. In essense, this is the inverse of -#initUndistortRectifyMap to accomodate stereo-rectification of projectors ('inverse-cameras') in projector-camera pairs. - -The function computes the joint projection and inverse rectification transformation and represents the -result in the form of maps for #remap. The projected image looks like a distorted version of the original which, -once projected by a projector, should visually match the original. In case of a monocular camera, newCameraMatrix -is usually equal to cameraMatrix, or it can be computed by -#getOptimalNewCameraMatrix for a better control over scaling. In case of a projector-camera pair, -newCameraMatrix is normally set to P1 or P2 computed by #stereoRectify . - -The projector is oriented differently in the coordinate space, according to R. In case of projector-camera pairs, -this helps align the projector (in the same manner as #initUndistortRectifyMap for the camera) to create a stereo-rectified pair. This -allows epipolar lines on both images to become horizontal and have the same y-coordinate (in case of a horizontally aligned projector-camera pair). - -The function builds the maps for the inverse mapping algorithm that is used by #remap. That -is, for each pixel \f$(u, v)\f$ in the destination (projected and inverse-rectified) image, the function -computes the corresponding coordinates in the source image (that is, in the original digital image). The following process is applied: - -\f[ -\begin{array}{l} -\text{newCameraMatrix}\\ -x \leftarrow (u - {c'}_x)/{f'}_x \\ -y \leftarrow (v - {c'}_y)/{f'}_y \\ - -\\\text{Undistortion} -\\\scriptsize{\textit{though equation shown is for radial undistortion, function implements cv::undistortPoints()}}\\ -r^2 \leftarrow x^2 + y^2 \\ -\theta \leftarrow \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6}\\ -x' \leftarrow \frac{x}{\theta} \\ -y' \leftarrow \frac{y}{\theta} \\ - -\\\text{Rectification}\\ -{[X\,Y\,W]} ^T \leftarrow R*[x' \, y' \, 1]^T \\ -x'' \leftarrow X/W \\ -y'' \leftarrow Y/W \\ - -\\\text{cameraMatrix}\\ -map_x(u,v) \leftarrow x'' f_x + c_x \\ -map_y(u,v) \leftarrow y'' f_y + c_y -\end{array} -\f] -where \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ -are the distortion coefficients vector distCoeffs. - -In case of a stereo-rectified projector-camera pair, this function is called for the projector while #initUndistortRectifyMap is called for the camera head. -This is done after #stereoRectify, which in turn is called after #stereoCalibrate. If the projector-camera pair -is not calibrated, it is still possible to compute the rectification transformations directly from -the fundamental matrix using #stereoRectifyUncalibrated. For the projector and camera, the function computes -homography H as the rectification transformation in a pixel domain, not a rotation matrix R in 3D -space. R can be computed from H as -\f[\texttt{R} = \texttt{cameraMatrix} ^{-1} \cdot \texttt{H} \cdot \texttt{cameraMatrix}\f] -where cameraMatrix can be chosen arbitrarily. - -@param cameraMatrix Input camera matrix \f$A=\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . -@param distCoeffs Input vector of distortion coefficients -\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ -of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. -@param R Optional rectification transformation in the object space (3x3 matrix). R1 or R2, -computed by #stereoRectify can be passed here. If the matrix is empty, the identity transformation -is assumed. -@param newCameraMatrix New camera matrix \f$A'=\vecthreethree{f_x'}{0}{c_x'}{0}{f_y'}{c_y'}{0}{0}{1}\f$. -@param size Distorted image size. -@param m1type Type of the first output map. Can be CV_32FC1, CV_32FC2 or CV_16SC2, see #convertMaps -@param map1 The first output map for #remap. -@param map2 The second output map for #remap. - */ -CV_EXPORTS_W -void initInverseRectificationMap( InputArray cameraMatrix, InputArray distCoeffs, - InputArray R, InputArray newCameraMatrix, - const Size& size, int m1type, OutputArray map1, OutputArray map2 ); - -//! initializes maps for #remap for wide-angle -CV_EXPORTS -float initWideAngleProjMap(InputArray cameraMatrix, InputArray distCoeffs, - Size imageSize, int destImageWidth, - int m1type, OutputArray map1, OutputArray map2, - enum UndistortTypes projType = PROJ_SPHERICAL_EQRECT, double alpha = 0); -static inline -float initWideAngleProjMap(InputArray cameraMatrix, InputArray distCoeffs, - Size imageSize, int destImageWidth, - int m1type, OutputArray map1, OutputArray map2, - int projType, double alpha = 0) -{ - return initWideAngleProjMap(cameraMatrix, distCoeffs, imageSize, destImageWidth, - m1type, map1, map2, (UndistortTypes)projType, alpha); -} - /** @brief Computes useful camera characteristics from the camera intrinsic matrix. * * @param cameraMatrix Input camera intrinsic matrix that can be estimated by #calibrateCamera or @@ -2701,55 +2487,6 @@ length. Balance is in range of [0, 1]. */ CV_EXPORTS_W 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); - -/** @brief Computes undistortion and rectification maps for image transform by cv::remap(). If D is empty zero -distortion is used, if R or P is empty identity matrixes are used. - -@param K Camera intrinsic matrix \f$cameramatrix{K}\f$. -@param D Input vector of distortion coefficients \f$\distcoeffsfisheye\f$. -@param R Rectification transformation in the object space: 3x3 1-channel, or vector: 3x1/1x3 -1-channel or 1x1 3-channel -@param P New camera intrinsic matrix (3x3) or new projection matrix (3x4) -@param size Undistorted image size. -@param m1type Type of the first output map that can be CV_32FC1 or CV_16SC2 . See convertMaps() -for details. -@param map1 The first output map. -@param map2 The second output map. - */ -CV_EXPORTS_W void initUndistortRectifyMap(InputArray K, InputArray D, InputArray R, InputArray P, - const cv::Size& size, int m1type, OutputArray map1, OutputArray map2); - -/** @brief Transforms an image to compensate for fisheye lens distortion. - -@param distorted image with fisheye lens distortion. -@param undistorted Output image with compensated fisheye lens distortion. -@param K Camera intrinsic matrix \f$cameramatrix{K}\f$. -@param D Input vector of distortion coefficients \f$\distcoeffsfisheye\f$. -@param Knew Camera intrinsic matrix of the distorted image. By default, it is the identity matrix but you -may additionally scale and shift the result by using a different matrix. -@param new_size the new size - -The function transforms an image to compensate radial and tangential lens distortion. - -The function is simply a combination of #cv::fisheye::initUndistortRectifyMap (with unity R ) and remap -(with bilinear interpolation). See the former function for details of the transformation being -performed. - -See below the results of undistortImage. - - a\) result of undistort of perspective camera model (all possible coefficients (k_1, k_2, k_3, - k_4, k_5, k_6) of distortion were optimized under calibration) - - b\) result of #cv::fisheye::undistortImage of fisheye camera model (all possible coefficients (k_1, k_2, - k_3, k_4) of fisheye distortion were optimized under calibration) - - c\) original image was captured with fisheye lens - -Pictures a) and b) almost the same. But if we consider points of image located far from the center -of image, we can notice that on image a) these points are distorted. - -![image](pics/fisheye_undistorted.jpg) - */ -CV_EXPORTS_W void undistortImage(InputArray distorted, OutputArray undistorted, - InputArray K, InputArray D, InputArray Knew = cv::noArray(), const Size& new_size = Size()); - /** @brief Finds an object pose from 3D-2D point correspondences for fisheye camera model. diff --git a/modules/imgproc/include/opencv2/imgproc/detail/gcgraph.hpp b/modules/geometry/include/opencv2/geometry/detail/gcgraph.hpp similarity index 100% rename from modules/imgproc/include/opencv2/imgproc/detail/gcgraph.hpp rename to modules/geometry/include/opencv2/geometry/detail/gcgraph.hpp diff --git a/modules/geometry/misc/java/gen_dict.json b/modules/geometry/misc/java/gen_dict.json index 87135fcc86..ab1448fa19 100644 --- a/modules/geometry/misc/java/gen_dict.json +++ b/modules/geometry/misc/java/gen_dict.json @@ -17,6 +17,25 @@ "dst" : {"ctype" : "vector_Point2f"} }, "projectPoints" : { "objectPoints" : {"ctype" : "vector_Point3f"}, "imagePoints" : {"ctype" : "vector_Point2f"}, - "distCoeffs" : {"ctype" : "vector_double" } } + "distCoeffs" : {"ctype" : "vector_double" } }, + "minEnclosingCircle" : { "points" : {"ctype" : "vector_Point2f"} }, + "fitEllipse" : { "points" : {"ctype" : "vector_Point2f"} }, + "fillPoly" : { "pts" : {"ctype" : "vector_vector_Point"} }, + "polylines" : { "pts" : {"ctype" : "vector_vector_Point"} }, + "fillConvexPoly" : { "points" : {"ctype" : "vector_Point"} }, + "approxPolyDP" : { "curve" : {"ctype" : "vector_Point2f"}, + "approxCurve" : {"ctype" : "vector_Point2f"} }, + "arcLength" : { "curve" : {"ctype" : "vector_Point2f"} }, + "pointPolygonTest" : { "contour" : {"ctype" : "vector_Point2f"} }, + "minAreaRect" : { "points" : {"ctype" : "vector_Point2f"} }, + "getAffineTransform" : { "src" : {"ctype" : "vector_Point2f"}, + "dst" : {"ctype" : "vector_Point2f"} }, + "convexityDefects" : { "contour" : {"ctype" : "vector_Point"}, + "convexhull" : {"ctype" : "vector_int"}, + "convexityDefects" : {"ctype" : "vector_Vec4i"} }, + "isContourConvex" : { "contour" : {"ctype" : "vector_Point"} }, + "convexHull" : { "points" : {"ctype" : "vector_Point"}, + "hull" : {"ctype" : "vector_int"}, + "returnPoints" : {"ctype" : ""} } } } diff --git a/modules/geometry/misc/java/src/java/geometry+Moments.java b/modules/geometry/misc/java/src/java/geometry+Moments.java new file mode 100644 index 0000000000..79c2d3a69a --- /dev/null +++ b/modules/geometry/misc/java/src/java/geometry+Moments.java @@ -0,0 +1,242 @@ +package org.opencv.geometry; + +//javadoc:Moments +public class Moments { + + public double m00; + public double m10; + public double m01; + public double m20; + public double m11; + public double m02; + public double m30; + public double m21; + public double m12; + public double m03; + + public double mu20; + public double mu11; + public double mu02; + public double mu30; + public double mu21; + public double mu12; + public double mu03; + + public double nu20; + public double nu11; + public double nu02; + public double nu30; + public double nu21; + public double nu12; + public double nu03; + + public Moments( + double m00, + double m10, + double m01, + double m20, + double m11, + double m02, + double m30, + double m21, + double m12, + double m03) + { + this.m00 = m00; + this.m10 = m10; + this.m01 = m01; + this.m20 = m20; + this.m11 = m11; + this.m02 = m02; + this.m30 = m30; + this.m21 = m21; + this.m12 = m12; + this.m03 = m03; + this.completeState(); + } + + public Moments() { + this(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + + public Moments(double[] vals) { + set(vals); + } + + public void set(double[] vals) { + if (vals != null) { + m00 = vals.length > 0 ? vals[0] : 0; + m10 = vals.length > 1 ? vals[1] : 0; + m01 = vals.length > 2 ? vals[2] : 0; + m20 = vals.length > 3 ? vals[3] : 0; + m11 = vals.length > 4 ? vals[4] : 0; + m02 = vals.length > 5 ? vals[5] : 0; + m30 = vals.length > 6 ? vals[6] : 0; + m21 = vals.length > 7 ? vals[7] : 0; + m12 = vals.length > 8 ? vals[8] : 0; + m03 = vals.length > 9 ? vals[9] : 0; + this.completeState(); + } else { + m00 = 0; + m10 = 0; + m01 = 0; + m20 = 0; + m11 = 0; + m02 = 0; + m30 = 0; + m21 = 0; + m12 = 0; + m03 = 0; + mu20 = 0; + mu11 = 0; + mu02 = 0; + mu30 = 0; + mu21 = 0; + mu12 = 0; + mu03 = 0; + nu20 = 0; + nu11 = 0; + nu02 = 0; + nu30 = 0; + nu21 = 0; + nu12 = 0; + nu03 = 0; + } + } + + @Override + public String toString() { + return "Moments [ " + + "\n" + + "m00=" + m00 + ", " + + "\n" + + "m10=" + m10 + ", " + + "m01=" + m01 + ", " + + "\n" + + "m20=" + m20 + ", " + + "m11=" + m11 + ", " + + "m02=" + m02 + ", " + + "\n" + + "m30=" + m30 + ", " + + "m21=" + m21 + ", " + + "m12=" + m12 + ", " + + "m03=" + m03 + ", " + + "\n" + + "mu20=" + mu20 + ", " + + "mu11=" + mu11 + ", " + + "mu02=" + mu02 + ", " + + "\n" + + "mu30=" + mu30 + ", " + + "mu21=" + mu21 + ", " + + "mu12=" + mu12 + ", " + + "mu03=" + mu03 + ", " + + "\n" + + "nu20=" + nu20 + ", " + + "nu11=" + nu11 + ", " + + "nu02=" + nu02 + ", " + + "\n" + + "nu30=" + nu30 + ", " + + "nu21=" + nu21 + ", " + + "nu12=" + nu12 + ", " + + "nu03=" + nu03 + ", " + + "\n]"; + } + + protected void completeState() + { + double cx = 0, cy = 0; + double mu20, mu11, mu02; + double inv_m00 = 0.0; + + if( Math.abs(this.m00) > 0.00000001 ) + { + inv_m00 = 1. / this.m00; + cx = this.m10 * inv_m00; + cy = this.m01 * inv_m00; + } + + // mu20 = m20 - m10*cx + mu20 = this.m20 - this.m10 * cx; + // mu11 = m11 - m10*cy + mu11 = this.m11 - this.m10 * cy; + // mu02 = m02 - m01*cy + mu02 = this.m02 - this.m01 * cy; + + this.mu20 = mu20; + this.mu11 = mu11; + this.mu02 = mu02; + + // mu30 = m30 - cx*(3*mu20 + cx*m10) + this.mu30 = this.m30 - cx * (3 * mu20 + cx * this.m10); + mu11 += mu11; + // mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20 + this.mu21 = this.m21 - cx * (mu11 + cx * this.m01) - cy * mu20; + // mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02 + this.mu12 = this.m12 - cy * (mu11 + cy * this.m10) - cx * mu02; + // mu03 = m03 - cy*(3*mu02 + cy*m01) + this.mu03 = this.m03 - cy * (3 * mu02 + cy * this.m01); + + + double inv_sqrt_m00 = Math.sqrt(Math.abs(inv_m00)); + double s2 = inv_m00*inv_m00, s3 = s2*inv_sqrt_m00; + + this.nu20 = this.mu20*s2; + this.nu11 = this.mu11*s2; + this.nu02 = this.mu02*s2; + this.nu30 = this.mu30*s3; + this.nu21 = this.mu21*s3; + this.nu12 = this.mu12*s3; + this.nu03 = this.mu03*s3; + + } + + public double get_m00() { return this.m00; } + public double get_m10() { return this.m10; } + public double get_m01() { return this.m01; } + public double get_m20() { return this.m20; } + public double get_m11() { return this.m11; } + public double get_m02() { return this.m02; } + public double get_m30() { return this.m30; } + public double get_m21() { return this.m21; } + public double get_m12() { return this.m12; } + public double get_m03() { return this.m03; } + public double get_mu20() { return this.mu20; } + public double get_mu11() { return this.mu11; } + public double get_mu02() { return this.mu02; } + public double get_mu30() { return this.mu30; } + public double get_mu21() { return this.mu21; } + public double get_mu12() { return this.mu12; } + public double get_mu03() { return this.mu03; } + public double get_nu20() { return this.nu20; } + public double get_nu11() { return this.nu11; } + public double get_nu02() { return this.nu02; } + public double get_nu30() { return this.nu30; } + public double get_nu21() { return this.nu21; } + public double get_nu12() { return this.nu12; } + public double get_nu03() { return this.nu03; } + + public void set_m00(double m00) { this.m00 = m00; } + public void set_m10(double m10) { this.m10 = m10; } + public void set_m01(double m01) { this.m01 = m01; } + public void set_m20(double m20) { this.m20 = m20; } + public void set_m11(double m11) { this.m11 = m11; } + public void set_m02(double m02) { this.m02 = m02; } + public void set_m30(double m30) { this.m30 = m30; } + public void set_m21(double m21) { this.m21 = m21; } + public void set_m12(double m12) { this.m12 = m12; } + public void set_m03(double m03) { this.m03 = m03; } + public void set_mu20(double mu20) { this.mu20 = mu20; } + public void set_mu11(double mu11) { this.mu11 = mu11; } + public void set_mu02(double mu02) { this.mu02 = mu02; } + public void set_mu30(double mu30) { this.mu30 = mu30; } + public void set_mu21(double mu21) { this.mu21 = mu21; } + public void set_mu12(double mu12) { this.mu12 = mu12; } + public void set_mu03(double mu03) { this.mu03 = mu03; } + public void set_nu20(double nu20) { this.nu20 = nu20; } + public void set_nu11(double nu11) { this.nu11 = nu11; } + public void set_nu02(double nu02) { this.nu02 = nu02; } + public void set_nu30(double nu30) { this.nu30 = nu30; } + public void set_nu21(double nu21) { this.nu21 = nu21; } + public void set_nu12(double nu12) { this.nu12 = nu12; } + public void set_nu03(double nu03) { this.nu03 = nu03; } +} diff --git a/modules/geometry/misc/java/test/GeometryTest.java b/modules/geometry/misc/java/test/GeometryTest.java index 64d0ff10a2..7b7e575ae2 100644 --- a/modules/geometry/misc/java/test/GeometryTest.java +++ b/modules/geometry/misc/java/test/GeometryTest.java @@ -452,101 +452,6 @@ public class GeometryTest extends OpenCVTestCase { // TODO_: write better test } - public void testInitUndistortRectifyMap() { - fail("Not yet implemented"); - Mat cameraMatrix = new Mat(3, 3, CvType.CV_32F); - cameraMatrix.put(0, 0, 1, 0, 1); - cameraMatrix.put(1, 0, 0, 1, 1); - cameraMatrix.put(2, 0, 0, 0, 1); - - Mat R = new Mat(3, 3, CvType.CV_32F, new Scalar(2)); - Mat newCameraMatrix = new Mat(3, 3, CvType.CV_32F, new Scalar(3)); - - Mat distCoeffs = new Mat(); - Mat map1 = new Mat(); - Mat map2 = new Mat(); - - // TODO: complete this test - Geometry.initUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, size, CvType.CV_32F, map1, map2); - } - - public void testInitWideAngleProjMapMatMatSizeIntIntMatMat() { - fail("Not yet implemented"); - Mat cameraMatrix = new Mat(3, 3, CvType.CV_32F); - Mat distCoeffs = new Mat(1, 4, CvType.CV_32F); - // Size imageSize = new Size(2, 2); - - cameraMatrix.put(0, 0, 1, 0, 1); - cameraMatrix.put(1, 0, 0, 1, 2); - cameraMatrix.put(2, 0, 0, 0, 1); - - distCoeffs.put(0, 0, 1, 3, 2, 4); - truth = new Mat(3, 3, CvType.CV_32F); - truth.put(0, 0, 0, 0, 0); - truth.put(1, 0, 0, 0, 0); - truth.put(2, 0, 0, 3, 0); - // TODO: No documentation for this function - // Geometry.initWideAngleProjMap(cameraMatrix, distCoeffs, imageSize, - // 5, m1type, truthput1, truthput2); - } - - public void testInitWideAngleProjMapMatMatSizeIntIntMatMatInt() { - fail("Not yet implemented"); - } - - public void testInitWideAngleProjMapMatMatSizeIntIntMatMatIntDouble() { - fail("Not yet implemented"); - } - - public void testUndistortMatMatMatMat() { - Mat src = new Mat(3, 3, CvType.CV_32F, new Scalar(3)); - Mat cameraMatrix = new Mat(3, 3, CvType.CV_32F) { - { - put(0, 0, 1, 0, 1); - put(1, 0, 0, 1, 2); - put(2, 0, 0, 0, 1); - } - }; - Mat distCoeffs = new Mat(1, 4, CvType.CV_32F) { - { - put(0, 0, 1, 3, 2, 4); - } - }; - - Geometry.undistort(src, dst, cameraMatrix, distCoeffs); - - truth = new Mat(3, 3, CvType.CV_32F) { - { - put(0, 0, 0, 0, 0); - put(1, 0, 0, 0, 0); - put(2, 0, 0, 3, 0); - } - }; - assertMatEqual(truth, dst, EPS); - } - - public void testUndistortMatMatMatMatMat() { - Mat src = new Mat(3, 3, CvType.CV_32F, new Scalar(3)); - Mat cameraMatrix = new Mat(3, 3, CvType.CV_32F) { - { - put(0, 0, 1, 0, 1); - put(1, 0, 0, 1, 2); - put(2, 0, 0, 0, 1); - } - }; - Mat distCoeffs = new Mat(1, 4, CvType.CV_32F) { - { - put(0, 0, 2, 1, 4, 5); - } - }; - Mat newCameraMatrix = new Mat(3, 3, CvType.CV_32F, new Scalar(1)); - - Geometry.undistort(src, dst, cameraMatrix, distCoeffs, newCameraMatrix); - - truth = new Mat(3, 3, CvType.CV_32F, new Scalar(3)); - assertMatEqual(truth, dst, EPS); - } - //undistortPoints(List src, List dst, Mat cameraMatrix, Mat distCoeffs) public void testUndistortPointsListOfPointListOfPointMatMat() { MatOfPoint2f src = new MatOfPoint2f(new Point(1, 2), new Point(3, 4), new Point(-1, -1)); @@ -687,7 +592,7 @@ public class GeometryTest extends OpenCVTestCase { Mat linePoints = new Mat(4, 1, CvType.CV_32FC1); linePoints.put(0, 0, 0.53198653, 0.84675282, 2.5, 3.75); - Geometry.fitLine(points, dst, Imgproc.DIST_L12, 0, 0.01, 0.01); + Geometry.fitLine(points, dst, Geometry.DIST_L12, 0, 0.01, 0.01); assertMatEqual(linePoints, dst, EPS); } @@ -780,4 +685,44 @@ public class GeometryTest extends OpenCVTestCase { assertTrue(bbox.contains(p1)); assertFalse(bbox.contains(p2)); } + + public void testGetAffineTransform() { + MatOfPoint2f src = new MatOfPoint2f(new Point(2, 3), new Point(3, 1), new Point(1, 4)); + MatOfPoint2f dst = new MatOfPoint2f(new Point(3, 3), new Point(7, 4), new Point(5, 6)); + + Mat transform = Geometry.getAffineTransform(src, dst); + + Mat truth = new Mat(2, 3, CvType.CV_64FC1) { + { + put(0, 0, -8, -6, 37); + put(1, 0, -7, -4, 29); + } + }; + assertMatEqual(truth, transform, EPS); + } + + public void testGetRotationMatrix2D() { + Point center = new Point(0, 0); + + dst = Geometry.getRotationMatrix2D(center, 0, 1); + + truth = new Mat(2, 3, CvType.CV_64F) { + { + put(0, 0, 1, 0, 0); + put(1, 0, 0, 1, 0); + } + }; + + assertMatEqual(truth, dst, EPS); + } + + public void testInvertAffineTransform() { + Mat src = new Mat(2, 3, CvType.CV_64F, new Scalar(1)); + + Geometry.invertAffineTransform(src, dst); + + truth = new Mat(2, 3, CvType.CV_64F, new Scalar(0)); + assertMatEqual(truth, dst, EPS); + } + } diff --git a/modules/imgproc/misc/java/test/MomentsTest.java b/modules/geometry/misc/java/test/MomentsTest.java similarity index 90% rename from modules/imgproc/misc/java/test/MomentsTest.java rename to modules/geometry/misc/java/test/MomentsTest.java index 9bec229b20..5647dcbadb 100644 --- a/modules/imgproc/misc/java/test/MomentsTest.java +++ b/modules/geometry/misc/java/test/MomentsTest.java @@ -1,12 +1,12 @@ -package org.opencv.test.imgproc; +package org.opencv.test.geometry; import org.opencv.test.OpenCVTestCase; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.CvType; import org.opencv.core.Scalar; -import org.opencv.imgproc.Imgproc; -import org.opencv.imgproc.Moments; +import org.opencv.geometry.Geometry; +import org.opencv.geometry.Moments; public class MomentsTest extends OpenCVTestCase { @@ -21,7 +21,7 @@ public class MomentsTest extends OpenCVTestCase { } public void testAll() { - Moments res = Imgproc.moments(data); + Moments res = Geometry.moments(data); assertEquals(res.m00, 21.0, EPS); assertEquals(res.m10, 21.0, EPS); assertEquals(res.m01, 21.0, EPS); diff --git a/modules/geometry/misc/js/gen_dict.json b/modules/geometry/misc/js/gen_dict.json index 690f6c9678..853c968ff5 100644 --- a/modules/geometry/misc/js/gen_dict.json +++ b/modules/geometry/misc/js/gen_dict.json @@ -3,7 +3,6 @@ { "": [ "findHomography", - "drawFrameAxes", "estimateAffine2D", "getDefaultNewCameraMatrix", "initUndistortRectifyMap", @@ -13,7 +12,6 @@ "solvePnPRefineLM", "projectPoints", "undistort", - "fisheye_initUndistortRectifyMap", "fisheye_projectPoints", "approxPolyDP", "approxPolyN", @@ -30,7 +28,14 @@ "fitEllipseAMS", "fitEllipseDirect", "fitLine", - "pointPolygonTest" + "pointPolygonTest", + "getAffineTransform", + "getPerspectiveTransform", + "getRotationMatrix2D", + "HuMoments", + "invertAffineTransform", + "moments", + "rotatedRectangleIntersection" ], "UsacParams": ["UsacParams"] } diff --git a/modules/geometry/misc/objc/gen_dict.json b/modules/geometry/misc/objc/gen_dict.json index 713fc99f6d..92ff8aeea9 100644 --- a/modules/geometry/misc/objc/gen_dict.json +++ b/modules/geometry/misc/objc/gen_dict.json @@ -1,5 +1,30 @@ { "namespaces_dict": { "cv.fisheye": "fisheye" + }, + "func_arg_fix" : { + "Geometry" : { + "minEnclosingCircle" : { "points" : {"ctype" : "vector_Point2f"} }, + "fitEllipse" : { "points" : {"ctype" : "vector_Point2f"} }, + "approxPolyDP" : { "curve" : {"ctype" : "vector_Point2f"}, + "approxCurve" : {"ctype" : "vector_Point2f"} }, + "arcLength" : { "curve" : {"ctype" : "vector_Point2f"} }, + "pointPolygonTest" : { "contour" : {"ctype" : "vector_Point2f"} }, + "minAreaRect" : { "points" : {"ctype" : "vector_Point2f"} }, + "getAffineTransform" : { "src" : {"ctype" : "vector_Point2f"}, + "dst" : {"ctype" : "vector_Point2f"} }, + "convexityDefects" : { "contour" : {"ctype" : "vector_Point"}, + "convexhull" : {"ctype" : "vector_int"}, + "convexityDefects" : {"ctype" : "vector_Vec4i"} }, + "isContourConvex" : { "contour" : {"ctype" : "vector_Point"} }, + "convexHull" : { "points" : {"ctype" : "vector_Point"}, + "hull" : {"ctype" : "vector_int"}, + "returnPoints" : {"ctype" : ""} }, + "matchShapes" : { "method" : {"ctype" : "ShapeMatchModes"}}, + "fitLine" : { "distType" : {"ctype" : "DistanceTypes"}} + }, + "Subdiv2D" : { + "(void)insert:(NSArray*)ptvec" : { "insert" : {"name" : "insertVector"} } + } } } diff --git a/modules/geometry/misc/objc/test/Cv3dTest.swift b/modules/geometry/misc/objc/test/Cv3dTest.swift index db68343c3f..f22ebcc9a1 100644 --- a/modules/geometry/misc/objc/test/Cv3dTest.swift +++ b/modules/geometry/misc/objc/test/Cv3dTest.swift @@ -7,7 +7,7 @@ import XCTest import OpenCV -class Cv3dTest: OpenCVTestCase { +class GeometryTest: OpenCVTestCase { var size = Size() @@ -38,7 +38,7 @@ class Cv3dTest: OpenCVTestCase { let outTvec = Mat(rows: 3, cols: 1, type: CvType.CV_32F) try outTvec.put(row: 0, col: 0, data: [1.4560841, 1.0680628, 0.81598103]) - Cv3d.composeRT(rvec1: rvec1, tvec1: tvec1, rvec2: rvec2, tvec2: tvec2, rvec3: rvec3, tvec3: tvec3) + Geometry.composeRT(rvec1: rvec1, tvec1: tvec1, rvec2: rvec2, tvec2: tvec2, rvec3: rvec3, tvec3: tvec3) try assertMatEqual(outRvec, rvec3, OpenCVTestCase.EPS) try assertMatEqual(outTvec, tvec3, OpenCVTestCase.EPS) @@ -59,7 +59,7 @@ class Cv3dTest: OpenCVTestCase { try transformedPoints.put(row:i, col:0, data:[y, x]) } - let hmg = Cv3d.findHomography(srcPoints: originalPoints, dstPoints: transformedPoints) + let hmg = Geometry.findHomography(srcPoints: originalPoints, dstPoints: transformedPoints) truth = Mat(rows: 3, cols: 3, type: CvType.CV_64F) try truth!.put(row:0, col:0, data:[0, 1, 0, 1, 0, 0, 0, 0, 1] as [Double]) @@ -72,14 +72,14 @@ class Cv3dTest: OpenCVTestCase { try r.put(row:0, col:0, data:[.pi, 0, 0] as [Float]) - Cv3d.Rodrigues(src: r, dst: R) + Geometry.Rodrigues(src: r, dst: R) truth = Mat(rows: 3, cols: 3, type: CvType.CV_32F) try truth!.put(row:0, col:0, data:[1, 0, 0, 0, -1, 0, 0, 0, -1] as [Float]) try assertMatEqual(truth!, R, OpenCVTestCase.EPS) let r2 = Mat() - Cv3d.Rodrigues(src: R, dst: r2) + Geometry.Rodrigues(src: R, dst: r2) try assertMatEqual(r, r2, OpenCVTestCase.EPS) } @@ -107,7 +107,7 @@ class Cv3dTest: OpenCVTestCase { let rvec = Mat() let tvec = Mat() - Cv3d.solvePnP(objectPoints: points3d, imagePoints: points2d, cameraMatrix: intrinsics, distCoeffs: MatOfDouble(), rvec: rvec, tvec: tvec) + Geometry.solvePnP(objectPoints: points3d, imagePoints: points2d, cameraMatrix: intrinsics, distCoeffs: MatOfDouble(), rvec: rvec, tvec: tvec) let truth_rvec = Mat(rows: 3, cols: 1, type: CvType.CV_64F) try truth_rvec.put(row: 0, col: 0, data: [0, .pi / 2, 0] as [Double]) @@ -128,7 +128,7 @@ class Cv3dTest: OpenCVTestCase { let lines = Mat() let truth = Mat(rows: 1, cols: 1, type: CvType.CV_32FC3) try truth.put(row: 0, col: 0, data: [-0.70735186, 0.70686162, -0.70588124]) - Cv3d.computeCorrespondEpilines(points: left, whichImage: 1, F: fundamental, lines: lines) + Geometry.computeCorrespondEpilines(points: left, whichImage: 1, F: fundamental, lines: lines) try assertMatEqual(truth, lines, OpenCVTestCase.EPS) } @@ -161,7 +161,7 @@ class Cv3dTest: OpenCVTestCase { let reprojectionError = Mat(rows: 2, cols: 1, type: CvType.CV_64FC1) - Cv3d.solvePnPGeneric(objectPoints: points3d, imagePoints: points2d, cameraMatrix: intrinsics, distCoeffs: MatOfDouble(), rvecs: &rvecs, tvecs: &tvecs, useExtrinsicGuess: false, flags: .SOLVEPNP_IPPE, rvec: rvec, tvec: tvec, reprojectionError: reprojectionError) + Geometry.solvePnPGeneric(objectPoints: points3d, imagePoints: points2d, cameraMatrix: intrinsics, distCoeffs: MatOfDouble(), rvecs: &rvecs, tvecs: &tvecs, useExtrinsicGuess: false, flags: .SOLVEPNP_IPPE, rvec: rvec, tvec: tvec, reprojectionError: reprojectionError) let truth_rvec = Mat(rows: 3, cols: 1, type: CvType.CV_64F) try truth_rvec.put(row: 0, col: 0, data: [0, .pi / 2, 0] as [Double]) @@ -174,14 +174,14 @@ class Cv3dTest: OpenCVTestCase { } func testGetDefaultNewCameraMatrixMat() { - let mtx = Cv3d.getDefaultNewCameraMatrix(cameraMatrix: gray0) + let mtx = Geometry.getDefaultNewCameraMatrix(cameraMatrix: gray0) XCTAssertFalse(mtx.empty()) XCTAssertEqual(0, Core.countNonZero(src: mtx)) } func testGetDefaultNewCameraMatrixMatSizeBoolean() { - let mtx = Cv3d.getDefaultNewCameraMatrix(cameraMatrix: gray0, imgsize: size, centerPrincipalPoint: true) + let mtx = Geometry.getDefaultNewCameraMatrix(cameraMatrix: gray0, imgsize: size, centerPrincipalPoint: true) XCTAssertFalse(mtx.empty()) XCTAssertFalse(0 == Core.countNonZero(src: mtx)) @@ -198,7 +198,7 @@ class Cv3dTest: OpenCVTestCase { let distCoeffs = Mat(rows: 1, cols: 4, type: CvType.CV_32F) try distCoeffs.put(row: 0, col: 0, data: [1, 3, 2, 4] as [Float]) - Cv3d.undistort(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs) + Geometry.undistort(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs) truth = Mat(rows: 3, cols: 3, type: CvType.CV_32F) try truth!.put(row: 0, col: 0, data: [0, 0, 0] as [Float]) @@ -220,7 +220,7 @@ class Cv3dTest: OpenCVTestCase { let newCameraMatrix = Mat(rows: 3, cols: 3, type: CvType.CV_32F, scalar: Scalar(1)) - Cv3d.undistort(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs, newCameraMatrix: newCameraMatrix) + Geometry.undistort(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs, newCameraMatrix: newCameraMatrix) truth = Mat(rows: 3, cols: 3, type: CvType.CV_32F, scalar: Scalar(3)) try assertMatEqual(truth!, dst, OpenCVTestCase.EPS) @@ -233,8 +233,154 @@ class Cv3dTest: OpenCVTestCase { let cameraMatrix = Mat.eye(rows: 3, cols: 3, type: CvType.CV_64FC1) let distCoeffs = Mat(rows: 8, cols: 1, type: CvType.CV_64FC1, scalar: Scalar(0)) - Cv3d.undistortPoints(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs) + Geometry.undistortPoints(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs) XCTAssertEqual(src.toArray(), dst.toArray()) } + + func testApproxPolyDP() { + let curve = [Point2f(x: 1, y: 3), Point2f(x: 2, y: 4), Point2f(x: 3, y: 5), Point2f(x: 4, y: 4), Point2f(x: 5, y: 3)] + + var approxCurve = [Point2f]() + + Geometry.approxPolyDP(curve: curve, approxCurve: &approxCurve, epsilon: OpenCVTestCase.EPS, closed: true) + + let approxCurveGold = [Point2f(x: 1, y: 3), Point2f(x: 3, y: 5), Point2f(x: 5, y: 3)] + + XCTAssert(approxCurve == approxCurveGold) + } + + func testArcLength() { + let curve = [Point2f(x: 1, y: 3), Point2f(x: 2, y: 4), Point2f(x: 3, y: 5), Point2f(x: 4, y: 4), Point2f(x: 5, y: 3)] + + let arcLength = Geometry.arcLength(curve: curve, closed: false) + + XCTAssertEqual(5.656854249, arcLength, accuracy:0.000001) + } + + func testContourAreaMat() throws { + let contour = Mat(rows: 1, cols: 4, type: CvType.CV_32FC2) + try contour.put(row: 0, col: 0, data: [0, 0, 10, 0, 10, 10, 5, 4] as [Float]) + + let area = Geometry.contourArea(contour: contour) + + XCTAssertEqual(45.0, area, accuracy: OpenCVTestCase.EPS) + } + + func testContourAreaMatBoolean() throws { + let contour = Mat(rows: 1, cols: 4, type: CvType.CV_32FC2) + try contour.put(row: 0, col: 0, data: [0, 0, 10, 0, 10, 10, 5, 4] as [Float]) + + let area = Geometry.contourArea(contour: contour, oriented: true) + + XCTAssertEqual(45.0, area, accuracy: OpenCVTestCase.EPS) + } + + func testConvexHullMatMatBooleanBoolean() { + let points = [Point(x: 2, y: 0), + Point(x: 4, y: 0), + Point(x: 3, y: 2), + Point(x: 0, y: 2), + Point(x: 2, y: 1), + Point(x: 3, y: 1)] + + var hull = [Int32]() + + Geometry.convexHull(points: points, hull: &hull, clockwise: true) + + XCTAssert([3, 2, 1, 0] == hull) + } + + func testConvexityDefects() throws { + let points = [Point(x: 20, y: 0), + Point(x: 40, y: 0), + Point(x: 30, y: 20), + Point(x: 0, y: 20), + Point(x: 20, y: 10), + Point(x: 30, y: 10)] + + var hull = [Int32]() + Geometry.convexHull(points: points, hull: &hull) + + var convexityDefects = [Int4]() + Geometry.convexityDefects(contour: points, convexhull: hull, convexityDefects: &convexityDefects) + + XCTAssertTrue(Int4(v0: 3, v1: 0, v2: 5, v3: 3620) == convexityDefects[0]) + } + + func testGetAffineTransform() throws { + let src = [Point2f(x: 2, y: 3), Point2f(x: 3, y: 1), Point2f(x: 1, y: 4)] + let dst = [Point2f(x: 3, y: 3), Point2f(x: 7, y: 4), Point2f(x: 5, y: 6)] + + let transform = Geometry.getAffineTransform(src: src, dst: dst) + + let truth = Mat(rows: 2, cols: 3, type: CvType.CV_64FC1) + + try truth.put(row: 0, col: 0, data: [-8.0, -6.0, 37.0]) + try truth.put(row: 1, col: 0, data: [-7.0, -4.0, 29.0]) + try assertMatEqual(truth, transform, OpenCVTestCase.EPS) + } + + func testGetRotationMatrix2D() throws { + let center = Point2f(x: 0, y: 0) + + dst = Geometry.getRotationMatrix2D(center: center, angle: 0, scale: 1) + + truth = Mat(rows: 2, cols: 3, type: CvType.CV_64F) + try truth!.put(row: 0, col: 0, data: [1.0, 0.0, 0.0]) + try truth!.put(row: 1, col: 0, data: [0.0, 1.0, 0.0]) + + try assertMatEqual(truth!, dst, OpenCVTestCase.EPS) + } + + func testInvertAffineTransform() throws { + let src = Mat(rows: 2, cols: 3, type: CvType.CV_64F, scalar: Scalar(1)) + + Geometry.invertAffineTransform(M: src, iM: dst) + + truth = Mat(rows: 2, cols: 3, type: CvType.CV_64F, scalar: Scalar(0)) + try assertMatEqual(truth!, dst, OpenCVTestCase.EPS) + } + + func testIsContourConvex() { + let contour1 = [Point(x: 0, y: 0), Point(x: 10, y: 0), Point(x: 10, y: 10), Point(x: 5, y: 4)] + + XCTAssertFalse(Geometry.isContourConvex(contour: contour1)) + + let contour2 = [Point(x: 0, y: 0), Point(x: 10, y: 0), Point(x: 10, y: 10), Point(x: 5, y: 6)] + + XCTAssert(Geometry.isContourConvex(contour: contour2)) + } + + func testMinAreaRect() { + let points = [Point2f(x: 1, y: 1), Point2f(x: 5, y: 1), Point2f(x: 4, y: 3), Point2f(x: 6, y: 2)] + + let rrect = Geometry.minAreaRect(points: points) + + XCTAssertEqual(Size2f(width: 5, height: 2), rrect.size) + XCTAssertEqual(0.0, rrect.angle) + XCTAssertEqual(Point2f(x: 3.5, y: 2), rrect.center) + } + + func testMinEnclosingCircle() { + let points = [Point2f(x: 0, y: 0), Point2f(x: -100, y: 0), Point2f(x: 0, y: -100), Point2f(x: 100, y: 0), Point2f(x: 0, y: 100)] + let actualCenter = Point2f() + var radius:Float = 0 + + Geometry.minEnclosingCircle(points: points, center: actualCenter, radius: &radius) + + XCTAssertEqual(Point2f(x: 0, y: 0), actualCenter) + XCTAssertEqual(100.0, radius, accuracy: 1.0) + } + + func testPointPolygonTest() { + let contour = [Point2f(x: 0, y: 0), Point2f(x: 1, y: 3), Point2f(x: 3, y: 4), Point2f(x: 4, y: 3), Point2f(x: 2, y: 1)] + let sign1 = Geometry.pointPolygonTest(contour: contour, pt: Point2f(x: 2, y: 2), measureDist: false) + XCTAssertEqual(1.0, sign1) + + let sign2 = Geometry.pointPolygonTest(contour: contour, pt: Point2f(x: 4, y: 4), measureDist: true) + XCTAssertEqual(-sqrt(0.5), sign2) + } + + } diff --git a/modules/imgproc/perf/perf_moments.cpp b/modules/geometry/perf/perf_moments.cpp similarity index 100% rename from modules/imgproc/perf/perf_moments.cpp rename to modules/geometry/perf/perf_moments.cpp diff --git a/modules/geometry/perf/perf_precomp.hpp b/modules/geometry/perf/perf_precomp.hpp index 26a6605469..59a07bef4d 100644 --- a/modules/geometry/perf/perf_precomp.hpp +++ b/modules/geometry/perf/perf_precomp.hpp @@ -11,4 +11,8 @@ #include #endif +namespace opencv_test { + using namespace perf; +} // namespace + #endif diff --git a/modules/geometry/src/fisheye.cpp b/modules/geometry/src/fisheye.cpp index 65847da113..34e89753a5 100644 --- a/modules/geometry/src/fisheye.cpp +++ b/modules/geometry/src/fisheye.cpp @@ -474,110 +474,6 @@ void cv::fisheye::undistortPoints( InputArray distorted, OutputArray undistorted } } -void cv::fisheye::initUndistortRectifyMap( InputArray K, InputArray D, InputArray R, InputArray P, - const cv::Size& size, int m1type, OutputArray map1, OutputArray map2 ) -{ - CV_INSTRUMENT_REGION(); - - 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.empty() || P.depth() == CV_32F || P.depth() == CV_64F) && (R.empty() || 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)); - - 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(): *D.getMat().ptr(); - - Matx33d RR = Matx33d::eye(); - if (!R.empty() && R.total() * R.channels() == 3) - { - 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); - - Matx33d PP = Matx33d::eye(); - if (!P.empty()) - P.getMat().colRange(0, 3).convertTo(PP, CV_64F); - - Matx33d iR = (PP * RR).inv(cv::DECOMP_SVD); - - for( int i = 0; i < size.height; ++i) - { - float* m1f = map1.getMat().ptr(i); - float* m2f = map2.getMat().ptr(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 u, v; - if( _w <= 0) - { - u = (_x > 0) ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); - v = (_y > 0) ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); - } - else - { - double x = _x/_w, y = _y/_w; - - double r = sqrt(x*x + y*y); - double theta = std::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; - u = f[0]*x*scale + c[0]; - v = f[1]*y*scale + c[1]; - } - - if( m1type == CV_16SC2 ) - { - int iu = cv::saturate_cast(u*static_cast(cv::INTER_TAB_SIZE)); - int iv = cv::saturate_cast(v*static_cast(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); - } - } -} - 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) { @@ -648,18 +544,6 @@ void cv::fisheye::estimateNewCameraMatrixForUndistortRectify(InputArray K, Input 0, 0, 1)).convertTo(P, P.empty() ? K.type() : P.type()); } -void cv::fisheye::undistortImage(InputArray distorted, OutputArray undistorted, - InputArray K, InputArray D, InputArray Knew, const Size& new_size) -{ - CV_INSTRUMENT_REGION(); - - Size size = !new_size.empty() ? new_size : distorted.size(); - - Mat map1, map2; - fisheye::initUndistortRectifyMap(K, D, Matx33d::eye(), Knew, size, CV_16SC2, map1, map2 ); - cv::remap(distorted, undistorted, map1, map2, INTER_LINEAR, BORDER_CONSTANT); -} - bool cv::fisheye::solvePnP( InputArray opoints, InputArray ipoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess, diff --git a/modules/geometry/src/geometry.cpp b/modules/geometry/src/geometry.cpp index 2d8dc9128e..5cba72c35d 100644 --- a/modules/geometry/src/geometry.cpp +++ b/modules/geometry/src/geometry.cpp @@ -40,6 +40,7 @@ //M*/ #include "precomp.hpp" #include "opencv2/core/hal/intrin.hpp" +#include "opencv2/core/softfloat.hpp" using namespace cv; @@ -711,9 +712,204 @@ cv::Rect boundingRect(InputArray array) return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m); } +cv::Matx23d getRotationMatrix2D_(Point2f center, double angle, double scale) +{ + CV_INSTRUMENT_REGION(); + + angle *= CV_PI/180; + double alpha = std::cos(angle)*scale; + double beta = std::sin(angle)*scale; + + Matx23d M( + alpha, beta, (1-alpha)*center.x - beta*center.y, + -beta, alpha, beta*center.x + (1-alpha)*center.y + ); + return M; } -float cv::intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p12, bool handleNested ) +/* Calculates coefficients of perspective transformation + * which maps (xi,yi) to (ui,vi), (i=1,2,3,4): + * + * c00*xi + c01*yi + c02 + * ui = --------------------- + * c20*xi + c21*yi + c22 + * + * c10*xi + c11*yi + c12 + * vi = --------------------- + * c20*xi + c21*yi + c22 + * + * Coefficients are calculated by solving one of 2 linear systems: + * / x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\ + * | x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1| + * | x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2| + * | x3 y3 1 0 0 0 -x3*u3 -y3*u3 |.|c10|=|u3|, + * | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 | |c11| |v0| + * | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 | |c12| |v1| + * | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 | |c20| |v2| + * \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 / \c21/ \v3/ + * + * where: + * cij - matrix coefficients, c22 = 1 + * + * or + * + * / x0 y0 1 0 0 0 -x0*u0 -y0*u0 -u0 \ /c00\ /0\ + * | x1 y1 1 0 0 0 -x1*u1 -y1*u1 -u1 | |c01| |0| + * | x2 y2 1 0 0 0 -x2*u2 -y2*u2 -u2 | |c02| |0| + * | x3 y3 1 0 0 0 -x3*u3 -y3*u3 -u3 |.|c10|=|0|, + * | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 -v0 | |c11| |0| + * | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 -v1 | |c12| |0| + * | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 -v2 | |c20| |0| + * \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 -v3 / |c21| \0/ + * \c22/ + * + * where: + * cij - matrix coefficients, c00^2 + c01^2 + c02^2 + c10^2 + c11^2 + c12^2 + c20^2 + c21^2 + c22^2 = 1 + */ +cv::Mat getPerspectiveTransform(const Point2f src[], const Point2f dst[], int solveMethod) +{ + CV_INSTRUMENT_REGION(); + + // try c22 = 1 + Mat M(3, 3, CV_64F), X8(8, 1, CV_64F, M.ptr()); + double a[8][8], b[8]; + Mat A(8, 8, CV_64F, a), B(8, 1, CV_64F, b); + + for( int i = 0; i < 4; ++i ) + { + a[i][0] = a[i+4][3] = src[i].x; + a[i][1] = a[i+4][4] = src[i].y; + a[i][2] = a[i+4][5] = 1; + a[i][3] = a[i][4] = a[i][5] = + a[i+4][0] = a[i+4][1] = a[i+4][2] = 0; + a[i][6] = -src[i].x*dst[i].x; + a[i][7] = -src[i].y*dst[i].x; + a[i+4][6] = -src[i].x*dst[i].y; + a[i+4][7] = -src[i].y*dst[i].y; + b[i] = dst[i].x; + b[i+4] = dst[i].y; + } + + if (solve(A, B, X8, solveMethod) && norm(A * X8, B) < 1e-8) + { + M.ptr()[8] = 1.; + + return M; + } + + // c00^2 + c01^2 + c02^2 + c10^2 + c11^2 + c12^2 + c20^2 + c21^2 + c22^2 = 1 + hconcat(A, -B, A); + + Mat AtA; + mulTransposed(A, AtA, true); + + Mat D, U; + SVDecomp(AtA, D, U, noArray()); + + Mat X9(9, 1, CV_64F, M.ptr()); + U.col(8).copyTo(X9); + + return M; +} + +/* Calculates coefficients of affine transformation + * which maps (xi,yi) to (ui,vi), (i=1,2,3): + * + * ui = c00*xi + c01*yi + c02 + * + * vi = c10*xi + c11*yi + c12 + * + * Coefficients are calculated by solving linear system: + * / x0 y0 1 0 0 0 \ /c00\ /u0\ + * | x1 y1 1 0 0 0 | |c01| |u1| + * | x2 y2 1 0 0 0 | |c02| |u2| + * | 0 0 0 x0 y0 1 | |c10| |v0| + * | 0 0 0 x1 y1 1 | |c11| |v1| + * \ 0 0 0 x2 y2 1 / |c12| |v2| + * + * where: + * cij - matrix coefficients + */ + +cv::Mat getAffineTransform( const Point2f src[], const Point2f dst[] ) +{ + Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.ptr()); + double a[6*6], b[6]; + Mat A(6, 6, CV_64F, a), B(6, 1, CV_64F, b); + + for( int i = 0; i < 3; i++ ) + { + int j = i*12; + int k = i*12+6; + a[j] = a[k+3] = src[i].x; + a[j+1] = a[k+4] = src[i].y; + a[j+2] = a[k+5] = 1; + a[j+3] = a[j+4] = a[j+5] = 0; + a[k] = a[k+1] = a[k+2] = 0; + b[i*2] = dst[i].x; + b[i*2+1] = dst[i].y; + } + + solve( A, B, X ); + return M; +} + +void invertAffineTransform(InputArray _matM, OutputArray __iM) +{ + Mat matM = _matM.getMat(); + CV_Assert(matM.rows == 2 && matM.cols == 3); + __iM.create(2, 3, matM.type()); + Mat _iM = __iM.getMat(); + + if( matM.type() == CV_32F ) + { + const softfloat* M = matM.ptr(); + softfloat* iM = _iM.ptr(); + int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0])); + + softdouble D = M[0]*M[step+1] - M[1]*M[step]; + D = D != 0. ? softdouble(1.)/D : softdouble(0.); + softdouble A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; + softdouble b1 = -A11*M[2] - A12*M[step+2]; + softdouble b2 = -A21*M[2] - A22*M[step+2]; + + iM[0] = A11; iM[1] = A12; iM[2] = b1; + iM[istep] = A21; iM[istep+1] = A22; iM[istep+2] = b2; + } + else if( matM.type() == CV_64F ) + { + const softdouble* M = matM.ptr(); + softdouble* iM = _iM.ptr(); + int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0])); + + softdouble D = M[0]*M[step+1] - M[1]*M[step]; + D = D != 0. ? softdouble(1.)/D : softdouble(0.); + softdouble A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; + softdouble b1 = -A11*M[2] - A12*M[step+2]; + softdouble b2 = -A21*M[2] - A22*M[step+2]; + + iM[0] = A11; iM[1] = A12; iM[2] = b1; + iM[istep] = A21; iM[istep+1] = A22; iM[istep+2] = b2; + } + else + CV_Error( cv::Error::StsUnsupportedFormat, "" ); +} + +cv::Mat getPerspectiveTransform(InputArray _src, InputArray _dst, int solveMethod) +{ + Mat src = _src.getMat(), dst = _dst.getMat(); + CV_Assert(src.checkVector(2, CV_32F) == 4 && dst.checkVector(2, CV_32F) == 4); + return getPerspectiveTransform((const Point2f*)src.data, (const Point2f*)dst.data, solveMethod); +} + +cv::Mat getAffineTransform(InputArray _src, InputArray _dst) +{ + Mat src = _src.getMat(), dst = _dst.getMat(); + CV_Assert(src.checkVector(2, CV_32F) == 3 && dst.checkVector(2, CV_32F) == 3); + return getAffineTransform((const Point2f*)src.data, (const Point2f*)dst.data); +} + +float intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p12, bool handleNested ) { CV_INSTRUMENT_REGION(); @@ -832,3 +1028,5 @@ float cv::intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p1 } return (float)fabs(area); } + +} // namespace cv diff --git a/modules/geometry/src/hal_replacement.hpp b/modules/geometry/src/hal_replacement.hpp index 8874c9127b..a1378f726e 100644 --- a/modules/geometry/src/hal_replacement.hpp +++ b/modules/geometry/src/hal_replacement.hpp @@ -154,6 +154,38 @@ inline int hal_ni_project_points_pinhole64f(const double* src_data, size_t src_s #define cv_hal_project_points_pinhole64f hal_ni_project_points_pinhole64f //! @endcond +/** + @brief Calculates all of the moments up to the third order of a polygon or rasterized shape for image + @param src_data Source image data + @param src_step Source image step + @param src_type source pints type + @param width Source image width + @param height Source image height + @param binary If it is true, all non-zero image pixels are treated as 1's + @param m Output array of moments (10 values) in the following order: + m00, m10, m01, m20, m11, m02, m30, m21, m12, m03. + @sa moments +*/ +inline int hal_ni_imageMoments(const uchar* src_data, size_t src_step, int src_type, int width, int height, bool binary, double m[10]) +{ return CV_HAL_ERROR_NOT_IMPLEMENTED; } + +/** + @brief Calculates all of the moments up to the third order of a polygon of 2d points + @param src_data Source points (Point 2x32f or 2x32s) + @param src_size Source points count + @param src_type source pints type + @param m Output array of moments (10 values) in the following order: + m00, m10, m01, m20, m11, m02, m30, m21, m12, m03. + @sa moments +*/ +inline int hal_ni_polygonMoments(const uchar* src_data, size_t src_size, int src_type, double m[10]) +{ return CV_HAL_ERROR_NOT_IMPLEMENTED; } + +//! @cond IGNORED +#define cv_hal_imageMoments hal_ni_imageMoments +#define cv_hal_polygonMoments hal_ni_polygonMoments +//! @endcond + //! @} #if defined(__clang__) diff --git a/modules/imgproc/src/moments.cpp b/modules/geometry/src/moments.cpp similarity index 99% rename from modules/imgproc/src/moments.cpp rename to modules/geometry/src/moments.cpp index 287cc125a9..7f4d26142d 100644 --- a/modules/imgproc/src/moments.cpp +++ b/modules/geometry/src/moments.cpp @@ -40,7 +40,8 @@ //M*/ #include "precomp.hpp" -#include "opencl_kernels_imgproc.hpp" +#include "hal_replacement.hpp" +#include "opencl_kernels_geometry.hpp" #include "opencv2/core/hal/intrin.hpp" namespace cv @@ -408,7 +409,7 @@ static bool ocl_moments( InputArray _src, Moments& m, bool binary) if (ntiles == 0) return false; - ocl::Kernel k = ocl::Kernel("moments", ocl::imgproc::moments_oclsrc, + ocl::Kernel k = ocl::Kernel("moments", ocl::geometry::moments_oclsrc, format("-D TILE_SIZE=%d%s", TILE_SIZE, binary ? " -D OP_MOMENTS_BINARY" : "")); diff --git a/modules/imgproc/src/opencl/moments.cl b/modules/geometry/src/opencl/moments.cl similarity index 100% rename from modules/imgproc/src/opencl/moments.cl rename to modules/geometry/src/opencl/moments.cl diff --git a/modules/geometry/src/pinhole.cpp b/modules/geometry/src/pinhole.cpp new file mode 100644 index 0000000000..c1d4ac0435 --- /dev/null +++ b/modules/geometry/src/pinhole.cpp @@ -0,0 +1,352 @@ +/*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*/ + +#include "opencv2/core/types.hpp" +#include "precomp.hpp" +#include "distortion_model.hpp" + +namespace cv { + +Mat getDefaultNewCameraMatrix( InputArray _cameraMatrix, Size imgsize, + bool centerPrincipalPoint ) +{ + Mat cameraMatrix = _cameraMatrix.getMat(); + if( !centerPrincipalPoint && cameraMatrix.type() == CV_64F ) + return cameraMatrix; + + Mat newCameraMatrix; + cameraMatrix.convertTo(newCameraMatrix, CV_64F); + if( centerPrincipalPoint ) + { + newCameraMatrix.ptr()[2] = (imgsize.width-1)*0.5; + newCameraMatrix.ptr()[5] = (imgsize.height-1)*0.5; + } + return newCameraMatrix; +} + +void calibrationMatrixValues( InputArray _cameraMatrix, Size imageSize, + double apertureWidth, double apertureHeight, + double& fovx, double& fovy, double& focalLength, + Point2d& principalPoint, double& aspectRatio ) +{ + CV_INSTRUMENT_REGION(); + + if(_cameraMatrix.size() != Size(3, 3)) + CV_Error(cv::Error::StsUnmatchedSizes, "Size of cameraMatrix must be 3x3!"); + + Matx33d A; + _cameraMatrix.getMat().convertTo(A, CV_64F); + CV_DbgAssert(imageSize.width != 0 && imageSize.height != 0 && A(0, 0) != 0.0 && A(1, 1) != 0.0); + + /* Calculate pixel aspect ratio. */ + aspectRatio = A(1, 1) / A(0, 0); + + /* Calculate number of pixel per realworld unit. */ + double mx, my; + if(apertureWidth != 0.0 && apertureHeight != 0.0) { + mx = imageSize.width / apertureWidth; + my = imageSize.height / apertureHeight; + } else { + mx = 1.0; + my = aspectRatio; + } + + /* Calculate fovx and fovy. */ + fovx = atan2(A(0, 2), A(0, 0)) + atan2(imageSize.width - A(0, 2), A(0, 0)); + fovy = atan2(A(1, 2), A(1, 1)) + atan2(imageSize.height - A(1, 2), A(1, 1)); + fovx *= 180.0 / CV_PI; + fovy *= 180.0 / CV_PI; + + /* Calculate focal length. */ + focalLength = A(0, 0) / mx; + + /* Calculate principle point. */ + principalPoint = Point2d(A(0, 2) / mx, A(1, 2) / my); +} + +static void undistortPointsInternal( const Mat& _src, Mat& _dst, const Mat& _cameraMatrix, + const Mat& _distCoeffs, const Mat& matR, const Mat& matP, TermCriteria criteria) +{ + CV_Assert(criteria.isValid()); + double A[3][3], RR[3][3], k[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + Mat matA(3, 3, CV_64F, A), _Dk; + Mat _RR(3, 3, CV_64F, RR); + cv::Matx33d invMatTilt = cv::Matx33d::eye(); + cv::Matx33d matTilt = cv::Matx33d::eye(); + bool haveDistCoeffs = !_distCoeffs.empty(); + + CV_Assert( (_src.rows == 1 || _src.cols == 1) && + (_dst.rows == 1 || _dst.cols == 1) && + _src.cols + _src.rows - 1 == _dst.rows + _dst.cols - 1 && + (_src.type() == CV_32FC2 || _src.type() == CV_64FC2) && + (_dst.type() == CV_32FC2 || _dst.type() == CV_64FC2)); + + CV_Assert( _cameraMatrix.rows == 3 && _cameraMatrix.cols == 3 && _cameraMatrix.channels() == 1 ); + _cameraMatrix.convertTo(matA, CV_64F); + + if( haveDistCoeffs ) + { + CV_Assert( + (_distCoeffs.rows == 1 || _distCoeffs.cols == 1) && + (_distCoeffs.rows*_distCoeffs.cols == 4 || + _distCoeffs.rows*_distCoeffs.cols == 5 || + _distCoeffs.rows*_distCoeffs.cols == 8 || + _distCoeffs.rows*_distCoeffs.cols == 12 || + _distCoeffs.rows*_distCoeffs.cols == 14)); + + _Dk = Mat( _distCoeffs.rows, _distCoeffs.cols, + CV_MAKETYPE(CV_64F,_distCoeffs.channels()), k); + _distCoeffs.convertTo(_Dk, CV_64F); + CV_Assert(_Dk.ptr() == k); + if (k[12] != 0 || k[13] != 0) + { + computeTiltProjectionMatrix(k[12], k[13], NULL, NULL, NULL, &invMatTilt); + computeTiltProjectionMatrix(k[12], k[13], &matTilt, NULL, NULL); + } + } + + if( !matR.empty() ) + { + CV_Assert( matR.rows == 3 && matR.cols == 3 && matR.channels() == 1 ); + matR.convertTo(_RR, CV_64F); + CV_Assert(_RR.ptr() == &RR[0][0]); + } + else + setIdentity(_RR); + + if( !matP.empty() ) + { + double PP[3][3]; + Mat _PP(3, 3, CV_64F, PP); + CV_Assert( matP.rows == 3 && (matP.cols == 3 || matP.cols == 4)); + matP.colRange(0, 3).convertTo(_PP, CV_64F); + CV_Assert(_PP.ptr() == &PP[0][0]); + _RR = _PP*_RR; + } + + const Point2f* srcf = (const Point2f*)_src.data; + const Point2d* srcd = (const Point2d*)_src.data; + Point2f* dstf = (Point2f*)_dst.data; + Point2d* dstd = (Point2d*)_dst.data; + int stype = _src.type(); + int dtype = _dst.type(); + int sstep = _src.rows == 1 ? 1 : (int)(_src.step/_src.elemSize()); + int dstep = _dst.rows == 1 ? 1 : (int)(_dst.step/_dst.elemSize()); + + double fx = A[0][0]; + double fy = A[1][1]; + double ifx = 1./fx; + double ify = 1./fy; + double cx = A[0][2]; + double cy = A[1][2]; + + int n = _src.rows + _src.cols - 1; + for( int i = 0; i < n; i++ ) + { + double x, y, x0 = 0, y0 = 0, u, v; + if( stype == CV_32FC2 ) + { + x = srcf[i*sstep].x; + y = srcf[i*sstep].y; + } + else + { + x = srcd[i*sstep].x; + y = srcd[i*sstep].y; + } + // [u, v]^T = [fx * x''' + cx, fy * y''' + cy]^T => + // [x''', y''']^T = [(u - cx) / fx, (v - cy) / fy]^T + u = x; v = y; + x = (x - cx)*ifx; + y = (y - cy)*ify; + + if( haveDistCoeffs ) { + // compensate tilt distortion + // s * [x''', y''', 1]^T = matTilt * [x'', y'', 1]^T => + // s * matTilt^{-1} * [x''', y''', 1]^T = [x'', y'', 1]^T => + // (invMatTilt := matTilt^{-1}, vecUntilt := invMatTilt * [x''', y''', 1]^T) + // s * vecUntilt = [x'', y'', 1]^T => + // s * vecUntilt_1 = x'', s * vecUntilt_2 = y'', s * vecUntilt_3 = 1 => + // invProj := s = 1 / vecUntilt_3, x'' = invProj * vecUntilt_1, y'' = invProj * vecUntilt_2 + cv::Vec3d vecUntilt = invMatTilt * cv::Vec3d(x, y, 1); + double invProj = vecUntilt(2) ? 1./vecUntilt(2) : 1; + x0 = x = invProj * vecUntilt(0); + y0 = y = invProj * vecUntilt(1); + + double error = std::numeric_limits::max(); + double prevError = std::numeric_limits::max(); + // compensate distortion iteratively using fixed-point iteration + + // parameter for damped fixed-point iteration + double alpha = 1.; + + for( int j = 0; ; j++ ) + { + if ((criteria.type & TermCriteria::COUNT) && j >= criteria.maxCount) + break; + if ((criteria.type & TermCriteria::EPS) && error < criteria.epsilon) + break; + // r^2 = x'^2 + y'^2 + double r2 = x*x + y*y; + // icdist := (1 + k4 * r^2 + k5 * r^4 + k6 * r^6) / (1 + k1 * r^2 + k2 * r^4 + k3 * r^6) + double icdist = (1 + ((k[7]*r2 + k[6])*r2 + k[5])*r2)/(1 + ((k[4]*r2 + k[1])*r2 + k[0])*r2); + if (icdist < 0) // test: undistortPoints.regression_14583 + { + x = (u - cx)*ifx; + y = (v - cy)*ify; + break; + } + // deltaX := 2 * p1 * x' * y' + p2 * (r^2 + 2 * x'^2) + s1 * r^2 + s2 * r^4 + // deltaY := p1 * (r^2 + 2 * y'^2) + 2 * p2 * x' * y' + s3 * r^2 + s4 * r^4 + double deltaX = 2*k[2]*x*y + k[3]*(r2 + 2*x*x)+ k[8]*r2+k[9]*r2*r2; + double deltaY = k[2]*(r2 + 2*y*y) + 2*k[3]*x*y+ k[10]*r2+k[11]*r2*r2; + // [x'', y'']^T = [x' / icdist + deltaX, y' / icdist + deltaY]^T => + // [x', y']^T = [(x'' - deltaX) * icdist, (y'' - deltaY) * icdist]^T => + // x' = f1(x') := (x'' - deltaX) * icdist, y' = f2(y') := (y'' - deltaY) * icdist + // Damped fixed-point iteration: + // f1(x') = (x'' - deltaX) * icdist, f2(y') = (y'' - deltaY) * icdist + // new_x' = (1 - alpha) * x' + alpha * f1(x'), new_y' = (1 - alpha) * y' + alpha * f2(y') + double new_x = (1. - alpha)*x + alpha*(x0 - deltaX)*icdist; + double new_y = (1. - alpha)*y + alpha*(y0 - deltaY)*icdist; + + if(criteria.type & TermCriteria::EPS) + { + double r4, r6, a1, a2, a3, cdist, icdist2; + double xd, yd, xd0, yd0; + Vec3d vecTilt; + + // r^2 = x'^2 + y'^2 + r2 = new_x*new_x + new_y*new_y; + r4 = r2*r2; + r6 = r4*r2; + a1 = 2*new_x*new_y; + a2 = r2 + 2*new_x*new_x; + a3 = r2 + 2*new_y*new_y; + // cdist := 1 + k1 * r^2 + k2 * r^4 + k3 * r^6 + cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6; + // icdist2 := 1 / (1 + k4 * r^2 + k5 * r^4 + k6 * r^6) + icdist2 = 1./(1 + k[5]*r2 + k[6]*r4 + k[7]*r6); + // x'' = x' * cdist * icdist2 + 2 * p1 * x' * y' + p2 * (r^2 + 2 * x'^2) + s1 * r^2 + s2 * r^4 + // y'' = y' * cdist * icdist2 + p1 * (r^2 + 2 * y'^2) + 2 * p2 * x' * y' + s3 * r^2 + s4 * r^4 + xd0 = new_x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4; + yd0 = new_y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4; + + // s * [x''', y''', 1]^T = matTilt * [x'', y'', 1]^T => + // (vecTilt := matTilt * [x'', y'', 1]^T) + // s * [x''', y''', 1]^T = vecTilt => + // s * x''' = vecTilt_1, s * y''' = vecTilt_2, s = vecTilt_3 => + // invProj := 1 / s = 1 / vecTilt_3, x''' = invProj * vecTilt_1, y''' = invProj * vecTilt_2 + vecTilt = matTilt*cv::Vec3d(xd0, yd0, 1); + invProj = vecTilt(2) ? 1./vecTilt(2) : 1; + xd = invProj * vecTilt(0); + yd = invProj * vecTilt(1); + + // [u, v]^T = [fx * x''' + cx, fy * y''' + cy]^T + double x_proj = xd*fx + cx; + double y_proj = yd*fy + cy; + + error = sqrt( std::pow(x_proj - u, 2) + std::pow(y_proj - v, 2) ); + } + if (error > prevError) { + alpha *= .5; + } else { + x = new_x; + y = new_y; + } + prevError = error; + } + } + + if( !matR.empty() || !matP.empty() ) + { + double xx = RR[0][0]*x + RR[0][1]*y + RR[0][2]; + double yy = RR[1][0]*x + RR[1][1]*y + RR[1][2]; + double ww = 1./(RR[2][0]*x + RR[2][1]*y + RR[2][2]); + x = xx*ww; + y = yy*ww; + } + + if( dtype == CV_32FC2 ) + { + dstf[i*dstep].x = (float)x; + dstf[i*dstep].y = (float)y; + } + else + { + dstd[i*dstep].x = x; + dstd[i*dstep].y = y; + } + } +} + +void undistortPoints(InputArray _src, OutputArray _dst, + InputArray _cameraMatrix, + InputArray _distCoeffs, + InputArray _Rmat, + InputArray _Pmat, + TermCriteria criteria) +{ + Mat src = _src.getMat(), cameraMatrix = _cameraMatrix.getMat(); + Mat distCoeffs = _distCoeffs.getMat(), R = _Rmat.getMat(), P = _Pmat.getMat(); + + int npoints = src.checkVector(2), depth = src.depth(); + if (npoints < 0) + src = src.t(); + npoints = src.checkVector(2); + CV_Assert(npoints >= 0 && src.isContinuous() && (depth == CV_32F || depth == CV_64F)); + + if (src.cols == 2) + src = src.reshape(2); + + _dst.create(npoints, 1, CV_MAKETYPE(depth, 2), -1, true); + Mat dst = _dst.getMat(); + + undistortPointsInternal(src, dst, cameraMatrix, distCoeffs, R, P, criteria); +} + +void undistortImagePoints(InputArray src, OutputArray dst, InputArray cameraMatrix, InputArray distCoeffs, TermCriteria termCriteria) +{ + undistortPoints(src, dst, cameraMatrix, distCoeffs, noArray(), cameraMatrix, termCriteria); +} + +} +/* End of file */ diff --git a/modules/geometry/src/precomp.hpp b/modules/geometry/src/precomp.hpp index 093be57273..1242cd0efd 100644 --- a/modules/geometry/src/precomp.hpp +++ b/modules/geometry/src/precomp.hpp @@ -63,7 +63,6 @@ #include "opencv2/core/utils/trace.hpp" #include "opencv2/geometry.hpp" -#include "opencv2/imgproc.hpp" #include "opencv2/core/ocl.hpp" #include "opencv2/core/hal/intrin.hpp" diff --git a/modules/geometry/src/solvepnp.cpp b/modules/geometry/src/solvepnp.cpp index 03dff956a7..4251927ceb 100644 --- a/modules/geometry/src/solvepnp.cpp +++ b/modules/geometry/src/solvepnp.cpp @@ -87,47 +87,6 @@ static bool approxEqual(double a, double b, double eps) } #endif -void drawFrameAxes(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs, - InputArray rvec, InputArray tvec, float length, int thickness) -{ - CV_INSTRUMENT_REGION(); - - int type = image.type(); - int cn = CV_MAT_CN(type); - CV_CheckType(type, cn == 1 || cn == 3 || cn == 4, - "Number of channels must be 1, 3 or 4" ); - - cv::Mat img = image.getMat(); - CV_Assert(img.total() > 0); - CV_Assert(length > 0); - - // project axes points - std::vector axesPoints; - axesPoints.push_back(Point3f(0, 0, 0)); - axesPoints.push_back(Point3f(length, 0, 0)); - axesPoints.push_back(Point3f(0, length, 0)); - axesPoints.push_back(Point3f(0, 0, length)); - std::vector imagePoints; - projectPoints(axesPoints, rvec, tvec, cameraMatrix, distCoeffs, imagePoints); - - cv::Rect imageRect(0, 0, img.cols, img.rows); - bool allIn = true; - for (size_t i = 0; i < imagePoints.size(); i++) - { - allIn &= imageRect.contains(imagePoints[i]); - } - - if (!allIn) - { - CV_LOG_WARNING(NULL, "Some of projected axes endpoints are out of frame. The drawn axes may be not reliable."); - } - - // draw axes lines - line(image, imagePoints[0], imagePoints[1], Scalar(0, 0, 255), thickness); - line(image, imagePoints[0], imagePoints[2], Scalar(0, 255, 0), thickness); - line(image, imagePoints[0], imagePoints[3], Scalar(255, 0, 0), thickness); -} - bool solvePnP( InputArray opoints, InputArray ipoints, InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec, OutputArray tvec, bool useExtrinsicGuess, int flags ) diff --git a/modules/geometry/src/usac/local_optimization.cpp b/modules/geometry/src/usac/local_optimization.cpp index fff8c33866..6d4a8078eb 100644 --- a/modules/geometry/src/usac/local_optimization.cpp +++ b/modules/geometry/src/usac/local_optimization.cpp @@ -4,7 +4,7 @@ #include "../precomp.hpp" #include "../usac.hpp" -#include "opencv2/imgproc/detail/gcgraph.hpp" +#include "opencv2/geometry/detail/gcgraph.hpp" namespace cv { namespace usac { class GraphCutImpl : public GraphCut { diff --git a/modules/imgproc/test/test_moments.cpp b/modules/geometry/test/test_moments.cpp similarity index 84% rename from modules/imgproc/test/test_moments.cpp rename to modules/geometry/test/test_moments.cpp index 55a49afd9b..381e433ffb 100644 --- a/modules/imgproc/test/test_moments.cpp +++ b/modules/geometry/test/test_moments.cpp @@ -60,9 +60,9 @@ protected: points.push_back(Point(49, 51)); Moments m = moments(points, false); - // double area = contourArea(points); + double area = contourArea(points); - CV_Assert( m.m00 == 0 && m.m01 == 0 && m.m10 == 0 /*&& area == 0*/ ); + CV_Assert( m.m00 == 0 && m.m01 == 0 && m.m10 == 0 && area == 0 ); } catch(...) { @@ -73,4 +73,19 @@ protected: TEST(Imgproc_ContourMoment, small) { CV_SmallContourMomentTest test; test.safe_run(); } +TEST(Imgproc_Moments, degenerateContours) +{ + std::vector c1; + c1.push_back(cv::Point(10,10)); + cv::Moments m1 = cv::moments(c1, false); + EXPECT_EQ(m1.m00, 0); + + std::vector c2; + c2.push_back(cv::Point(0,0)); + c2.push_back(cv::Point(5,5)); + c2.push_back(cv::Point(10,10)); + cv::Moments m2 = cv::moments(c2, false); + EXPECT_EQ(m2.m00, 0); +} + }} // namespace diff --git a/modules/imgproc/CMakeLists.txt b/modules/imgproc/CMakeLists.txt index e750f4535a..9ee827b22a 100644 --- a/modules/imgproc/CMakeLists.txt +++ b/modules/imgproc/CMakeLists.txt @@ -1,4 +1,5 @@ set(the_description "Image Processing") + ocv_add_dispatched_file(accum SSE4_1 AVX AVX2) ocv_add_dispatched_file(bilateral_filter SSE2 AVX2 AVX512_SKX AVX512_ICL) ocv_add_dispatched_file(box_filter SSE2 SSE4_1 AVX2 AVX512_SKX) @@ -11,7 +12,9 @@ ocv_add_dispatched_file(morph SSE2 SSE4_1 AVX2) ocv_add_dispatched_file(smooth SSE2 SSE4_1 AVX2 AVX512_ICL) ocv_add_dispatched_file(sumpixels SSE2 AVX2 AVX512_SKX) ocv_add_dispatched_file(warp_kernels SSE2 SSE4_1 AVX2 NEON NEON_FP16 RVV LASX) -ocv_define_module(imgproc opencv_core WRAP java objc python js) +ocv_add_dispatched_file(undistort SSE2 AVX2) + +ocv_define_module(imgproc opencv_core opencv_geometry WRAP java objc python js) ocv_module_include_directories(opencv_imgproc ${ZLIB_INCLUDE_DIRS}) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index e6796cb292..b7cc07ee15 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -295,19 +295,6 @@ enum InterpolationMasks { //! @addtogroup imgproc_misc //! @{ -//! Distance types for Distance Transform and M-estimators -//! @see distanceTransform, fitLine -enum DistanceTypes { - DIST_USER = -1, //!< User defined distance - DIST_L1 = 1, //!< distance = |x1-x2| + |y1-y2| - DIST_L2 = 2, //!< the simple euclidean distance - DIST_C = 3, //!< distance = max(|x1-x2|,|y1-y2|) - DIST_L12 = 4, //!< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) - DIST_FAIR = 5, //!< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 - DIST_WELSCH = 6, //!< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 - DIST_HUBER = 7 //!< distance = |x|detect(image(roi), lines, ...); lines += Scalar(roi.x, roi.y, roi.x, roi.y);` + @param lines A vector of Vec4f elements specifying the beginning and ending point of a line. Where + Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end. Returned lines are strictly + oriented depending on the gradient. + @param width Vector of widths of the regions, where the lines are found. E.g. Width of line. + @param prec Vector of precisions with which the lines are found. + @param nfa Vector containing number of false alarms in the line region, with precision of 10%. The + bigger the value, logarithmically better the detection. + - -1 corresponds to 10 mean false alarms + - 0 corresponds to 1 mean false alarm + - 1 corresponds to 0.1 mean false alarms + This vector will be calculated only when the objects type is #LSD_REFINE_ADV. + */ + CV_WRAP virtual void detect(InputArray image, OutputArray lines, + OutputArray width = noArray(), OutputArray prec = noArray(), + OutputArray nfa = noArray()) = 0; + + /** @brief Draws the line segments on a given image. + @param image The image, where the lines will be drawn. Should be bigger or equal to the image, + where the lines were found. + @param lines A vector of the lines that needed to be drawn. + */ + CV_WRAP virtual void drawSegments(InputOutputArray image, InputArray lines) = 0; + + /** @brief Draws two groups of lines in blue and red, counting the non overlapping (mismatching) pixels. + + @param size The size of the image, where lines1 and lines2 were found. + @param lines1 The first group of lines that needs to be drawn. It is visualized in blue color. + @param lines2 The second group of lines. They visualized in red color. + @param image Optional image, where the lines will be drawn. The image should be color(3-channel) + in order for lines1 and lines2 to be drawn in the above mentioned colors. + */ + CV_WRAP virtual int compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray image = noArray()) = 0; + + virtual ~LineSegmentDetector() { } +}; + +/** @brief Creates a smart pointer to a LineSegmentDetector object and initializes it. + +The LineSegmentDetector algorithm is defined using the standard values. Only advanced users may want +to edit those, as to tailor it for their own application. + +@param refine The way found lines will be refined, see #LineSegmentDetectorModes +@param scale The scale of the image that will be used to find the lines. Range (0..1]. +@param sigma_scale Sigma for Gaussian filter. It is computed as sigma = sigma_scale/scale. +@param quant Bound to the quantization error on the gradient norm. +@param ang_th Gradient angle tolerance in degrees. +@param log_eps Detection threshold: -log10(NFA) \> log_eps. Used only when advance refinement is chosen. +@param density_th Minimal density of aligned region points in the enclosing rectangle. +@param n_bins Number of bins in pseudo-ordering of gradient modulus. +*/ +CV_EXPORTS_W Ptr createLineSegmentDetector( + LineSegmentDetectorModes refine = LSD_REFINE_STD, double scale = 0.8, + double sigma_scale = 0.6, double quant = 2.0, double ang_th = 22.5, + double log_eps = 0, double density_th = 0.7, int n_bins = 1024); + +//! @} imgproc_feature + //! @addtogroup imgproc_filter //! @{ @@ -2166,89 +2245,252 @@ CV_EXPORTS_W void convertMaps( InputArray map1, InputArray map2, OutputArray dstmap1, OutputArray dstmap2, int dstmap1type, bool nninterpolation = false ); -/** @brief Calculates an affine matrix of 2D rotation. - -The function calculates the following matrix: - -\f[\begin{bmatrix} \alpha & \beta & (1- \alpha ) \cdot \texttt{center.x} - \beta \cdot \texttt{center.y} \\ - \beta & \alpha & \beta \cdot \texttt{center.x} + (1- \alpha ) \cdot \texttt{center.y} \end{bmatrix}\f] - -where - -\f[\begin{array}{l} \alpha = \texttt{scale} \cdot \cos \texttt{angle} , \\ \beta = \texttt{scale} \cdot \sin \texttt{angle} \end{array}\f] - -The transformation maps the rotation center to itself. If this is not the target, adjust the shift. - -@param center Center of the rotation in the source image. -@param angle Rotation angle in degrees. Positive values mean counter-clockwise rotation (the -coordinate origin is assumed to be the top-left corner). -@param scale Isotropic scale factor. - -@sa getAffineTransform, warpAffine, transform - */ -CV_EXPORTS_W Mat getRotationMatrix2D(Point2f center, double angle, double scale); - -/** @sa getRotationMatrix2D */ -CV_EXPORTS Matx23d getRotationMatrix2D_(Point2f center, double angle, double scale); - -inline -Mat getRotationMatrix2D(Point2f center, double angle, double scale) +//! cv::undistort mode +enum UndistortTypes { - return Mat(getRotationMatrix2D_(center, angle, scale), true); + PROJ_SPHERICAL_ORTHO = 0, + PROJ_SPHERICAL_EQRECT = 1 +}; + +/** @brief Transforms an image to compensate for lens distortion. + +The function transforms an image to compensate radial and tangential lens distortion. + +The function is simply a combination of #initUndistortRectifyMap (with unity R ) and #remap +(with bilinear interpolation). See the former function for details of the transformation being +performed. + +Those pixels in the destination image, for which there is no correspondent pixels in the source +image, are filled with zeros (black color). + +A particular subset of the source image that will be visible in the corrected image can be regulated +by newCameraMatrix. You can use #getOptimalNewCameraMatrix to compute the appropriate +newCameraMatrix depending on your requirements. + +The camera matrix and the distortion parameters can be determined using #calibrateCamera. If +the resolution of images is different from the resolution used at the calibration stage, \f$f_x, +f_y, c_x\f$ and \f$c_y\f$ need to be scaled accordingly, while the distortion coefficients remain +the same. + +@param src Input (distorted) image. +@param dst Output (corrected) image that has the same size and type as src . +@param cameraMatrix Input camera matrix \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . +@param distCoeffs Input vector of distortion coefficients +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. +@param newCameraMatrix Camera matrix of the distorted image. By default, it is the same as +cameraMatrix but you may additionally scale and shift the result by using a different matrix. + */ +CV_EXPORTS_W void undistort( InputArray src, OutputArray dst, + InputArray cameraMatrix, + InputArray distCoeffs, + InputArray newCameraMatrix = noArray() ); + +/** @brief Computes the undistortion and rectification transformation map. + +The function computes the joint undistortion and rectification transformation and represents the +result in the form of maps for #remap. The undistorted image looks like original, as if it is +captured with a camera using the camera matrix =newCameraMatrix and zero distortion. In case of a +monocular camera, newCameraMatrix is usually equal to cameraMatrix, or it can be computed by +#getOptimalNewCameraMatrix for a better control over scaling. In case of a stereo camera, +newCameraMatrix is normally set to P1 or P2 computed by #stereoRectify . + +Also, this new camera is oriented differently in the coordinate space, according to R. That, for +example, helps to align two heads of a stereo camera so that the epipolar lines on both images +become horizontal and have the same y- coordinate (in case of a horizontally aligned stereo camera). + +The function actually builds the maps for the inverse mapping algorithm that is used by #remap. That +is, for each pixel \f$(u, v)\f$ in the destination (corrected and rectified) image, the function +computes the corresponding coordinates in the source image (that is, in the original image from +camera). The following process is applied: +\f[ +\begin{array}{l} +x \leftarrow (u - {c'}_x)/{f'}_x \\ +y \leftarrow (v - {c'}_y)/{f'}_y \\ +{[X\,Y\,W]} ^T \leftarrow R^{-1}*[x \, y \, 1]^T \\ +x' \leftarrow X/W \\ +y' \leftarrow Y/W \\ +r^2 \leftarrow x'^2 + y'^2 \\ +x'' \leftarrow x' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} ++ 2p_1 x' y' + p_2(r^2 + 2 x'^2) + s_1 r^2 + s_2 r^4\\ +y'' \leftarrow y' \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} ++ p_1 (r^2 + 2 y'^2) + 2 p_2 x' y' + s_3 r^2 + s_4 r^4 \\ +s\vecthree{x'''}{y'''}{1} = +\vecthreethree{R_{33}(\tau_x, \tau_y)}{0}{-R_{13}((\tau_x, \tau_y)} +{0}{R_{33}(\tau_x, \tau_y)}{-R_{23}(\tau_x, \tau_y)} +{0}{0}{1} R(\tau_x, \tau_y) \vecthree{x''}{y''}{1}\\ +map_x(u,v) \leftarrow x''' f_x + c_x \\ +map_y(u,v) \leftarrow y''' f_y + c_y +\end{array} +\f] +where \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +are the distortion coefficients. + +In case of a stereo camera, this function is called twice: once for each camera head, after +#stereoRectify, which in its turn is called after #stereoCalibrate. But if the stereo camera +was not calibrated, it is still possible to compute the rectification transformations directly from +the fundamental matrix using #stereoRectifyUncalibrated. For each camera, the function computes +homography H as the rectification transformation in a pixel domain, not a rotation matrix R in 3D +space. R can be computed from H as +\f[\texttt{R} = \texttt{cameraMatrix} ^{-1} \cdot \texttt{H} \cdot \texttt{cameraMatrix}\f] +where cameraMatrix can be chosen arbitrarily. + +@param cameraMatrix Input camera matrix \f$A=\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . +@param distCoeffs Input vector of distortion coefficients +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. +@param R Optional rectification transformation in the object space (3x3 matrix). R1 or R2 , +computed by #stereoRectify can be passed here. If the matrix is empty, the identity transformation +is assumed. In #initUndistortRectifyMap R assumed to be an identity matrix. +@param newCameraMatrix New camera matrix \f$A'=\vecthreethree{f_x'}{0}{c_x'}{0}{f_y'}{c_y'}{0}{0}{1}\f$. +@param size Undistorted image size. +@param m1type Type of the first output map that can be CV_32FC1, CV_32FC2 or CV_16SC2, see #convertMaps +@param map1 The first output map. +@param map2 The second output map. + */ +CV_EXPORTS_W +void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, + InputArray R, InputArray newCameraMatrix, + Size size, int m1type, OutputArray map1, OutputArray map2); + +/** @brief Computes the projection and inverse-rectification transformation map. In essense, this is the inverse of +#initUndistortRectifyMap to accomodate stereo-rectification of projectors ('inverse-cameras') in projector-camera pairs. + +The function computes the joint projection and inverse rectification transformation and represents the +result in the form of maps for #remap. The projected image looks like a distorted version of the original which, +once projected by a projector, should visually match the original. In case of a monocular camera, newCameraMatrix +is usually equal to cameraMatrix, or it can be computed by +#getOptimalNewCameraMatrix for a better control over scaling. In case of a projector-camera pair, +newCameraMatrix is normally set to P1 or P2 computed by #stereoRectify . + +The projector is oriented differently in the coordinate space, according to R. In case of projector-camera pairs, +this helps align the projector (in the same manner as #initUndistortRectifyMap for the camera) to create a stereo-rectified pair. This +allows epipolar lines on both images to become horizontal and have the same y-coordinate (in case of a horizontally aligned projector-camera pair). + +The function builds the maps for the inverse mapping algorithm that is used by #remap. That +is, for each pixel \f$(u, v)\f$ in the destination (projected and inverse-rectified) image, the function +computes the corresponding coordinates in the source image (that is, in the original digital image). The following process is applied: + +\f[ +\begin{array}{l} +\text{newCameraMatrix}\\ +x \leftarrow (u - {c'}_x)/{f'}_x \\ +y \leftarrow (v - {c'}_y)/{f'}_y \\ + +\\\text{Undistortion} +\\\scriptsize{\textit{though equation shown is for radial undistortion, function implements cv::undistortPoints()}}\\ +r^2 \leftarrow x^2 + y^2 \\ +\theta \leftarrow \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6}\\ +x' \leftarrow \frac{x}{\theta} \\ +y' \leftarrow \frac{y}{\theta} \\ + +\\\text{Rectification}\\ +{[X\,Y\,W]} ^T \leftarrow R*[x' \, y' \, 1]^T \\ +x'' \leftarrow X/W \\ +y'' \leftarrow Y/W \\ + +\\\text{cameraMatrix}\\ +map_x(u,v) \leftarrow x'' f_x + c_x \\ +map_y(u,v) \leftarrow y'' f_y + c_y +\end{array} +\f] +where \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +are the distortion coefficients vector distCoeffs. + +In case of a stereo-rectified projector-camera pair, this function is called for the projector while #initUndistortRectifyMap is called for the camera head. +This is done after #stereoRectify, which in turn is called after #stereoCalibrate. If the projector-camera pair +is not calibrated, it is still possible to compute the rectification transformations directly from +the fundamental matrix using #stereoRectifyUncalibrated. For the projector and camera, the function computes +homography H as the rectification transformation in a pixel domain, not a rotation matrix R in 3D +space. R can be computed from H as +\f[\texttt{R} = \texttt{cameraMatrix} ^{-1} \cdot \texttt{H} \cdot \texttt{cameraMatrix}\f] +where cameraMatrix can be chosen arbitrarily. + +@param cameraMatrix Input camera matrix \f$A=\vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$ . +@param distCoeffs Input vector of distortion coefficients +\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$ +of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. +@param R Optional rectification transformation in the object space (3x3 matrix). R1 or R2, +computed by #stereoRectify can be passed here. If the matrix is empty, the identity transformation +is assumed. +@param newCameraMatrix New camera matrix \f$A'=\vecthreethree{f_x'}{0}{c_x'}{0}{f_y'}{c_y'}{0}{0}{1}\f$. +@param size Distorted image size. +@param m1type Type of the first output map. Can be CV_32FC1, CV_32FC2 or CV_16SC2, see #convertMaps +@param map1 The first output map for #remap. +@param map2 The second output map for #remap. + */ +CV_EXPORTS_W +void initInverseRectificationMap( InputArray cameraMatrix, InputArray distCoeffs, + InputArray R, InputArray newCameraMatrix, + const Size& size, int m1type, OutputArray map1, OutputArray map2 ); + +//! initializes maps for #remap for wide-angle +CV_EXPORTS +float initWideAngleProjMap(InputArray cameraMatrix, InputArray distCoeffs, + Size imageSize, int destImageWidth, + int m1type, OutputArray map1, OutputArray map2, + enum UndistortTypes projType = PROJ_SPHERICAL_EQRECT, double alpha = 0); +static inline +float initWideAngleProjMap(InputArray cameraMatrix, InputArray distCoeffs, + Size imageSize, int destImageWidth, + int m1type, OutputArray map1, OutputArray map2, + int projType, double alpha = 0) +{ + return initWideAngleProjMap(cameraMatrix, distCoeffs, imageSize, destImageWidth, + m1type, map1, map2, (UndistortTypes)projType, alpha); } -/** @brief Calculates an affine transform from three pairs of the corresponding points. - * - * The function calculates the \f$2 \times 3\f$ matrix of an affine transform so that: - * - * \f[\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] - * - * where - * - * \f[dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2\f] - * - * @param src Coordinates of triangle vertices in the source image. - * @param dst Coordinates of the corresponding triangle vertices in the destination image. - * - * @sa warpAffine, transform +namespace fisheye { + +/** @brief Computes undistortion and rectification maps for image transform by cv::remap(). If D is empty zero +distortion is used, if R or P is empty identity matrixes are used. + +@param K Camera intrinsic matrix \f$cameramatrix{K}\f$. +@param D Input vector of distortion coefficients \f$\distcoeffsfisheye\f$. +@param R Rectification transformation in the object space: 3x3 1-channel, or vector: 3x1/1x3 +1-channel or 1x1 3-channel +@param P New camera intrinsic matrix (3x3) or new projection matrix (3x4) +@param size Undistorted image size. +@param m1type Type of the first output map that can be CV_32FC1 or CV_16SC2 . See convertMaps() +for details. +@param map1 The first output map. +@param map2 The second output map. */ -CV_EXPORTS Mat getAffineTransform( const Point2f src[], const Point2f dst[] ); +CV_EXPORTS_W void initUndistortRectifyMap(InputArray K, InputArray D, InputArray R, InputArray P, + const cv::Size& size, int m1type, OutputArray map1, OutputArray map2); -/** @brief Inverts an affine transformation. - * - * The function computes an inverse affine transformation represented by \f$2 \times 3\f$ matrix M: - * - * \f[\begin{bmatrix} a_{11} & a_{12} & b_1 \\ a_{21} & a_{22} & b_2 \end{bmatrix}\f] - * - * The result is also a \f$2 \times 3\f$ matrix of the same type as M. - * - * @param M Original affine transformation. - * @param iM Output reverse affine transformation. +/** @brief Transforms an image to compensate for fisheye lens distortion. + +@param distorted image with fisheye lens distortion. +@param undistorted Output image with compensated fisheye lens distortion. +@param K Camera intrinsic matrix \f$cameramatrix{K}\f$. +@param D Input vector of distortion coefficients \f$\distcoeffsfisheye\f$. +@param Knew Camera intrinsic matrix of the distorted image. By default, it is the identity matrix but you +may additionally scale and shift the result by using a different matrix. +@param new_size the new size + +The function transforms an image to compensate radial and tangential lens distortion. + +The function is simply a combination of #cv::fisheye::initUndistortRectifyMap (with unity R ) and remap +(with bilinear interpolation). See the former function for details of the transformation being +performed. + +See below the results of undistortImage. + - a\) result of undistort of perspective camera model (all possible coefficients (k_1, k_2, k_3, + k_4, k_5, k_6) of distortion were optimized under calibration) + - b\) result of #cv::fisheye::undistortImage of fisheye camera model (all possible coefficients (k_1, k_2, + k_3, k_4) of fisheye distortion were optimized under calibration) + - c\) original image was captured with fisheye lens + +Pictures a) and b) almost the same. But if we consider points of image located far from the center +of image, we can notice that on image a) these points are distorted. + +![image](pics/fisheye_undistorted.jpg) */ -CV_EXPORTS_W void invertAffineTransform( InputArray M, OutputArray iM ); +CV_EXPORTS_W void undistortImage(InputArray distorted, OutputArray undistorted, + InputArray K, InputArray D, InputArray Knew = cv::noArray(), const Size& new_size = Size()); -/** @brief Calculates a perspective transform from four pairs of the corresponding points. - * - * The function calculates the \f$3 \times 3\f$ matrix of a perspective transform so that: - * - * \f[\begin{bmatrix} t_i x'_i \\ t_i y'_i \\ t_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f] - * - * where - * - * \f[dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2,3\f] - * - * @param src Coordinates of quadrangle vertices in the source image. - * @param dst Coordinates of the corresponding quadrangle vertices in the destination image. - * @param solveMethod method passed to cv::solve (#DecompTypes) - * - * @sa findHomography, warpPerspective, perspectiveTransform - */ -CV_EXPORTS_W Mat getPerspectiveTransform(InputArray src, InputArray dst, int solveMethod = DECOMP_LU); - -/** @overload */ -CV_EXPORTS Mat getPerspectiveTransform(const Point2f src[], const Point2f dst[], int solveMethod = DECOMP_LU); - - -CV_EXPORTS_W Mat getAffineTransform( InputArray src, InputArray dst ); +} /** @brief Retrieves a pixel rectangle from an image with sub-pixel accuracy. @@ -3337,65 +3579,6 @@ CV_EXPORTS_W void demosaicing(InputArray src, OutputArray dst, int code, int dst //! @} imgproc_color_conversions -//! @addtogroup imgproc_shape -//! @{ - -/** @brief Calculates all of the moments up to the third order of a polygon or rasterized shape. - -The function computes moments, up to the 3rd order, of a vector shape or a rasterized shape. The -results are returned in the structure cv::Moments. - -@param array Single channel raster image (CV_8U, CV_16U, CV_16S, CV_32F, CV_64F) or an array ( -\f$1 \times N\f$ or \f$N \times 1\f$ ) of 2D points (Point or Point2f). -@param binaryImage If it is true, all non-zero image pixels are treated as 1's. The parameter is -used for images only. -@returns moments. - -@note Only applicable to contour moments calculations from Python bindings: Note that the numpy -type for the input array should be either np.int32 or np.float32. - -@note For contour-based moments, the zeroth-order moment \c m00 represents -the contour area. - -If the input contour is degenerate (for example, a single point or all points -are collinear), the area is zero and therefore \c m00 == 0. - -In this case, the centroid coordinates (\c m10/m00, \c m01/m00) are undefined -and must be handled explicitly by the caller. - -A common workaround is to compute the center using cv::boundingRect() or by -averaging the input points. - -@sa contourArea, arcLength - */ -CV_EXPORTS_W Moments moments( InputArray array, bool binaryImage = false ); - -/** @brief Calculates seven Hu invariants. - -The function calculates seven Hu invariants (introduced in @cite Hu62; see also -) defined as: - -\f[\begin{array}{l} hu[0]= \eta _{20}+ \eta _{02} \\ hu[1]=( \eta _{20}- \eta _{02})^{2}+4 \eta _{11}^{2} \\ hu[2]=( \eta _{30}-3 \eta _{12})^{2}+ (3 \eta _{21}- \eta _{03})^{2} \\ hu[3]=( \eta _{30}+ \eta _{12})^{2}+ ( \eta _{21}+ \eta _{03})^{2} \\ hu[4]=( \eta _{30}-3 \eta _{12})( \eta _{30}+ \eta _{12})[( \eta _{30}+ \eta _{12})^{2}-3( \eta _{21}+ \eta _{03})^{2}]+(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ hu[5]=( \eta _{20}- \eta _{02})[( \eta _{30}+ \eta _{12})^{2}- ( \eta _{21}+ \eta _{03})^{2}]+4 \eta _{11}( \eta _{30}+ \eta _{12})( \eta _{21}+ \eta _{03}) \\ hu[6]=(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}]-( \eta _{30}-3 \eta _{12})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ \end{array}\f] - -where \f$\eta_{ji}\f$ stands for \f$\texttt{Moments::nu}_{ji}\f$ . - -These values are proved to be invariants to the image scale, rotation, and reflection except the -seventh one, whose sign is changed by reflection. This invariance is proved with the assumption of -infinite image resolution. In case of raster images, the computed Hu invariants for the original and -transformed images are a bit different. - -@param moments Input moments computed with moments . -@param hu Output Hu invariants. - -@sa matchShapes - */ -CV_EXPORTS void HuMoments( const Moments& moments, double hu[7] ); - -/** @overload */ -CV_EXPORTS_W void HuMoments( const Moments& m, OutputArray hu ); - -//! @} imgproc_shape - //! @addtogroup imgproc_object //! @{ @@ -3719,6 +3902,26 @@ The function cv::arrowedLine draws an arrow between pt1 and pt2 points in the im CV_EXPORTS_W void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int line_type=8, int shift=0, double tipLength=0.1); +/** @brief Draw axes of the world/object coordinate system from pose estimation. @sa solvePnP + * + * @param image Input/output image. It must have 1 or 3 channels. The number of channels is not altered. + * @param cameraMatrix Input 3x3 floating-point matrix of camera intrinsic parameters. + * \f$\cameramatrix{A}\f$ + * @param distCoeffs Input vector of distortion coefficients + * \f$\distcoeffs\f$. If the vector is empty, the zero distortion coefficients are assumed. + * @param rvec Rotation vector (see @ref Rodrigues ) that, together with tvec, brings points from + * the model coordinate system to the camera coordinate system. + * @param tvec Translation vector. + * @param length Length of the painted axes in the same unit than tvec (usually in meters). + * @param thickness Line thickness of the painted axes. + * + * This function draws the axes of the world/object coordinate system w.r.t. to the camera frame. + * OX is drawn in red, OY in green and OZ in blue. + */ +CV_EXPORTS_W void drawFrameAxes(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs, + InputArray rvec, InputArray tvec, float length, int thickness=3); + + /** @brief Draws a simple, thick, or filled up-right rectangle. The function cv::rectangle draws a rectangle outline or a filled rectangle whose two opposite corners diff --git a/modules/imgproc/misc/java/gen_dict.json b/modules/imgproc/misc/java/gen_dict.json index accb4959b3..0f2dd62a56 100644 --- a/modules/imgproc/misc/java/gen_dict.json +++ b/modules/imgproc/misc/java/gen_dict.json @@ -105,26 +105,7 @@ } }, "func_arg_fix" : { - "minEnclosingCircle" : { "points" : {"ctype" : "vector_Point2f"} }, - "fitEllipse" : { "points" : {"ctype" : "vector_Point2f"} }, - "fillPoly" : { "pts" : {"ctype" : "vector_vector_Point"} }, - "polylines" : { "pts" : {"ctype" : "vector_vector_Point"} }, - "fillConvexPoly" : { "points" : {"ctype" : "vector_Point"} }, - "approxPolyDP" : { "curve" : {"ctype" : "vector_Point2f"}, - "approxCurve" : {"ctype" : "vector_Point2f"} }, - "arcLength" : { "curve" : {"ctype" : "vector_Point2f"} }, - "pointPolygonTest" : { "contour" : {"ctype" : "vector_Point2f"} }, - "minAreaRect" : { "points" : {"ctype" : "vector_Point2f"} }, - "getAffineTransform" : { "src" : {"ctype" : "vector_Point2f"}, - "dst" : {"ctype" : "vector_Point2f"} }, "drawContours" : {"contours" : {"ctype" : "vector_vector_Point"} }, - "findContours" : {"contours" : {"ctype" : "vector_vector_Point"} }, - "convexityDefects" : { "contour" : {"ctype" : "vector_Point"}, - "convexhull" : {"ctype" : "vector_int"}, - "convexityDefects" : {"ctype" : "vector_Vec4i"} }, - "isContourConvex" : { "contour" : {"ctype" : "vector_Point"} }, - "convexHull" : { "points" : {"ctype" : "vector_Point"}, - "hull" : {"ctype" : "vector_int"}, - "returnPoints" : {"ctype" : ""} } + "findContours" : {"contours" : {"ctype" : "vector_vector_Point"} } } } diff --git a/modules/imgproc/misc/java/test/ImgprocTest.java b/modules/imgproc/misc/java/test/ImgprocTest.java index 6e2ef437ba..5c833e1162 100644 --- a/modules/imgproc/misc/java/test/ImgprocTest.java +++ b/modules/imgproc/misc/java/test/ImgprocTest.java @@ -19,6 +19,7 @@ import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.core.TermCriteria; import org.opencv.imgproc.Imgproc; +import org.opencv.geometry.Geometry; import org.opencv.test.OpenCVTestCase; public class ImgprocTest extends OpenCVTestCase { @@ -524,7 +525,7 @@ public class ImgprocTest extends OpenCVTestCase { Mat dstLables = getMat(CvType.CV_32SC1, 0); Mat labels = new Mat(); - Imgproc.distanceTransformWithLabels(gray128, dst, labels, Imgproc.DIST_L2, 3); + Imgproc.distanceTransformWithLabels(gray128, dst, labels, Geometry.DIST_L2, 3); assertMatEqual(dstLables, labels); assertMatEqual(getMat(CvType.CV_32FC1, 65533.805), dst, EPS); @@ -741,21 +742,6 @@ public class ImgprocTest extends OpenCVTestCase { // TODO_: write better test } - public void testGetAffineTransform() { - MatOfPoint2f src = new MatOfPoint2f(new Point(2, 3), new Point(3, 1), new Point(1, 4)); - MatOfPoint2f dst = new MatOfPoint2f(new Point(3, 3), new Point(7, 4), new Point(5, 6)); - - Mat transform = Imgproc.getAffineTransform(src, dst); - - Mat truth = new Mat(2, 3, CvType.CV_64FC1) { - { - put(0, 0, -8, -6, 37); - put(1, 0, -7, -4, 29); - } - }; - assertMatEqual(truth, transform, EPS); - } - public void testGetDerivKernelsMatMatIntIntInt() { Mat kx = new Mat(imgprocSz, imgprocSz, CvType.CV_32F); Mat ky = new Mat(imgprocSz, imgprocSz, CvType.CV_32F); @@ -833,21 +819,6 @@ public class ImgprocTest extends OpenCVTestCase { assertMatEqual(truth, dst, EPS); } - public void testGetRotationMatrix2D() { - Point center = new Point(0, 0); - - dst = Imgproc.getRotationMatrix2D(center, 0, 1); - - truth = new Mat(2, 3, CvType.CV_64F) { - { - put(0, 0, 1, 0, 0); - put(1, 0, 0, 1, 0); - } - }; - - assertMatEqual(truth, dst, EPS); - } - public void testGetStructuringElementIntSize() { dst = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, size); @@ -1095,15 +1066,6 @@ public class ImgprocTest extends OpenCVTestCase { assertMatEqual(truth, dst, EPS); } - public void testInvertAffineTransform() { - Mat src = new Mat(2, 3, CvType.CV_64F, new Scalar(1)); - - Imgproc.invertAffineTransform(src, dst); - - truth = new Mat(2, 3, CvType.CV_64F, new Scalar(0)); - assertMatEqual(truth, dst, EPS); - } - public void testLaplacianMatMatInt() { Imgproc.Laplacian(gray0, dst, CvType.CV_8U); @@ -1863,4 +1825,98 @@ public class ImgprocTest extends OpenCVTestCase { Imgproc.rectangle(img, new Point(10, 10), new Point(labelSize.width + 10, labelSize.height + 10), colorBlack, Imgproc.FILLED); assertEquals(0, Core.countNonZero(img)); } + public void testInitUndistortRectifyMap() { + fail("Not yet implemented"); + Mat cameraMatrix = new Mat(3, 3, CvType.CV_32F); + cameraMatrix.put(0, 0, 1, 0, 1); + cameraMatrix.put(1, 0, 0, 1, 1); + cameraMatrix.put(2, 0, 0, 0, 1); + + Mat R = new Mat(3, 3, CvType.CV_32F, new Scalar(2)); + Mat newCameraMatrix = new Mat(3, 3, CvType.CV_32F, new Scalar(3)); + + Mat distCoeffs = new Mat(); + Mat map1 = new Mat(); + Mat map2 = new Mat(); + + // TODO: complete this test + Imgproc.initUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, size, CvType.CV_32F, map1, map2); + } + + public void testInitWideAngleProjMapMatMatSizeIntIntMatMat() { + fail("Not yet implemented"); + Mat cameraMatrix = new Mat(3, 3, CvType.CV_32F); + Mat distCoeffs = new Mat(1, 4, CvType.CV_32F); + // Size imageSize = new Size(2, 2); + + cameraMatrix.put(0, 0, 1, 0, 1); + cameraMatrix.put(1, 0, 0, 1, 2); + cameraMatrix.put(2, 0, 0, 0, 1); + + distCoeffs.put(0, 0, 1, 3, 2, 4); + truth = new Mat(3, 3, CvType.CV_32F); + truth.put(0, 0, 0, 0, 0); + truth.put(1, 0, 0, 0, 0); + truth.put(2, 0, 0, 3, 0); + // TODO: No documentation for this function + // Imgproc.initWideAngleProjMap(cameraMatrix, distCoeffs, imageSize, + // 5, m1type, truthput1, truthput2); + } + + public void testInitWideAngleProjMapMatMatSizeIntIntMatMatInt() { + fail("Not yet implemented"); + } + + public void testInitWideAngleProjMapMatMatSizeIntIntMatMatIntDouble() { + fail("Not yet implemented"); + } + + public void testUndistortMatMatMatMat() { + Mat src = new Mat(3, 3, CvType.CV_32F, new Scalar(3)); + Mat cameraMatrix = new Mat(3, 3, CvType.CV_32F) { + { + put(0, 0, 1, 0, 1); + put(1, 0, 0, 1, 2); + put(2, 0, 0, 0, 1); + } + }; + Mat distCoeffs = new Mat(1, 4, CvType.CV_32F) { + { + put(0, 0, 1, 3, 2, 4); + } + }; + + Imgproc.undistort(src, dst, cameraMatrix, distCoeffs); + + truth = new Mat(3, 3, CvType.CV_32F) { + { + put(0, 0, 0, 0, 0); + put(1, 0, 0, 0, 0); + put(2, 0, 0, 3, 0); + } + }; + assertMatEqual(truth, dst, EPS); + } + + public void testUndistortMatMatMatMatMat() { + Mat src = new Mat(3, 3, CvType.CV_32F, new Scalar(3)); + Mat cameraMatrix = new Mat(3, 3, CvType.CV_32F) { + { + put(0, 0, 1, 0, 1); + put(1, 0, 0, 1, 2); + put(2, 0, 0, 0, 1); + } + }; + Mat distCoeffs = new Mat(1, 4, CvType.CV_32F) { + { + put(0, 0, 2, 1, 4, 5); + } + }; + Mat newCameraMatrix = new Mat(3, 3, CvType.CV_32F, new Scalar(1)); + + Imgproc.undistort(src, dst, cameraMatrix, distCoeffs, newCameraMatrix); + + truth = new Mat(3, 3, CvType.CV_32F, new Scalar(3)); + assertMatEqual(truth, dst, EPS); + } } diff --git a/modules/imgproc/misc/js/gen_dict.json b/modules/imgproc/misc/js/gen_dict.json index 6b8b7f842c..5c01ddc4de 100644 --- a/modules/imgproc/misc/js/gen_dict.json +++ b/modules/imgproc/misc/js/gen_dict.json @@ -32,6 +32,7 @@ "distanceTransformWithLabels", "drawContours", "drawMarker", + "drawFrameAxes", "ellipse", "ellipse2Poly", "equalizeHist", @@ -42,26 +43,21 @@ "findContours", "findContoursLinkRuns", "floodFill", + "fisheye_initUndistortRectifyMap", "GaussianBlur", - "getAffineTransform", "getFontScaleFromHeight", - "getPerspectiveTransform", "getRectSubPix", - "getRotationMatrix2D", "getStructuringElement", "grabCut", "HoughCircles", "HoughLines", "HoughLinesP", - "HuMoments", "integral", "integral2", - "invertAffineTransform", "Laplacian", "line", "matchTemplate", "medianBlur", - "moments", "morphologyEx", "polylines", "preCornerDetect", @@ -71,7 +67,6 @@ "rectangle", "remap", "resize", - "rotatedRectangleIntersection", "Scharr", "sepFilter2D", "Sobel", diff --git a/modules/imgproc/misc/objc/gen_dict.json b/modules/imgproc/misc/objc/gen_dict.json index 997b2c0ca3..995ade982a 100644 --- a/modules/imgproc/misc/objc/gen_dict.json +++ b/modules/imgproc/misc/objc/gen_dict.json @@ -45,39 +45,22 @@ }, "func_arg_fix" : { "Imgproc" : { - "minEnclosingCircle" : { "points" : {"ctype" : "vector_Point2f"} }, - "fitEllipse" : { "points" : {"ctype" : "vector_Point2f"} }, "fillPoly" : { "pts" : {"ctype" : "vector_vector_Point"}, "lineType" : {"ctype" : "LineTypes"}}, "polylines" : { "pts" : {"ctype" : "vector_vector_Point"}, "lineType" : {"ctype" : "LineTypes"} }, "fillConvexPoly" : { "points" : {"ctype" : "vector_Point"}, "lineType" : {"ctype" : "LineTypes"} }, - "approxPolyDP" : { "curve" : {"ctype" : "vector_Point2f"}, - "approxCurve" : {"ctype" : "vector_Point2f"} }, - "arcLength" : { "curve" : {"ctype" : "vector_Point2f"} }, - "pointPolygonTest" : { "contour" : {"ctype" : "vector_Point2f"} }, - "minAreaRect" : { "points" : {"ctype" : "vector_Point2f"} }, - "getAffineTransform" : { "src" : {"ctype" : "vector_Point2f"}, - "dst" : {"ctype" : "vector_Point2f"} }, "drawContours" : { "contours" : {"ctype" : "vector_vector_Point"}, "lineType" : {"ctype" : "LineTypes"} }, "findContours" : { "contours" : {"ctype" : "vector_vector_Point"}, "mode" : {"ctype" : "RetrievalModes"}, "method" : {"ctype" : "ContourApproximationModes"} }, - "convexityDefects" : { "contour" : {"ctype" : "vector_Point"}, - "convexhull" : {"ctype" : "vector_int"}, - "convexityDefects" : {"ctype" : "vector_Vec4i"} }, - "isContourConvex" : { "contour" : {"ctype" : "vector_Point"} }, - "convexHull" : { "points" : {"ctype" : "vector_Point"}, - "hull" : {"ctype" : "vector_int"}, - "returnPoints" : {"ctype" : ""} }, "getStructuringElement" : { "shape" : {"ctype" : "MorphShapes"} }, "EMD" : {"lowerBound" : {"defval" : "cv::Ptr()"}, "distType" : {"ctype" : "DistanceTypes"}}, "createLineSegmentDetector" : { "_refine" : {"ctype" : "LineSegmentDetectorModes"}}, "compareHist" : { "method" : {"ctype" : "HistCompMethods"}}, - "matchShapes" : { "method" : {"ctype" : "ShapeMatchModes"}}, "threshold" : { "type" : {"ctype" : "ThresholdTypes"}}, "connectedComponentsWithStatsWithAlgorithm" : { "ccltype" : {"ctype" : "ConnectedComponentsAlgorithmsTypes"}}, "GaussianBlur" : { "borderType" : {"ctype" : "BorderTypes"}}, @@ -108,7 +91,6 @@ "ellipse" : { "lineType" : {"ctype" : "LineTypes"}}, "erode" : { "borderType" : {"ctype" : "BorderTypes"}}, "filter2D" : { "borderType" : {"ctype" : "BorderTypes"}}, - "fitLine" : { "distType" : {"ctype" : "DistanceTypes"}}, "line" : { "lineType" : {"ctype" : "LineTypes"}}, "matchTemplate" : { "method" : {"ctype" : "TemplateMatchModes"}}, "morphologyEx" : { "op" : {"ctype" : "MorphTypes"}, @@ -126,9 +108,6 @@ "warpAffine" : { "borderMode": {"ctype" : "BorderTypes"}}, "warpPerspective" : { "borderMode": {"ctype" : "BorderTypes"}}, "getTextSize" : { "fontFace": {"ctype" : "HersheyFonts"}} - }, - "Subdiv2D" : { - "(void)insert:(NSArray*)ptvec" : { "insert" : {"name" : "insertVector"} } } }, "type_dict": { diff --git a/modules/imgproc/misc/objc/test/ImgprocTest.swift b/modules/imgproc/misc/objc/test/ImgprocTest.swift index 8a32ecb236..8ed79131a3 100644 --- a/modules/imgproc/misc/objc/test/ImgprocTest.swift +++ b/modules/imgproc/misc/objc/test/ImgprocTest.swift @@ -122,26 +122,6 @@ class ImgprocTest: OpenCVTestCase { XCTAssertEqual(src.rows(), Core.countNonZero(src: dst)) } - func testApproxPolyDP() { - let curve = [Point2f(x: 1, y: 3), Point2f(x: 2, y: 4), Point2f(x: 3, y: 5), Point2f(x: 4, y: 4), Point2f(x: 5, y: 3)] - - var approxCurve = [Point2f]() - - Imgproc.approxPolyDP(curve: curve, approxCurve: &approxCurve, epsilon: OpenCVTestCase.EPS, closed: true) - - let approxCurveGold = [Point2f(x: 1, y: 3), Point2f(x: 3, y: 5), Point2f(x: 5, y: 3)] - - XCTAssert(approxCurve == approxCurveGold) - } - - func testArcLength() { - let curve = [Point2f(x: 1, y: 3), Point2f(x: 2, y: 4), Point2f(x: 3, y: 5), Point2f(x: 4, y: 4), Point2f(x: 5, y: 3)] - - let arcLength = Imgproc.arcLength(curve: curve, closed: false) - - XCTAssertEqual(5.656854249, arcLength, accuracy:0.000001) - } - func testBilateralFilterMatMatIntDoubleDouble() throws { Imgproc.bilateralFilter(src: gray255, dst: dst, d: 5, sigmaColor: 10, sigmaSpace: 5) @@ -315,24 +295,6 @@ class ImgprocTest: OpenCVTestCase { XCTAssertEqual(1.0, distance, accuracy: OpenCVTestCase.EPS) } - func testContourAreaMat() throws { - let contour = Mat(rows: 1, cols: 4, type: CvType.CV_32FC2) - try contour.put(row: 0, col: 0, data: [0, 0, 10, 0, 10, 10, 5, 4] as [Float]) - - let area = Imgproc.contourArea(contour: contour) - - XCTAssertEqual(45.0, area, accuracy: OpenCVTestCase.EPS) - } - - func testContourAreaMatBoolean() throws { - let contour = Mat(rows: 1, cols: 4, type: CvType.CV_32FC2) - try contour.put(row: 0, col: 0, data: [0, 0, 10, 0, 10, 10, 5, 4] as [Float]) - - let area = Imgproc.contourArea(contour: contour, oriented: true) - - XCTAssertEqual(45.0, area, accuracy: OpenCVTestCase.EPS) - } - func testConvertMapsMatMatMatMatInt() throws { let map1 = Mat(rows: 1, cols: 4, type: CvType.CV_32FC1, scalar: Scalar(1)) let map2 = Mat(rows: 1, cols: 4, type: CvType.CV_32FC1, scalar: Scalar(2)) @@ -379,38 +341,6 @@ class ImgprocTest: OpenCVTestCase { XCTAssert([0, 1, 2, 3] == hull) } - func testConvexHullMatMatBooleanBoolean() { - let points = [Point(x: 2, y: 0), - Point(x: 4, y: 0), - Point(x: 3, y: 2), - Point(x: 0, y: 2), - Point(x: 2, y: 1), - Point(x: 3, y: 1)] - - var hull = [Int32]() - - Imgproc.convexHull(points: points, hull: &hull, clockwise: true) - - XCTAssert([3, 2, 1, 0] == hull) - } - - func testConvexityDefects() throws { - let points = [Point(x: 20, y: 0), - Point(x: 40, y: 0), - Point(x: 30, y: 20), - Point(x: 0, y: 20), - Point(x: 20, y: 10), - Point(x: 30, y: 10)] - - var hull = [Int32]() - Imgproc.convexHull(points: points, hull: &hull) - - var convexityDefects = [Int4]() - Imgproc.convexityDefects(contour: points, convexhull: hull, convexityDefects: &convexityDefects) - - XCTAssertTrue(Int4(v0: 3, v1: 0, v2: 5, v3: 3620) == convexityDefects[0]) - } - func testCornerEigenValsAndVecsMatMatIntInt() throws { let src = Mat(rows: imgprocSz, cols: imgprocSz, type: CvType.CV_32FC1) try src.put(row: 0, col: 0, data: [1, 2] as [Float]) @@ -733,19 +663,6 @@ class ImgprocTest: OpenCVTestCase { try assertMatEqual(gray2, dst) } - func testGetAffineTransform() throws { - let src = [Point2f(x: 2, y: 3), Point2f(x: 3, y: 1), Point2f(x: 1, y: 4)] - let dst = [Point2f(x: 3, y: 3), Point2f(x: 7, y: 4), Point2f(x: 5, y: 6)] - - let transform = Imgproc.getAffineTransform(src: src, dst: dst) - - let truth = Mat(rows: 2, cols: 3, type: CvType.CV_64FC1) - - try truth.put(row: 0, col: 0, data: [-8.0, -6.0, 37.0]) - try truth.put(row: 1, col: 0, data: [-7.0, -4.0, 29.0]) - try assertMatEqual(truth, transform, OpenCVTestCase.EPS) - } - func testGetDerivKernelsMatMatIntIntInt() throws { let kx = Mat(rows: imgprocSz, cols: imgprocSz, type: CvType.CV_32F) let ky = Mat(rows: imgprocSz, cols: imgprocSz, type: CvType.CV_32F) @@ -819,18 +736,6 @@ class ImgprocTest: OpenCVTestCase { try assertMatEqual(truth!, dst, OpenCVTestCase.EPS) } - func testGetRotationMatrix2D() throws { - let center = Point2f(x: 0, y: 0) - - dst = Imgproc.getRotationMatrix2D(center: center, angle: 0, scale: 1) - - truth = Mat(rows: 2, cols: 3, type: CvType.CV_64F) - try truth!.put(row: 0, col: 0, data: [1.0, 0.0, 0.0]) - try truth!.put(row: 1, col: 0, data: [0.0, 1.0, 0.0]) - - try assertMatEqual(truth!, dst, OpenCVTestCase.EPS) - } - func testGetStructuringElementIntSize() throws { dst = Imgproc.getStructuringElement(shape: .MORPH_RECT, ksize: size) @@ -1021,25 +926,6 @@ class ImgprocTest: OpenCVTestCase { try assertMatEqual(truth!, dst, OpenCVTestCase.EPS) } - func testInvertAffineTransform() throws { - let src = Mat(rows: 2, cols: 3, type: CvType.CV_64F, scalar: Scalar(1)) - - Imgproc.invertAffineTransform(M: src, iM: dst) - - truth = Mat(rows: 2, cols: 3, type: CvType.CV_64F, scalar: Scalar(0)) - try assertMatEqual(truth!, dst, OpenCVTestCase.EPS) - } - - func testIsContourConvex() { - let contour1 = [Point(x: 0, y: 0), Point(x: 10, y: 0), Point(x: 10, y: 10), Point(x: 5, y: 4)] - - XCTAssertFalse(Imgproc.isContourConvex(contour: contour1)) - - let contour2 = [Point(x: 0, y: 0), Point(x: 10, y: 0), Point(x: 10, y: 10), Point(x: 5, y: 6)] - - XCTAssert(Imgproc.isContourConvex(contour: contour2)) - } - func testLaplacianMatMatInt() throws { Imgproc.Laplacian(src: gray0, dst: dst, ddepth: CvType.CV_8U) @@ -1103,27 +989,6 @@ class ImgprocTest: OpenCVTestCase { // TODO_: write better test } - func testMinAreaRect() { - let points = [Point2f(x: 1, y: 1), Point2f(x: 5, y: 1), Point2f(x: 4, y: 3), Point2f(x: 6, y: 2)] - - let rrect = Imgproc.minAreaRect(points: points) - - XCTAssertEqual(Size2f(width: 5, height: 2), rrect.size) - XCTAssertEqual(0.0, rrect.angle) - XCTAssertEqual(Point2f(x: 3.5, y: 2), rrect.center) - } - - func testMinEnclosingCircle() { - let points = [Point2f(x: 0, y: 0), Point2f(x: -100, y: 0), Point2f(x: 0, y: -100), Point2f(x: 100, y: 0), Point2f(x: 0, y: 100)] - let actualCenter = Point2f() - var radius:Float = 0 - - Imgproc.minEnclosingCircle(points: points, center: actualCenter, radius: &radius) - - XCTAssertEqual(Point2f(x: 0, y: 0), actualCenter) - XCTAssertEqual(100.0, radius, accuracy: 1.0) - } - func testMorphologyExMatMatIntMat() throws { Imgproc.morphologyEx(src: gray255, dst: dst, op: MorphTypes.MORPH_GRADIENT, kernel: gray0) @@ -1159,15 +1024,6 @@ class ImgprocTest: OpenCVTestCase { try assertMatEqual(truth!, dst) } - func testPointPolygonTest() { - let contour = [Point2f(x: 0, y: 0), Point2f(x: 1, y: 3), Point2f(x: 3, y: 4), Point2f(x: 4, y: 3), Point2f(x: 2, y: 1)] - let sign1 = Imgproc.pointPolygonTest(contour: contour, pt: Point2f(x: 2, y: 2), measureDist: false) - XCTAssertEqual(1.0, sign1) - - let sign2 = Imgproc.pointPolygonTest(contour: contour, pt: Point2f(x: 4, y: 4), measureDist: true) - XCTAssertEqual(-sqrt(0.5), sign2) - } - func testPreCornerDetectMatMatInt() throws { let src = Mat(rows: 4, cols: 4, type: CvType.CV_32F, scalar: Scalar(1)) let ksize:Int32 = 3 diff --git a/modules/imgproc/misc/objc/test/MomentsTest.swift b/modules/imgproc/misc/objc/test/MomentsTest.swift deleted file mode 100644 index 01902f536f..0000000000 --- a/modules/imgproc/misc/objc/test/MomentsTest.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// MomentsTest.swift -// -// Created by Giles Payne on 2020/02/10. -// - -import XCTest -import OpenCV - -class MomentsTest: XCTestCase { - - func testAll() { - let data = Mat(rows: 3,cols: 3, type: CvType.CV_8UC1, scalar: Scalar(1)) - data.row(1).setTo(scalar: Scalar(5)) - let res = Imgproc.moments(array: data) - XCTAssertEqual(res.m00, 21.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m10, 21.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m01, 21.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m20, 35.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m11, 21.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m02, 27.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m30, 63.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m21, 35.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m12, 27.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.m03, 39.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.mu20, 14.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.mu11, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.mu02, 6.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.mu30, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.mu21, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.mu12, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.mu03, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.nu20, 0.031746031746031744, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.nu11, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.nu02, 0.013605442176870746, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.nu30, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.nu21, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.nu12, 0.0, accuracy: OpenCVTestCase.EPS); - XCTAssertEqual(res.nu03, 0.0, accuracy: OpenCVTestCase.EPS); - } - -} diff --git a/modules/imgproc/perf/perf_precomp.hpp b/modules/imgproc/perf/perf_precomp.hpp index b2c47c80e8..2044bf575d 100644 --- a/modules/imgproc/perf/perf_precomp.hpp +++ b/modules/imgproc/perf/perf_precomp.hpp @@ -6,6 +6,7 @@ #include "opencv2/ts.hpp" #include "opencv2/imgproc.hpp" +#include "opencv2/geometry.hpp" namespace opencv_test { using namespace perf; diff --git a/modules/imgproc/src/distortion_model.hpp b/modules/imgproc/src/distortion_model.hpp new file mode 100644 index 0000000000..c6fb7e58ed --- /dev/null +++ b/modules/imgproc/src/distortion_model.hpp @@ -0,0 +1,123 @@ +/*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_IMGPROC_DETAIL_DISTORTION_MODEL_HPP +#define OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP + +//! @cond IGNORED + +namespace cv { +/** +Computes the matrix for the projection onto a tilted image sensor +\param tauX angular parameter rotation around x-axis +\param tauY angular parameter rotation around y-axis +\param matTilt if not NULL returns the matrix +\f[ +\vecthreethree{R_{33}(\tau_x, \tau_y)}{0}{-R_{13}((\tau_x, \tau_y)} +{0}{R_{33}(\tau_x, \tau_y)}{-R_{23}(\tau_x, \tau_y)} +{0}{0}{1} R(\tau_x, \tau_y) +\f] +where +\f[ +R(\tau_x, \tau_y) = +\vecthreethree{\cos(\tau_y)}{0}{-\sin(\tau_y)}{0}{1}{0}{\sin(\tau_y)}{0}{\cos(\tau_y)} +\vecthreethree{1}{0}{0}{0}{\cos(\tau_x)}{\sin(\tau_x)}{0}{-\sin(\tau_x)}{\cos(\tau_x)} = +\vecthreethree{\cos(\tau_y)}{\sin(\tau_y)\sin(\tau_x)}{-\sin(\tau_y)\cos(\tau_x)} +{0}{\cos(\tau_x)}{\sin(\tau_x)} +{\sin(\tau_y)}{-\cos(\tau_y)\sin(\tau_x)}{\cos(\tau_y)\cos(\tau_x)}. +\f] +\param dMatTiltdTauX if not NULL it returns the derivative of matTilt with +respect to \f$\tau_x\f$. +\param dMatTiltdTauY if not NULL it returns the derivative of matTilt with +respect to \f$\tau_y\f$. +\param invMatTilt if not NULL it returns the inverse of matTilt +**/ +template +void computeTiltProjectionMatrix(FLOAT tauX, + FLOAT tauY, + Matx* matTilt = 0, + Matx* dMatTiltdTauX = 0, + Matx* dMatTiltdTauY = 0, + Matx* invMatTilt = 0) +{ + FLOAT cTauX = std::cos(tauX); + FLOAT sTauX = std::sin(tauX); + FLOAT cTauY = std::cos(tauY); + FLOAT sTauY = std::sin(tauY); + Matx matRotX = Matx(1,0,0,0,cTauX,sTauX,0,-sTauX,cTauX); + Matx matRotY = Matx(cTauY,0,-sTauY,0,1,0,sTauY,0,cTauY); + Matx matRotXY = matRotY * matRotX; + Matx matProjZ = Matx(matRotXY(2,2),0,-matRotXY(0,2),0,matRotXY(2,2),-matRotXY(1,2),0,0,1); + if (matTilt) + { + // Matrix for trapezoidal distortion of tilted image sensor + *matTilt = matProjZ * matRotXY; + } + if (dMatTiltdTauX) + { + // Derivative with respect to tauX + Matx dMatRotXYdTauX = matRotY * Matx(0,0,0,0,-sTauX,cTauX,0,-cTauX,-sTauX); + Matx dMatProjZdTauX = Matx(dMatRotXYdTauX(2,2),0,-dMatRotXYdTauX(0,2), + 0,dMatRotXYdTauX(2,2),-dMatRotXYdTauX(1,2),0,0,0); + *dMatTiltdTauX = (matProjZ * dMatRotXYdTauX) + (dMatProjZdTauX * matRotXY); + } + if (dMatTiltdTauY) + { + // Derivative with respect to tauY + Matx dMatRotXYdTauY = Matx(-sTauY,0,-cTauY,0,0,0,cTauY,0,-sTauY) * matRotX; + Matx dMatProjZdTauY = Matx(dMatRotXYdTauY(2,2),0,-dMatRotXYdTauY(0,2), + 0,dMatRotXYdTauY(2,2),-dMatRotXYdTauY(1,2),0,0,0); + *dMatTiltdTauY = (matProjZ * dMatRotXYdTauY) + (dMatProjZdTauY * matRotXY); + } + if (invMatTilt) + { + FLOAT inv = 1./matRotXY(2,2); + Matx invMatProjZ = Matx(inv,0,inv*matRotXY(0,2),0,inv,inv*matRotXY(1,2),0,0,1); + *invMatTilt = matRotXY.t()*invMatProjZ; + } +} +} // namespace detail, _3d, cv + + +//! @endcond + +#endif // OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP diff --git a/modules/imgproc/src/drawing.cpp b/modules/imgproc/src/drawing.cpp index e18fa2a420..a79bffd96f 100644 --- a/modules/imgproc/src/drawing.cpp +++ b/modules/imgproc/src/drawing.cpp @@ -2250,3 +2250,44 @@ void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours, } } } + +void cv::drawFrameAxes(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs, + InputArray rvec, InputArray tvec, float length, int thickness) +{ + CV_INSTRUMENT_REGION(); + + int type = image.type(); + int cn = CV_MAT_CN(type); + CV_CheckType(type, cn == 1 || cn == 3 || cn == 4, + "Number of channels must be 1, 3 or 4" ); + + cv::Mat img = image.getMat(); + CV_Assert(img.total() > 0); + CV_Assert(length > 0); + + // project axes points + std::vector axesPoints; + axesPoints.push_back(Point3f(0, 0, 0)); + axesPoints.push_back(Point3f(length, 0, 0)); + axesPoints.push_back(Point3f(0, length, 0)); + axesPoints.push_back(Point3f(0, 0, length)); + std::vector imagePoints; + projectPoints(axesPoints, rvec, tvec, cameraMatrix, distCoeffs, imagePoints); + + cv::Rect imageRect(0, 0, img.cols, img.rows); + bool allIn = true; + for (size_t i = 0; i < imagePoints.size(); i++) + { + allIn &= imageRect.contains(imagePoints[i]); + } + + if (!allIn) + { + CV_LOG_WARNING(NULL, "Some of projected axes endpoints are out of frame. The drawn axes may be not reliable."); + } + + // draw axes lines + line(image, imagePoints[0], imagePoints[1], Scalar(0, 0, 255), thickness); + line(image, imagePoints[0], imagePoints[2], Scalar(0, 255, 0), thickness); + line(image, imagePoints[0], imagePoints[3], Scalar(255, 0, 0), thickness); +} diff --git a/modules/imgproc/src/fisheye.cpp b/modules/imgproc/src/fisheye.cpp new file mode 100644 index 0000000000..c43defce47 --- /dev/null +++ b/modules/imgproc/src/fisheye.cpp @@ -0,0 +1,128 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html + +#include "precomp.hpp" +#include "opencv2/core/affine.hpp" + +namespace cv { +namespace fisheye { + +void initUndistortRectifyMap( InputArray K, InputArray D, InputArray R, InputArray P, + const cv::Size& size, int m1type, OutputArray map1, OutputArray map2 ) +{ + CV_INSTRUMENT_REGION(); + + 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.empty() || P.depth() == CV_32F || P.depth() == CV_64F) && (R.empty() || 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)); + + 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(): *D.getMat().ptr(); + + Matx33d RR = Matx33d::eye(); + if (!R.empty() && R.total() * R.channels() == 3) + { + 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); + + Matx33d PP = Matx33d::eye(); + if (!P.empty()) + P.getMat().colRange(0, 3).convertTo(PP, CV_64F); + + Matx33d iR = (PP * RR).inv(cv::DECOMP_SVD); + + for( int i = 0; i < size.height; ++i) + { + float* m1f = map1.getMat().ptr(i); + float* m2f = map2.getMat().ptr(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 u, v; + if( _w <= 0) + { + u = (_x > 0) ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); + v = (_y > 0) ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); + } + else + { + double x = _x/_w, y = _y/_w; + + double r = sqrt(x*x + y*y); + double theta = std::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; + u = f[0]*x*scale + c[0]; + v = f[1]*y*scale + c[1]; + } + + if( m1type == CV_16SC2 ) + { + int iu = cv::saturate_cast(u*static_cast(cv::INTER_TAB_SIZE)); + int iv = cv::saturate_cast(v*static_cast(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); + } + } +} + +void undistortImage(InputArray distorted, OutputArray undistorted, + InputArray K, InputArray D, InputArray Knew, const Size& new_size) +{ + CV_INSTRUMENT_REGION(); + + Size size = !new_size.empty() ? new_size : distorted.size(); + + Mat map1, map2; + fisheye::initUndistortRectifyMap(K, D, Matx33d::eye(), Knew, size, CV_16SC2, map1, map2 ); + cv::remap(distorted, undistorted, map1, map2, INTER_LINEAR, BORDER_CONSTANT); +} + +} // namespace fisheye +} // namespace cv diff --git a/modules/imgproc/src/grabcut.cpp b/modules/imgproc/src/grabcut.cpp index 115f346e99..da7e9cdee4 100644 --- a/modules/imgproc/src/grabcut.cpp +++ b/modules/imgproc/src/grabcut.cpp @@ -40,7 +40,7 @@ //M*/ #include "precomp.hpp" -#include "opencv2/imgproc/detail/gcgraph.hpp" +#include "opencv2/geometry/detail/gcgraph.hpp" #include using namespace cv; diff --git a/modules/imgproc/src/hal_replacement.hpp b/modules/imgproc/src/hal_replacement.hpp index 4d3fe4477d..ef6bbdbb7d 100644 --- a/modules/imgproc/src/hal_replacement.hpp +++ b/modules/imgproc/src/hal_replacement.hpp @@ -1520,38 +1520,6 @@ inline int hal_ni_canny(const uchar* src_data, size_t src_step, uchar* dst_data, #define cv_hal_canny hal_ni_canny //! @endcond -/** - @brief Calculates all of the moments up to the third order of a polygon or rasterized shape for image - @param src_data Source image data - @param src_step Source image step - @param src_type source pints type - @param width Source image width - @param height Source image height - @param binary If it is true, all non-zero image pixels are treated as 1's - @param m Output array of moments (10 values) in the following order: - m00, m10, m01, m20, m11, m02, m30, m21, m12, m03. - @sa moments -*/ -inline int hal_ni_imageMoments(const uchar* src_data, size_t src_step, int src_type, int width, int height, bool binary, double m[10]) -{ return CV_HAL_ERROR_NOT_IMPLEMENTED; } - -/** - @brief Calculates all of the moments up to the third order of a polygon of 2d points - @param src_data Source points (Point 2x32f or 2x32s) - @param src_size Source points count - @param src_type source pints type - @param m Output array of moments (10 values) in the following order: - m00, m10, m01, m20, m11, m02, m30, m21, m12, m03. - @sa moments -*/ -inline int hal_ni_polygonMoments(const uchar* src_data, size_t src_size, int src_type, double m[10]) -{ return CV_HAL_ERROR_NOT_IMPLEMENTED; } - -//! @cond IGNORED -#define cv_hal_imageMoments hal_ni_imageMoments -#define cv_hal_polygonMoments hal_ni_polygonMoments -//! @endcond - /** @brief Calculates a histogram of a set of arrays @param src_data Source imgage data diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index b98ee04223..9a76877e90 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -3059,204 +3059,6 @@ void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0, matM.ptr(), interpolation, borderType, borderValue.val, hint); } - -cv::Matx23d cv::getRotationMatrix2D_(Point2f center, double angle, double scale) -{ - CV_INSTRUMENT_REGION(); - - angle *= CV_PI/180; - double alpha = std::cos(angle)*scale; - double beta = std::sin(angle)*scale; - - Matx23d M( - alpha, beta, (1-alpha)*center.x - beta*center.y, - -beta, alpha, beta*center.x + (1-alpha)*center.y - ); - return M; -} - -/* Calculates coefficients of perspective transformation - * which maps (xi,yi) to (ui,vi), (i=1,2,3,4): - * - * c00*xi + c01*yi + c02 - * ui = --------------------- - * c20*xi + c21*yi + c22 - * - * c10*xi + c11*yi + c12 - * vi = --------------------- - * c20*xi + c21*yi + c22 - * - * Coefficients are calculated by solving one of 2 linear systems: - * / x0 y0 1 0 0 0 -x0*u0 -y0*u0 \ /c00\ /u0\ - * | x1 y1 1 0 0 0 -x1*u1 -y1*u1 | |c01| |u1| - * | x2 y2 1 0 0 0 -x2*u2 -y2*u2 | |c02| |u2| - * | x3 y3 1 0 0 0 -x3*u3 -y3*u3 |.|c10|=|u3|, - * | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 | |c11| |v0| - * | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 | |c12| |v1| - * | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 | |c20| |v2| - * \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 / \c21/ \v3/ - * - * where: - * cij - matrix coefficients, c22 = 1 - * - * or - * - * / x0 y0 1 0 0 0 -x0*u0 -y0*u0 -u0 \ /c00\ /0\ - * | x1 y1 1 0 0 0 -x1*u1 -y1*u1 -u1 | |c01| |0| - * | x2 y2 1 0 0 0 -x2*u2 -y2*u2 -u2 | |c02| |0| - * | x3 y3 1 0 0 0 -x3*u3 -y3*u3 -u3 |.|c10|=|0|, - * | 0 0 0 x0 y0 1 -x0*v0 -y0*v0 -v0 | |c11| |0| - * | 0 0 0 x1 y1 1 -x1*v1 -y1*v1 -v1 | |c12| |0| - * | 0 0 0 x2 y2 1 -x2*v2 -y2*v2 -v2 | |c20| |0| - * \ 0 0 0 x3 y3 1 -x3*v3 -y3*v3 -v3 / |c21| \0/ - * \c22/ - * - * where: - * cij - matrix coefficients, c00^2 + c01^2 + c02^2 + c10^2 + c11^2 + c12^2 + c20^2 + c21^2 + c22^2 = 1 - */ -cv::Mat cv::getPerspectiveTransform(const Point2f src[], const Point2f dst[], int solveMethod) -{ - CV_INSTRUMENT_REGION(); - - // try c22 = 1 - Mat M(3, 3, CV_64F), X8(8, 1, CV_64F, M.ptr()); - double a[8][8], b[8]; - Mat A(8, 8, CV_64F, a), B(8, 1, CV_64F, b); - - for( int i = 0; i < 4; ++i ) - { - a[i][0] = a[i+4][3] = src[i].x; - a[i][1] = a[i+4][4] = src[i].y; - a[i][2] = a[i+4][5] = 1; - a[i][3] = a[i][4] = a[i][5] = - a[i+4][0] = a[i+4][1] = a[i+4][2] = 0; - a[i][6] = -src[i].x*dst[i].x; - a[i][7] = -src[i].y*dst[i].x; - a[i+4][6] = -src[i].x*dst[i].y; - a[i+4][7] = -src[i].y*dst[i].y; - b[i] = dst[i].x; - b[i+4] = dst[i].y; - } - - if (solve(A, B, X8, solveMethod) && norm(A * X8, B) < 1e-8) - { - M.ptr()[8] = 1.; - - return M; - } - - // c00^2 + c01^2 + c02^2 + c10^2 + c11^2 + c12^2 + c20^2 + c21^2 + c22^2 = 1 - hconcat(A, -B, A); - - Mat AtA; - mulTransposed(A, AtA, true); - - Mat D, U; - SVDecomp(AtA, D, U, noArray()); - - Mat X9(9, 1, CV_64F, M.ptr()); - U.col(8).copyTo(X9); - - return M; -} - -/* Calculates coefficients of affine transformation - * which maps (xi,yi) to (ui,vi), (i=1,2,3): - * - * ui = c00*xi + c01*yi + c02 - * - * vi = c10*xi + c11*yi + c12 - * - * Coefficients are calculated by solving linear system: - * / x0 y0 1 0 0 0 \ /c00\ /u0\ - * | x1 y1 1 0 0 0 | |c01| |u1| - * | x2 y2 1 0 0 0 | |c02| |u2| - * | 0 0 0 x0 y0 1 | |c10| |v0| - * | 0 0 0 x1 y1 1 | |c11| |v1| - * \ 0 0 0 x2 y2 1 / |c12| |v2| - * - * where: - * cij - matrix coefficients - */ - -cv::Mat cv::getAffineTransform( const Point2f src[], const Point2f dst[] ) -{ - Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.ptr()); - double a[6*6], b[6]; - Mat A(6, 6, CV_64F, a), B(6, 1, CV_64F, b); - - for( int i = 0; i < 3; i++ ) - { - int j = i*12; - int k = i*12+6; - a[j] = a[k+3] = src[i].x; - a[j+1] = a[k+4] = src[i].y; - a[j+2] = a[k+5] = 1; - a[j+3] = a[j+4] = a[j+5] = 0; - a[k] = a[k+1] = a[k+2] = 0; - b[i*2] = dst[i].x; - b[i*2+1] = dst[i].y; - } - - solve( A, B, X ); - return M; -} - -void cv::invertAffineTransform(InputArray _matM, OutputArray __iM) -{ - Mat matM = _matM.getMat(); - CV_Assert(matM.rows == 2 && matM.cols == 3); - __iM.create(2, 3, matM.type()); - Mat _iM = __iM.getMat(); - - if( matM.type() == CV_32F ) - { - const softfloat* M = matM.ptr(); - softfloat* iM = _iM.ptr(); - int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0])); - - softdouble D = M[0]*M[step+1] - M[1]*M[step]; - D = D != 0. ? softdouble(1.)/D : softdouble(0.); - softdouble A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; - softdouble b1 = -A11*M[2] - A12*M[step+2]; - softdouble b2 = -A21*M[2] - A22*M[step+2]; - - iM[0] = A11; iM[1] = A12; iM[2] = b1; - iM[istep] = A21; iM[istep+1] = A22; iM[istep+2] = b2; - } - else if( matM.type() == CV_64F ) - { - const softdouble* M = matM.ptr(); - softdouble* iM = _iM.ptr(); - int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0])); - - softdouble D = M[0]*M[step+1] - M[1]*M[step]; - D = D != 0. ? softdouble(1.)/D : softdouble(0.); - softdouble A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; - softdouble b1 = -A11*M[2] - A12*M[step+2]; - softdouble b2 = -A21*M[2] - A22*M[step+2]; - - iM[0] = A11; iM[1] = A12; iM[2] = b1; - iM[istep] = A21; iM[istep+1] = A22; iM[istep+2] = b2; - } - else - CV_Error( cv::Error::StsUnsupportedFormat, "" ); -} - -cv::Mat cv::getPerspectiveTransform(InputArray _src, InputArray _dst, int solveMethod) -{ - Mat src = _src.getMat(), dst = _dst.getMat(); - CV_Assert(src.checkVector(2, CV_32F) == 4 && dst.checkVector(2, CV_32F) == 4); - return getPerspectiveTransform((const Point2f*)src.data, (const Point2f*)dst.data, solveMethod); -} - -cv::Mat cv::getAffineTransform(InputArray _src, InputArray _dst) -{ - Mat src = _src.getMat(), dst = _dst.getMat(); - CV_Assert(src.checkVector(2, CV_32F) == 3 && dst.checkVector(2, CV_32F) == 3); - return getAffineTransform((const Point2f*)src.data, (const Point2f*)dst.data); -} - /**************************************************************************************** PkLab.net 2018 based on cv::linearPolar from OpenCV by J.L. Blanco, Apr 2009 ****************************************************************************************/ diff --git a/modules/geometry/src/lsd.cpp b/modules/imgproc/src/lsd.cpp similarity index 100% rename from modules/geometry/src/lsd.cpp rename to modules/imgproc/src/lsd.cpp diff --git a/modules/imgproc/src/precomp.hpp b/modules/imgproc/src/precomp.hpp index 18aa57905f..bc202ed922 100644 --- a/modules/imgproc/src/precomp.hpp +++ b/modules/imgproc/src/precomp.hpp @@ -44,6 +44,7 @@ #define __OPENCV_PRECOMP_H__ #include "opencv2/imgproc.hpp" +#include "opencv2/geometry.hpp" #include "opencv2/core/utility.hpp" #include "opencv2/core/private.hpp" diff --git a/modules/geometry/src/undistort.dispatch.cpp b/modules/imgproc/src/undistort.dispatch.cpp similarity index 60% rename from modules/geometry/src/undistort.dispatch.cpp rename to modules/imgproc/src/undistort.dispatch.cpp index fc6ee6a271..0fa48cc9a2 100644 --- a/modules/geometry/src/undistort.dispatch.cpp +++ b/modules/imgproc/src/undistort.dispatch.cpp @@ -49,63 +49,6 @@ namespace cv { -Mat getDefaultNewCameraMatrix( InputArray _cameraMatrix, Size imgsize, - bool centerPrincipalPoint ) -{ - Mat cameraMatrix = _cameraMatrix.getMat(); - if( !centerPrincipalPoint && cameraMatrix.type() == CV_64F ) - return cameraMatrix; - - Mat newCameraMatrix; - cameraMatrix.convertTo(newCameraMatrix, CV_64F); - if( centerPrincipalPoint ) - { - newCameraMatrix.ptr()[2] = (imgsize.width-1)*0.5; - newCameraMatrix.ptr()[5] = (imgsize.height-1)*0.5; - } - return newCameraMatrix; -} - -void calibrationMatrixValues( InputArray _cameraMatrix, Size imageSize, - double apertureWidth, double apertureHeight, - double& fovx, double& fovy, double& focalLength, - Point2d& principalPoint, double& aspectRatio ) -{ - CV_INSTRUMENT_REGION(); - - if(_cameraMatrix.size() != Size(3, 3)) - CV_Error(cv::Error::StsUnmatchedSizes, "Size of cameraMatrix must be 3x3!"); - - Matx33d A; - _cameraMatrix.getMat().convertTo(A, CV_64F); - CV_DbgAssert(imageSize.width != 0 && imageSize.height != 0 && A(0, 0) != 0.0 && A(1, 1) != 0.0); - - /* Calculate pixel aspect ratio. */ - aspectRatio = A(1, 1) / A(0, 0); - - /* Calculate number of pixel per realworld unit. */ - double mx, my; - if(apertureWidth != 0.0 && apertureHeight != 0.0) { - mx = imageSize.width / apertureWidth; - my = imageSize.height / apertureHeight; - } else { - mx = 1.0; - my = aspectRatio; - } - - /* Calculate fovx and fovy. */ - fovx = atan2(A(0, 2), A(0, 0)) + atan2(imageSize.width - A(0, 2), A(0, 0)); - fovy = atan2(A(1, 2), A(1, 1)) + atan2(imageSize.height - A(1, 2), A(1, 1)); - fovx *= 180.0 / CV_PI; - fovy *= 180.0 / CV_PI; - - /* Calculate focal length. */ - focalLength = A(0, 0) / mx; - - /* Calculate principle point. */ - principalPoint = Point2d(A(0, 2) / mx, A(1, 2) / my); -} - static Ptr getInitUndistortRectifyMapComputer(Size _size, Mat &_map1, Mat &_map2, int _m1type, const double* _ir, Matx33d &_matTilt, double _u0, double _v0, double _fx, double _fy, @@ -358,8 +301,8 @@ void undistort( InputArray _src, OutputArray _dst, InputArray _cameraMatrix, int stripe_size = std::min( stripe_size0, src.rows - y ); Ar(1, 2) = v0 - y; Mat map1_part = map1.rowRange(0, stripe_size), - map2_part = map2.rowRange(0, stripe_size), - dst_part = dst.rowRange(y, y + stripe_size); + map2_part = map2.rowRange(0, stripe_size), + dst_part = dst.rowRange(y, y + stripe_size); initUndistortRectifyMap( A, distCoeffs, I, Ar, Size(src.cols, stripe_size), map1_part.type(), map1_part, map2_part ); @@ -367,251 +310,6 @@ void undistort( InputArray _src, OutputArray _dst, InputArray _cameraMatrix, } } -static void undistortPointsInternal( const Mat& _src, Mat& _dst, const Mat& _cameraMatrix, - const Mat& _distCoeffs, const Mat& matR, const Mat& matP, TermCriteria criteria) -{ - CV_Assert(criteria.isValid()); - double A[3][3], RR[3][3], k[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - Mat matA(3, 3, CV_64F, A), _Dk; - Mat _RR(3, 3, CV_64F, RR); - cv::Matx33d invMatTilt = cv::Matx33d::eye(); - cv::Matx33d matTilt = cv::Matx33d::eye(); - bool haveDistCoeffs = !_distCoeffs.empty(); - - CV_Assert( (_src.rows == 1 || _src.cols == 1) && - (_dst.rows == 1 || _dst.cols == 1) && - _src.cols + _src.rows - 1 == _dst.rows + _dst.cols - 1 && - (_src.type() == CV_32FC2 || _src.type() == CV_64FC2) && - (_dst.type() == CV_32FC2 || _dst.type() == CV_64FC2)); - - CV_Assert( _cameraMatrix.rows == 3 && _cameraMatrix.cols == 3 && _cameraMatrix.channels() == 1 ); - _cameraMatrix.convertTo(matA, CV_64F); - - if( haveDistCoeffs ) - { - CV_Assert( - (_distCoeffs.rows == 1 || _distCoeffs.cols == 1) && - (_distCoeffs.rows*_distCoeffs.cols == 4 || - _distCoeffs.rows*_distCoeffs.cols == 5 || - _distCoeffs.rows*_distCoeffs.cols == 8 || - _distCoeffs.rows*_distCoeffs.cols == 12 || - _distCoeffs.rows*_distCoeffs.cols == 14)); - - _Dk = Mat( _distCoeffs.rows, _distCoeffs.cols, - CV_MAKETYPE(CV_64F,_distCoeffs.channels()), k); - _distCoeffs.convertTo(_Dk, CV_64F); - CV_Assert(_Dk.ptr() == k); - if (k[12] != 0 || k[13] != 0) - { - computeTiltProjectionMatrix(k[12], k[13], NULL, NULL, NULL, &invMatTilt); - computeTiltProjectionMatrix(k[12], k[13], &matTilt, NULL, NULL); - } - } - - if( !matR.empty() ) - { - CV_Assert( matR.rows == 3 && matR.cols == 3 && matR.channels() == 1 ); - matR.convertTo(_RR, CV_64F); - CV_Assert(_RR.ptr() == &RR[0][0]); - } - else - setIdentity(_RR); - - if( !matP.empty() ) - { - double PP[3][3]; - Mat _PP(3, 3, CV_64F, PP); - CV_Assert( matP.rows == 3 && (matP.cols == 3 || matP.cols == 4)); - matP.colRange(0, 3).convertTo(_PP, CV_64F); - CV_Assert(_PP.ptr() == &PP[0][0]); - _RR = _PP*_RR; - } - - const Point2f* srcf = (const Point2f*)_src.data; - const Point2d* srcd = (const Point2d*)_src.data; - Point2f* dstf = (Point2f*)_dst.data; - Point2d* dstd = (Point2d*)_dst.data; - int stype = _src.type(); - int dtype = _dst.type(); - int sstep = _src.rows == 1 ? 1 : (int)(_src.step/_src.elemSize()); - int dstep = _dst.rows == 1 ? 1 : (int)(_dst.step/_dst.elemSize()); - - double fx = A[0][0]; - double fy = A[1][1]; - double ifx = 1./fx; - double ify = 1./fy; - double cx = A[0][2]; - double cy = A[1][2]; - - int n = _src.rows + _src.cols - 1; - for( int i = 0; i < n; i++ ) - { - double x, y, x0 = 0, y0 = 0, u, v; - if( stype == CV_32FC2 ) - { - x = srcf[i*sstep].x; - y = srcf[i*sstep].y; - } - else - { - x = srcd[i*sstep].x; - y = srcd[i*sstep].y; - } - // [u, v]^T = [fx * x''' + cx, fy * y''' + cy]^T => - // [x''', y''']^T = [(u - cx) / fx, (v - cy) / fy]^T - u = x; v = y; - x = (x - cx)*ifx; - y = (y - cy)*ify; - - if( haveDistCoeffs ) { - // compensate tilt distortion - // s * [x''', y''', 1]^T = matTilt * [x'', y'', 1]^T => - // s * matTilt^{-1} * [x''', y''', 1]^T = [x'', y'', 1]^T => - // (invMatTilt := matTilt^{-1}, vecUntilt := invMatTilt * [x''', y''', 1]^T) - // s * vecUntilt = [x'', y'', 1]^T => - // s * vecUntilt_1 = x'', s * vecUntilt_2 = y'', s * vecUntilt_3 = 1 => - // invProj := s = 1 / vecUntilt_3, x'' = invProj * vecUntilt_1, y'' = invProj * vecUntilt_2 - cv::Vec3d vecUntilt = invMatTilt * cv::Vec3d(x, y, 1); - double invProj = vecUntilt(2) ? 1./vecUntilt(2) : 1; - x0 = x = invProj * vecUntilt(0); - y0 = y = invProj * vecUntilt(1); - - double error = std::numeric_limits::max(); - double prevError = std::numeric_limits::max(); - // compensate distortion iteratively using fixed-point iteration - - // parameter for damped fixed-point iteration - double alpha = 1.; - - for( int j = 0; ; j++ ) - { - if ((criteria.type & TermCriteria::COUNT) && j >= criteria.maxCount) - break; - if ((criteria.type & TermCriteria::EPS) && error < criteria.epsilon) - break; - // r^2 = x'^2 + y'^2 - double r2 = x*x + y*y; - // icdist := (1 + k4 * r^2 + k5 * r^4 + k6 * r^6) / (1 + k1 * r^2 + k2 * r^4 + k3 * r^6) - double icdist = (1 + ((k[7]*r2 + k[6])*r2 + k[5])*r2)/(1 + ((k[4]*r2 + k[1])*r2 + k[0])*r2); - if (icdist < 0) // test: undistortPoints.regression_14583 - { - x = (u - cx)*ifx; - y = (v - cy)*ify; - break; - } - // deltaX := 2 * p1 * x' * y' + p2 * (r^2 + 2 * x'^2) + s1 * r^2 + s2 * r^4 - // deltaY := p1 * (r^2 + 2 * y'^2) + 2 * p2 * x' * y' + s3 * r^2 + s4 * r^4 - double deltaX = 2*k[2]*x*y + k[3]*(r2 + 2*x*x)+ k[8]*r2+k[9]*r2*r2; - double deltaY = k[2]*(r2 + 2*y*y) + 2*k[3]*x*y+ k[10]*r2+k[11]*r2*r2; - // [x'', y'']^T = [x' / icdist + deltaX, y' / icdist + deltaY]^T => - // [x', y']^T = [(x'' - deltaX) * icdist, (y'' - deltaY) * icdist]^T => - // x' = f1(x') := (x'' - deltaX) * icdist, y' = f2(y') := (y'' - deltaY) * icdist - // Damped fixed-point iteration: - // f1(x') = (x'' - deltaX) * icdist, f2(y') = (y'' - deltaY) * icdist - // new_x' = (1 - alpha) * x' + alpha * f1(x'), new_y' = (1 - alpha) * y' + alpha * f2(y') - double new_x = (1. - alpha)*x + alpha*(x0 - deltaX)*icdist; - double new_y = (1. - alpha)*y + alpha*(y0 - deltaY)*icdist; - - if(criteria.type & TermCriteria::EPS) - { - double r4, r6, a1, a2, a3, cdist, icdist2; - double xd, yd, xd0, yd0; - Vec3d vecTilt; - - // r^2 = x'^2 + y'^2 - r2 = new_x*new_x + new_y*new_y; - r4 = r2*r2; - r6 = r4*r2; - a1 = 2*new_x*new_y; - a2 = r2 + 2*new_x*new_x; - a3 = r2 + 2*new_y*new_y; - // cdist := 1 + k1 * r^2 + k2 * r^4 + k3 * r^6 - cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6; - // icdist2 := 1 / (1 + k4 * r^2 + k5 * r^4 + k6 * r^6) - icdist2 = 1./(1 + k[5]*r2 + k[6]*r4 + k[7]*r6); - // x'' = x' * cdist * icdist2 + 2 * p1 * x' * y' + p2 * (r^2 + 2 * x'^2) + s1 * r^2 + s2 * r^4 - // y'' = y' * cdist * icdist2 + p1 * (r^2 + 2 * y'^2) + 2 * p2 * x' * y' + s3 * r^2 + s4 * r^4 - xd0 = new_x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4; - yd0 = new_y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4; - - // s * [x''', y''', 1]^T = matTilt * [x'', y'', 1]^T => - // (vecTilt := matTilt * [x'', y'', 1]^T) - // s * [x''', y''', 1]^T = vecTilt => - // s * x''' = vecTilt_1, s * y''' = vecTilt_2, s = vecTilt_3 => - // invProj := 1 / s = 1 / vecTilt_3, x''' = invProj * vecTilt_1, y''' = invProj * vecTilt_2 - vecTilt = matTilt*cv::Vec3d(xd0, yd0, 1); - invProj = vecTilt(2) ? 1./vecTilt(2) : 1; - xd = invProj * vecTilt(0); - yd = invProj * vecTilt(1); - - // [u, v]^T = [fx * x''' + cx, fy * y''' + cy]^T - double x_proj = xd*fx + cx; - double y_proj = yd*fy + cy; - - error = sqrt( std::pow(x_proj - u, 2) + std::pow(y_proj - v, 2) ); - } - if (error > prevError) { - alpha *= .5; - } else { - x = new_x; - y = new_y; - } - prevError = error; - } - } - - if( !matR.empty() || !matP.empty() ) - { - double xx = RR[0][0]*x + RR[0][1]*y + RR[0][2]; - double yy = RR[1][0]*x + RR[1][1]*y + RR[1][2]; - double ww = 1./(RR[2][0]*x + RR[2][1]*y + RR[2][2]); - x = xx*ww; - y = yy*ww; - } - - if( dtype == CV_32FC2 ) - { - dstf[i*dstep].x = (float)x; - dstf[i*dstep].y = (float)y; - } - else - { - dstd[i*dstep].x = x; - dstd[i*dstep].y = y; - } - } -} - -void undistortPoints(InputArray _src, OutputArray _dst, - InputArray _cameraMatrix, - InputArray _distCoeffs, - InputArray _Rmat, - InputArray _Pmat, - TermCriteria criteria) -{ - Mat src = _src.getMat(), cameraMatrix = _cameraMatrix.getMat(); - Mat distCoeffs = _distCoeffs.getMat(), R = _Rmat.getMat(), P = _Pmat.getMat(); - - int npoints = src.checkVector(2), depth = src.depth(); - if (npoints < 0) - src = src.t(); - npoints = src.checkVector(2); - CV_Assert(npoints >= 0 && src.isContinuous() && (depth == CV_32F || depth == CV_64F)); - - if (src.cols == 2) - src = src.reshape(2); - - _dst.create(npoints, 1, CV_MAKETYPE(depth, 2), -1, true); - Mat dst = _dst.getMat(); - - undistortPointsInternal(src, dst, cameraMatrix, distCoeffs, R, P, criteria); -} - -void undistortImagePoints(InputArray src, OutputArray dst, InputArray cameraMatrix, InputArray distCoeffs, TermCriteria termCriteria) -{ - undistortPoints(src, dst, cameraMatrix, distCoeffs, noArray(), cameraMatrix, termCriteria); -} - static Point2f mapPointSpherical(const Point2f& p, float alpha, Vec4d* J, enum UndistortTypes projType) { double x = p.x, y = p.y; diff --git a/modules/geometry/src/undistort.simd.hpp b/modules/imgproc/src/undistort.simd.hpp similarity index 100% rename from modules/geometry/src/undistort.simd.hpp rename to modules/imgproc/src/undistort.simd.hpp diff --git a/modules/imgproc/test/test_contours.cpp b/modules/imgproc/test/test_contours.cpp index 8b104e2815..1cf8e327c7 100644 --- a/modules/imgproc/test/test_contours.cpp +++ b/modules/imgproc/test/test_contours.cpp @@ -219,20 +219,5 @@ TEST(Imgproc_DrawContours, MatListOfMatIntScalarInt) EXPECT_EQ(nz, 0); } -TEST(Imgproc_Moments, degenerateContours) -{ - std::vector c1; - c1.push_back(cv::Point(10,10)); - cv::Moments m1 = cv::moments(c1, false); - EXPECT_EQ(m1.m00, 0); - - std::vector c2; - c2.push_back(cv::Point(0,0)); - c2.push_back(cv::Point(5,5)); - c2.push_back(cv::Point(10,10)); - cv::Moments m2 = cv::moments(c2, false); - EXPECT_EQ(m2.m00, 0); -} - }} // namespace /* End of file. */ diff --git a/modules/imgproc/test/test_drawing.cpp b/modules/imgproc/test/test_drawing.cpp old mode 100755 new mode 100644 diff --git a/modules/geometry/test/test_lsd.cpp b/modules/imgproc/test/test_lsd.cpp similarity index 100% rename from modules/geometry/test/test_lsd.cpp rename to modules/imgproc/test/test_lsd.cpp diff --git a/modules/imgproc/test/test_precomp.hpp b/modules/imgproc/test/test_precomp.hpp index dcb787b9eb..5e26a3f8ed 100644 --- a/modules/imgproc/test/test_precomp.hpp +++ b/modules/imgproc/test/test_precomp.hpp @@ -7,8 +7,9 @@ #include "opencv2/ts.hpp" #include "opencv2/ts/ts_gtest.h" #include "opencv2/ts/ocl_test.hpp" -#include "opencv2/imgproc.hpp" #include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/geometry.hpp" #include "opencv2/core/private.hpp" diff --git a/modules/stitching/src/seam_finders.cpp b/modules/stitching/src/seam_finders.cpp index 3b29094ba8..0db6360d17 100644 --- a/modules/stitching/src/seam_finders.cpp +++ b/modules/stitching/src/seam_finders.cpp @@ -41,7 +41,7 @@ //M*/ #include "precomp.hpp" -#include "opencv2/imgproc/detail/gcgraph.hpp" +#include "opencv2/geometry/detail/gcgraph.hpp" #include namespace cv { diff --git a/modules/video/src/precomp.hpp b/modules/video/src/precomp.hpp index aac0c5734f..27cd0adcaa 100644 --- a/modules/video/src/precomp.hpp +++ b/modules/video/src/precomp.hpp @@ -48,5 +48,6 @@ #include "opencv2/core/private.hpp" #include "opencv2/core/ocl.hpp" #include "opencv2/core.hpp" +#include "opencv2/geometry.hpp" #endif diff --git a/modules/video/test/test_precomp.hpp b/modules/video/test/test_precomp.hpp index a6810ccc1f..97ad864a0e 100644 --- a/modules/video/test/test_precomp.hpp +++ b/modules/video/test/test_precomp.hpp @@ -6,6 +6,7 @@ #include "opencv2/ts.hpp" #include "opencv2/video.hpp" +#include "opencv2/geometry.hpp" #include #include "opencv2/core/utils/configuration.private.hpp" diff --git a/samples/cpp/snippets/distrans.cpp b/samples/cpp/snippets/distrans.cpp index 9304ec6d9d..1627b6c2a7 100644 --- a/samples/cpp/snippets/distrans.cpp +++ b/samples/cpp/snippets/distrans.cpp @@ -1,4 +1,5 @@ #include +#include "opencv2/geometry.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" diff --git a/samples/cpp/snippets/warpPerspective_demo.cpp b/samples/cpp/snippets/warpPerspective_demo.cpp index 1a5bb07d87..b31c330fa2 100644 --- a/samples/cpp/snippets/warpPerspective_demo.cpp +++ b/samples/cpp/snippets/warpPerspective_demo.cpp @@ -5,6 +5,7 @@ @modified by Suleyman TURKMEN */ +#include "opencv2/geometry.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" diff --git a/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp index 65ca184749..bc6ffcbc75 100644 --- a/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp +++ b/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp @@ -6,6 +6,7 @@ #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" +#include "opencv2/geometry.hpp" #include "opencv2/imgproc.hpp" #include diff --git a/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp b/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp index e8e7644c6a..2ba2b8f2ff 100644 --- a/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp +++ b/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp @@ -4,6 +4,7 @@ */ #include +#include #include #include #include diff --git a/samples/cpp/tutorial_code/objectDetection/detect_board.cpp b/samples/cpp/tutorial_code/objectDetection/detect_board.cpp index c7ed7ca7c0..86822a6f28 100644 --- a/samples/cpp/tutorial_code/objectDetection/detect_board.cpp +++ b/samples/cpp/tutorial_code/objectDetection/detect_board.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include "aruco_samples_utility.hpp" diff --git a/samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp b/samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp index 7c4b5a6f50..42d5382ad5 100644 --- a/samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp +++ b/samples/cpp/tutorial_code/objectDetection/detect_board_charuco.cpp @@ -1,4 +1,5 @@ #include +#include //! [charucohdr] #include //! [charucohdr] diff --git a/samples/cpp/tutorial_code/objectDetection/detect_diamonds.cpp b/samples/cpp/tutorial_code/objectDetection/detect_diamonds.cpp index 37097d87e9..0a533fe528 100644 --- a/samples/cpp/tutorial_code/objectDetection/detect_diamonds.cpp +++ b/samples/cpp/tutorial_code/objectDetection/detect_diamonds.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/samples/cpp/tutorial_code/objectDetection/detect_markers.cpp b/samples/cpp/tutorial_code/objectDetection/detect_markers.cpp index 06aa6221c4..2aba4654e5 100644 --- a/samples/cpp/tutorial_code/objectDetection/detect_markers.cpp +++ b/samples/cpp/tutorial_code/objectDetection/detect_markers.cpp @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/samples/dnn/text_detection.cpp b/samples/dnn/text_detection.cpp index c958715d8c..57e45d45bb 100644 --- a/samples/dnn/text_detection.cpp +++ b/samples/dnn/text_detection.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include