From 0d52c37e11121226eb7c8c356c369d202f00be5d Mon Sep 17 00:00:00 2001 From: Vincent Rabaud Date: Fri, 17 Jun 2022 11:39:50 +0200 Subject: [PATCH 1/7] Fix typo that prevents compilation with sanitizer. --- modules/core/src/hal_internal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/hal_internal.cpp b/modules/core/src/hal_internal.cpp index 5239acc585..d2648fae81 100644 --- a/modules/core/src/hal_internal.cpp +++ b/modules/core/src/hal_internal.cpp @@ -67,7 +67,7 @@ #if defined(__clang__) && defined(__has_feature) #if __has_feature(memory_sanitizer) #define CV_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ -__msan_unpoison(adresse, size) +__msan_unpoison(address, size) #endif #endif #ifndef CV_ANNOTATE_MEMORY_IS_INITIALIZED From db5b22e89549687dfd28dc3f9005545df4c96f9b Mon Sep 17 00:00:00 2001 From: Christine Poerschke Date: Fri, 17 Jun 2022 12:48:30 +0100 Subject: [PATCH 2/7] Merge pull request #22065 from cpoerschke:3.4-apps-visualisation-configurable-codec * apps/opencv_visualisation: configurable video codec * Update apps/visualisation/opencv_visualisation.cpp --- apps/visualisation/opencv_visualisation.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/visualisation/opencv_visualisation.cpp b/apps/visualisation/opencv_visualisation.cpp index be540efa62..85e9697aad 100644 --- a/apps/visualisation/opencv_visualisation.cpp +++ b/apps/visualisation/opencv_visualisation.cpp @@ -86,6 +86,9 @@ int main( int argc, const char** argv ) "{ image i | | (required) path to reference image }" "{ model m | | (required) path to cascade xml file }" "{ data d | | (optional) path to video output folder }" + "{ ext | avi | (optional) output video file extension e.g. avi (default) or mp4 }" + "{ fourcc | XVID | (optional) output video file's 4-character codec e.g. XVID (default) or H264 }" + "{ fps | 15 | (optional) output video file's frames-per-second rate }" ); // Read in the input arguments if (parser.has("help")){ @@ -96,7 +99,9 @@ int main( int argc, const char** argv ) string model(parser.get("model")); string output_folder(parser.get("data")); string image_ref = (parser.get("image")); - if (model.empty() || image_ref.empty()){ + string fourcc = (parser.get("fourcc")); + int fps = parser.get("fps"); + if (model.empty() || image_ref.empty() || fourcc.size()!=4 || fps<1){ parser.printMessage(); printLimits(); return -1; @@ -166,11 +171,19 @@ int main( int argc, const char** argv ) // each stage, containing all weak classifiers for that stage. bool draw_planes = false; stringstream output_video; - output_video << output_folder << "model_visualization.avi"; + output_video << output_folder << "model_visualization." << parser.get("ext"); VideoWriter result_video; if( output_folder.compare("") != 0 ){ draw_planes = true; - result_video.open(output_video.str(), VideoWriter::fourcc('X','V','I','D'), 15, Size(reference_image.cols * resize_factor, reference_image.rows * resize_factor), false); + result_video.open(output_video.str(), VideoWriter::fourcc(fourcc[0],fourcc[1],fourcc[2],fourcc[3]), fps, visualization.size(), false); + if (!result_video.isOpened()){ + cerr << "the output video '" << output_video.str() << "' could not be opened." + << " fourcc=" << fourcc + << " fps=" << fps + << " frameSize=" << visualization.size() + << endl; + return -1; + } } if(haar){ From a04f9e7a59b83008255bdae40e3499efe0af9fb2 Mon Sep 17 00:00:00 2001 From: catree Date: Sun, 19 Jun 2022 01:27:32 +0200 Subject: [PATCH 3/7] Add more references. Update missing references with webarchive. Use mathbf for matrices. Check that the determinant of the rotation matrix is not negative (reflection), and correct it if it is the case. --- doc/opencv.bib | 20 +++-- .../features2d/homography/homography.markdown | 84 ++++++++++--------- modules/calib3d/include/opencv2/calib3d.hpp | 4 +- .../Homography/pose_from_homography.cpp | 11 ++- 4 files changed, 70 insertions(+), 49 deletions(-) diff --git a/doc/opencv.bib b/doc/opencv.bib index 13fe71a1fb..dddb957995 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -543,7 +543,7 @@ title = {Multiple view geometry in computer vision}, year = {2003}, publisher = {Cambridge university press}, - url = {http://cds.cern.ch/record/1598612/files/0521540518_TOC.pdf} + url = {https://www.robots.ox.ac.uk/~vgg/hzbook/} } @article{Horaud95, author = {Horaud, Radu and Dornaika, Fadi}, @@ -745,10 +745,17 @@ isbn = {0387008934}, publisher = {Springer} } -@article{Malis, - author = {Malis, Ezio and Vargas, Manuel and others}, - title = {Deeper understanding of the homography decomposition for vision-based control}, - year = {2007} +@article{Malis2007, + author = {Malis, Ezio and Vargas, Manuel}, + title = {{Deeper understanding of the homography decomposition for vision-based control}}, + year = {2007}, + url = {https://hal.inria.fr/inria-00174036}, + type = {Research Report}, + number = {RR-6303}, + pages = {90}, + institution = {{INRIA}}, + keywords = {Visual servoing ; planar objects ; homography ; decomposition ; camera calibration errors ; structure from motion ; Euclidean}, + pdf = {https://hal.inria.fr/inria-00174036v3/file/RR-6303.pdf}, } @article{Marchand16, author = {Marchand, Eric and Uchiyama, Hideaki and Spindler, Fabien}, @@ -905,7 +912,8 @@ author = {Szeliski, Richard}, title = {Computer vision: algorithms and applications}, year = {2010}, - publisher = {Springer} + publisher = {Springer}, + url = {https://szeliski.org/Book/} } @article{Rafael12, author = {von Gioi, Rafael Grompone and Jakubowicz, J{\'e}r{\'e}mie and Morel, Jean-Michel and Randall, Gregory}, diff --git a/doc/tutorials/features2d/homography/homography.markdown b/doc/tutorials/features2d/homography/homography.markdown index 3d8f97c28b..e5009798c3 100644 --- a/doc/tutorials/features2d/homography/homography.markdown +++ b/doc/tutorials/features2d/homography/homography.markdown @@ -10,9 +10,11 @@ Introduction {#tutorial_homography_Introduction} This tutorial will demonstrate the basic concepts of the homography with some codes. For detailed explanations about the theory, please refer to a computer vision course or a computer vision book, e.g.: -* Multiple View Geometry in Computer Vision, @cite HartleyZ00. -* An Invitation to 3-D Vision: From Images to Geometric Models, @cite Ma:2003:IVI -* Computer Vision: Algorithms and Applications, @cite RS10 +* Multiple View Geometry in Computer Vision, Richard Hartley and Andrew Zisserman, @cite HartleyZ00 (some sample chapters are available [here](https://www.robots.ox.ac.uk/~vgg/hzbook/), CVPR Tutorials are available [here](https://www.robots.ox.ac.uk/~az/tutorials/)) +* An Invitation to 3-D Vision: From Images to Geometric Models, Yi Ma, Stefano Soatto, Jana Kosecka, and S. Shankar Sastry, @cite Ma:2003:IVI (a computer vision book handout is available [here](https://cs.gmu.edu/%7Ekosecka/cs685/VisionBookHandout.pdf)) +* Computer Vision: Algorithms and Applications, Richard Szeliski, @cite RS10 (an electronic version is available [here](https://szeliski.org/Book/)) +* Deeper understanding of the homography decomposition for vision-based control, Ezio Malis, Manuel Vargas, @cite Malis2007 (open access [here](https://hal.inria.fr/inria-00174036)) +* Pose Estimation for Augmented Reality: A Hands-On Survey, Eric Marchand, Hideaki Uchiyama, Fabien Spindler, @cite Marchand16 (open access [here](https://hal.inria.fr/hal-01246370)) The tutorial code can be found here [C++](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/features2D/Homography), [Python](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/features2D/Homography), @@ -32,7 +34,7 @@ Briefly, the planar homography relates the transformation between two planes (up x^{'} \\ y^{'} \\ 1 - \end{bmatrix} = H + \end{bmatrix} = \mathbf{H} \begin{bmatrix} x \\ y \\ @@ -123,22 +125,22 @@ A quick solution to retrieve the pose from the homography matrix is (see \ref po \f[ \begin{align*} - \boldsymbol{X} &= \left( X, Y, 0, 1 \right ) \\ - \boldsymbol{x} &= \boldsymbol{P}\boldsymbol{X} \\ - &= \boldsymbol{K} \left[ \boldsymbol{r_1} \hspace{0.5em} \boldsymbol{r_2} \hspace{0.5em} \boldsymbol{r_3} \hspace{0.5em} \boldsymbol{t} \right ] + \mathbf{X} &= \left( X, Y, 0, 1 \right ) \\ + \mathbf{x} &= \mathbf{P}\mathbf{X} \\ + &= \mathbf{K} \left[ \mathbf{r_1} \hspace{0.5em} \mathbf{r_2} \hspace{0.5em} \mathbf{r_3} \hspace{0.5em} \mathbf{t} \right ] \begin{pmatrix} X \\ Y \\ 0 \\ 1 \end{pmatrix} \\ - &= \boldsymbol{K} \left[ \boldsymbol{r_1} \hspace{0.5em} \boldsymbol{r_2} \hspace{0.5em} \boldsymbol{t} \right ] + &= \mathbf{K} \left[ \mathbf{r_1} \hspace{0.5em} \mathbf{r_2} \hspace{0.5em} \mathbf{t} \right ] \begin{pmatrix} X \\ Y \\ 1 \end{pmatrix} \\ - &= \boldsymbol{H} + &= \mathbf{H} \begin{pmatrix} X \\ Y \\ @@ -149,16 +151,16 @@ A quick solution to retrieve the pose from the homography matrix is (see \ref po \f[ \begin{align*} - \boldsymbol{H} &= \lambda \boldsymbol{K} \left[ \boldsymbol{r_1} \hspace{0.5em} \boldsymbol{r_2} \hspace{0.5em} \boldsymbol{t} \right ] \\ - \boldsymbol{K}^{-1} \boldsymbol{H} &= \lambda \left[ \boldsymbol{r_1} \hspace{0.5em} \boldsymbol{r_2} \hspace{0.5em} \boldsymbol{t} \right ] \\ - \boldsymbol{P} &= \boldsymbol{K} \left[ \boldsymbol{r_1} \hspace{0.5em} \boldsymbol{r_2} \hspace{0.5em} \left( \boldsymbol{r_1} \times \boldsymbol{r_2} \right ) \hspace{0.5em} \boldsymbol{t} \right ] + \mathbf{H} &= \lambda \mathbf{K} \left[ \mathbf{r_1} \hspace{0.5em} \mathbf{r_2} \hspace{0.5em} \mathbf{t} \right ] \\ + \mathbf{K}^{-1} \mathbf{H} &= \lambda \left[ \mathbf{r_1} \hspace{0.5em} \mathbf{r_2} \hspace{0.5em} \mathbf{t} \right ] \\ + \mathbf{P} &= \mathbf{K} \left[ \mathbf{r_1} \hspace{0.5em} \mathbf{r_2} \hspace{0.5em} \left( \mathbf{r_1} \times \mathbf{r_2} \right ) \hspace{0.5em} \mathbf{t} \right ] \end{align*} \f] This is a quick solution (see also \ref projective_transformations "2") as this does not ensure that the resulting rotation matrix will be orthogonal and the scale is estimated roughly by normalize the first column to 1. -A solution to have a proper rotation matrix (with the properties of a rotation matrix) consists to apply a polar decomposition -(see \ref polar_decomposition "6" or \ref polar_decomposition_svd "7" for some information): +A solution to have a proper rotation matrix (with the properties of a rotation matrix) consists to apply a polar decomposition, or orthogonalization of the rotation matrix +(see \ref polar_decomposition "6" or \ref polar_decomposition_svd "7" or \ref polar_decomposition_svd_2 "8" or \ref Kabsch_algorithm "9" for some information): @snippet pose_from_homography.cpp polar-decomposition-of-the-rotation-matrix @@ -239,7 +241,7 @@ To check the correctness of the calculation, the matching lines are displayed: ### Demo 3: Homography from the camera displacement {#tutorial_homography_Demo3} -The homography relates the transformation between two planes and it is possible to retrieve the corresponding camera displacement that allows to go from the first to the second plane view (see @cite Malis for more information). +The homography relates the transformation between two planes and it is possible to retrieve the corresponding camera displacement that allows to go from the first to the second plane view (see @cite Malis2007 for more information). Before going into the details that allow to compute the homography from the camera displacement, some recalls about camera pose and homogeneous transformation. The function @ref cv::solvePnP allows to compute the camera pose from the correspondences 3D object points (points expressed in the object frame) and the projected 2D image points (object points viewed in the image). @@ -269,7 +271,7 @@ The intrinsic parameters and the distortion coefficients are required (see the c Z_o \\ 1 \end{bmatrix} \\ - &= \boldsymbol{K} \hspace{0.2em} ^{c}\textrm{M}_o + &= \mathbf{K} \hspace{0.2em} ^{c}\mathbf{M}_o \begin{bmatrix} X_o \\ Y_o \\ @@ -279,9 +281,9 @@ The intrinsic parameters and the distortion coefficients are required (see the c \end{align*} \f] -\f$ \boldsymbol{K} \f$ is the intrinsic matrix and \f$ ^{c}\textrm{M}_o \f$ is the camera pose. The output of @ref cv::solvePnP is exactly this: `rvec` is the Rodrigues rotation vector and `tvec` the translation vector. +\f$ \mathbf{K} \f$ is the intrinsic matrix and \f$ ^{c}\mathbf{M}_o \f$ is the camera pose. The output of @ref cv::solvePnP is exactly this: `rvec` is the Rodrigues rotation vector and `tvec` the translation vector. -\f$ ^{c}\textrm{M}_o \f$ can be represented in a homogeneous form and allows to transform a point expressed in the object frame into the camera frame: +\f$ ^{c}\mathbf{M}_o \f$ can be represented in a homogeneous form and allows to transform a point expressed in the object frame into the camera frame: \f[ \begin{align*} @@ -291,7 +293,7 @@ The intrinsic parameters and the distortion coefficients are required (see the c Z_c \\ 1 \end{bmatrix} &= - \hspace{0.2em} ^{c}\textrm{M}_o + \hspace{0.2em} ^{c}\mathbf{M}_o \begin{bmatrix} X_o \\ Y_o \\ @@ -300,7 +302,7 @@ The intrinsic parameters and the distortion coefficients are required (see the c \end{bmatrix} \\ &= \begin{bmatrix} - ^{c}\textrm{R}_o & ^{c}\textrm{t}_o \\ + ^{c}\mathbf{R}_o & ^{c}\mathbf{t}_o \\ 0_{1\times3} & 1 \end{bmatrix} \begin{bmatrix} @@ -327,19 +329,19 @@ The intrinsic parameters and the distortion coefficients are required (see the c Transform a point expressed in one frame to another frame can be easily done with matrix multiplication: -* \f$ ^{c_1}\textrm{M}_o \f$ is the camera pose for the camera 1 -* \f$ ^{c_2}\textrm{M}_o \f$ is the camera pose for the camera 2 +* \f$ ^{c_1}\mathbf{M}_o \f$ is the camera pose for the camera 1 +* \f$ ^{c_2}\mathbf{M}_o \f$ is the camera pose for the camera 2 To transform a 3D point expressed in the camera 1 frame to the camera 2 frame: \f[ - ^{c_2}\textrm{M}_{c_1} = \hspace{0.2em} ^{c_2}\textrm{M}_{o} \cdot \hspace{0.1em} ^{o}\textrm{M}_{c_1} = \hspace{0.2em} ^{c_2}\textrm{M}_{o} \cdot \hspace{0.1em} \left( ^{c_1}\textrm{M}_{o} \right )^{-1} = + ^{c_2}\mathbf{M}_{c_1} = \hspace{0.2em} ^{c_2}\mathbf{M}_{o} \cdot \hspace{0.1em} ^{o}\mathbf{M}_{c_1} = \hspace{0.2em} ^{c_2}\mathbf{M}_{o} \cdot \hspace{0.1em} \left( ^{c_1}\mathbf{M}_{o} \right )^{-1} = \begin{bmatrix} - ^{c_2}\textrm{R}_{o} & ^{c_2}\textrm{t}_{o} \\ + ^{c_2}\mathbf{R}_{o} & ^{c_2}\mathbf{t}_{o} \\ 0_{3 \times 1} & 1 \end{bmatrix} \cdot \begin{bmatrix} - ^{c_1}\textrm{R}_{o}^T & - \hspace{0.2em} ^{c_1}\textrm{R}_{o}^T \cdot \hspace{0.2em} ^{c_1}\textrm{t}_{o} \\ + ^{c_1}\mathbf{R}_{o}^T & - \hspace{0.2em} ^{c_1}\mathbf{R}_{o}^T \cdot \hspace{0.2em} ^{c_1}\mathbf{t}_{o} \\ 0_{1 \times 3} & 1 \end{bmatrix} \f] @@ -362,11 +364,11 @@ On this figure, `n` is the normal vector of the plane and `d` the distance betwe The [equation](https://en.wikipedia.org/wiki/Homography_(computer_vision)#3D_plane_to_plane_equation) to compute the homography from the camera displacement is: \f[ - ^{2}\textrm{H}_{1} = \hspace{0.2em} ^{2}\textrm{R}_{1} - \hspace{0.1em} \frac{^{2}\textrm{t}_{1} \cdot n^T}{d} + ^{2}\mathbf{H}_{1} = \hspace{0.2em} ^{2}\mathbf{R}_{1} - \hspace{0.1em} \frac{^{2}\mathbf{t}_{1} \cdot \hspace{0.1em} ^{1}\mathbf{n}^\top}{^1d} \f] -Where \f$ ^{2}\textrm{H}_{1} \f$ is the homography matrix that maps the points in the first camera frame to the corresponding points in the second camera frame, \f$ ^{2}\textrm{R}_{1} = \hspace{0.2em} ^{c_2}\textrm{R}_{o} \cdot \hspace{0.1em} ^{c_1}\textrm{R}_{o}^{T} \f$ -is the rotation matrix that represents the rotation between the two camera frames and \f$ ^{2}\textrm{t}_{1} = \hspace{0.2em} ^{c_2}\textrm{R}_{o} \cdot \left( - \hspace{0.1em} ^{c_1}\textrm{R}_{o}^{T} \cdot \hspace{0.1em} ^{c_1}\textrm{t}_{o} \right ) + \hspace{0.1em} ^{c_2}\textrm{t}_{o} \f$ +Where \f$ ^{2}\mathbf{H}_{1} \f$ is the homography matrix that maps the points in the first camera frame to the corresponding points in the second camera frame, \f$ ^{2}\mathbf{R}_{1} = \hspace{0.2em} ^{c_2}\mathbf{R}_{o} \cdot \hspace{0.1em} ^{c_1}\mathbf{R}_{o}^{\top} \f$ +is the rotation matrix that represents the rotation between the two camera frames and \f$ ^{2}\mathbf{t}_{1} = \hspace{0.2em} ^{c_2}\mathbf{R}_{o} \cdot \left( - \hspace{0.1em} ^{c_1}\mathbf{R}_{o}^{\top} \cdot \hspace{0.1em} ^{c_1}\mathbf{t}_{o} \right ) + \hspace{0.1em} ^{c_2}\mathbf{t}_{o} \f$ the translation vector between the two camera frames. Here the normal vector `n` is the plane normal expressed in the camera frame 1 and can be computed as the cross product of 2 vectors (using 3 non collinear points that lie on the plane) or in our case directly with: @@ -377,7 +379,7 @@ The distance `d` can be computed as the dot product between the plane normal and @snippet homography_from_camera_displacement.cpp compute-plane-distance-to-the-camera-frame-1 -The projective homography matrix \f$ \textbf{G} \f$ can be computed from the Euclidean homography \f$ \textbf{H} \f$ using the intrinsic matrix \f$ \textbf{K} \f$ (see @cite Malis), here assuming the same camera between the two plane views: +The projective homography matrix \f$ \textbf{G} \f$ can be computed from the Euclidean homography \f$ \textbf{H} \f$ using the intrinsic matrix \f$ \textbf{K} \f$ (see @cite Malis2007), here assuming the same camera between the two plane views: \f[ \textbf{G} = \gamma \textbf{K} \textbf{H} \textbf{K}^{-1} @@ -388,7 +390,7 @@ The projective homography matrix \f$ \textbf{G} \f$ can be computed from the Euc In our case, the Z-axis of the chessboard goes inside the object whereas in the homography figure it goes outside. This is just a matter of sign: \f[ - ^{2}\textrm{H}_{1} = \hspace{0.2em} ^{2}\textrm{R}_{1} + \hspace{0.1em} \frac{^{2}\textrm{t}_{1} \cdot n^T}{d} + ^{2}\mathbf{H}_{1} = \hspace{0.2em} ^{2}\mathbf{R}_{1} + \hspace{0.1em} \frac{^{2}\mathbf{t}_{1} \cdot \hspace{0.1em} ^{1}\mathbf{n}^\top}{^1d} \f] @snippet homography_from_camera_displacement.cpp compute-homography-from-camera-displacement @@ -466,8 +468,8 @@ As you can see, there is one solution that matches almost perfectly with the com At least two of the solutions may further be invalidated if point correspondences are available by applying positive depth constraint (all points must be in front of the camera). ``` -As the result of the decomposition is a camera displacement, if we have the initial camera pose \f$ ^{c_1}\textrm{M}_{o} \f$, we can compute the current camera pose -\f$ ^{c_2}\textrm{M}_{o} = \hspace{0.2em} ^{c_2}\textrm{M}_{c_1} \cdot \hspace{0.1em} ^{c_1}\textrm{M}_{o} \f$ and test if the 3D object points that belong to the plane are projected in front of the camera or not. +As the result of the decomposition is a camera displacement, if we have the initial camera pose \f$ ^{c_1}\mathbf{M}_{o} \f$, we can compute the current camera pose +\f$ ^{c_2}\mathbf{M}_{o} = \hspace{0.2em} ^{c_2}\mathbf{M}_{c_1} \cdot \hspace{0.1em} ^{c_1}\mathbf{M}_{o} \f$ and test if the 3D object points that belong to the plane are projected in front of the camera or not. Another solution could be to retain the solution with the closest normal if we know the plane normal expressed at the camera 1 pose. The same thing but with the homography matrix estimated with @ref cv::findHomography @@ -516,7 +518,7 @@ The [stitching module](@ref stitching) provides a complete pipeline to stitch im The homography transformation applies only for planar structure. But in the case of a rotating camera (pure rotation around the camera axis of projection, no translation), an arbitrary world can be considered ([see previously](@ref tutorial_homography_What_is_the_homography_matrix)). -The homography can then be computed using the rotation transformation and the camera intrinsic parameters as (see for instance \ref homography_course "8"): +The homography can then be computed using the rotation transformation and the camera intrinsic parameters as (see for instance \ref homography_course "10"): \f[ s @@ -534,7 +536,7 @@ The homography can then be computed using the rotation transformation and the ca \f] To illustrate, we used Blender, a free and open-source 3D computer graphics software, to generate two camera views with only a rotation transformation between each other. -More information about how to retrieve the camera intrinsic parameters and the `3x4` extrinsic matrix with respect to the world can be found in \ref answer_blender "9" (an additional transformation +More information about how to retrieve the camera intrinsic parameters and the `3x4` extrinsic matrix with respect to the world can be found in \ref answer_blender "11" (an additional transformation is needed to get the transformation between the camera and the object frames) with Blender. The figure below shows the two generated views of the Suzanne model, with only a rotation transformation: @@ -603,11 +605,13 @@ Additional references {#tutorial_homography_Additional_references} --------------------- * \anchor lecture_16 1. [Lecture 16: Planar Homographies](http://www.cse.psu.edu/~rtc12/CSE486/lecture16.pdf), Robert Collins -* \anchor projective_transformations 2. [2D projective transformations (homographies)](https://ags.cs.uni-kl.de/fileadmin/inf_ags/3dcv-ws11-12/3DCV_WS11-12_lec04.pdf), Christiano Gava, Gabriele Bleser -* \anchor szeliski 3. [Computer Vision: Algorithms and Applications](http://szeliski.org/Book/drafts/SzeliskiBook_20100903_draft.pdf), Richard Szeliski +* \anchor projective_transformations 2. [2D projective transformations (homographies)](https://web.archive.org/web/20171226115739/https://ags.cs.uni-kl.de/fileadmin/inf_ags/3dcv-ws11-12/3DCV_WS11-12_lec04.pdf), Christiano Gava, Gabriele Bleser +* \anchor szeliski 3. [Computer Vision: Algorithms and Applications](https://szeliski.org/Book/), Richard Szeliski * \anchor answer_dsp 4. [Step by Step Camera Pose Estimation for Visual Tracking and Planar Markers](https://dsp.stackexchange.com/a/2737) -* \anchor pose_ar 5. [Pose from homography estimation](https://team.inria.fr/lagadic/camera_localization/tutorial-pose-dlt-planar-opencv.html) +* \anchor pose_ar 5. [Pose from homography estimation](https://visp-doc.inria.fr/doxygen/camera_localization/tutorial-pose-dlt-planar-opencv.html) * \anchor polar_decomposition 6. [Polar Decomposition (in Continuum Mechanics)](http://www.continuummechanics.org/polardecomposition.html) -* \anchor polar_decomposition_svd 7. [A Personal Interview with the Singular Value Decomposition](https://web.stanford.edu/~gavish/documents/SVD_ans_you.pdf), Matan Gavish -* \anchor homography_course 8. [Homography](http://people.scs.carleton.ca/~c_shu/Courses/comp4900d/notes/homography.pdf), Dr. Gerhard Roth -* \anchor answer_blender 9. [3x4 camera matrix from blender camera](https://blender.stackexchange.com/a/38210) +* \anchor polar_decomposition_svd 7. [Chapter 3 - 3.1.2 From matrices to rotations - Theorem 3.1 (Least-squares estimation of a rotation from a matrix K)](https://www-sop.inria.fr/asclepios/cours/MVA/Rotations.pdf) +* \anchor polar_decomposition_svd_2 8. [A Personal Interview with the Singular Value Decomposition](https://web.stanford.edu/~gavish/documents/SVD_ans_you.pdf), Matan Gavish +* \anchor Kabsch_algorithm 9. [Kabsch algorithm, Computation of the optimal rotation matrix](https://en.wikipedia.org/wiki/Kabsch_algorithm#Computation_of_the_optimal_rotation_matrix) +* \anchor homography_course 10. [Homography](http://people.scs.carleton.ca/~c_shu/Courses/comp4900d/notes/homography.pdf), Dr. Gerhard Roth +* \anchor answer_blender 11. [3x4 camera matrix from blender camera](https://blender.stackexchange.com/a/38210) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index 63eded027f..99458e86fa 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -2559,7 +2559,7 @@ Check @ref tutorial_homography "the corresponding tutorial" for more details. This function extracts relative camera motion between two views of a planar object and returns up to four mathematical solution tuples of rotation, translation, and plane normal. The decomposition of -the homography matrix H is described in detail in @cite Malis. +the homography matrix H is described in detail in @cite Malis2007. If the homography H, induced by the plane, gives the constraint \f[s_i \vecthree{x'_i}{y'_i}{1} \sim H \vecthree{x_i}{y_i}{1}\f] on the source image points @@ -2587,7 +2587,7 @@ CV_EXPORTS_W int decomposeHomographyMat(InputArray H, @param pointsMask optional Mat/Vector of 8u type representing the mask for the inliers as given by the findHomography function This function is intended to filter the output of the decomposeHomographyMat based on additional -information as described in @cite Malis . The summary of the method: the decomposeHomographyMat function +information as described in @cite Malis2007 . The summary of the method: the decomposeHomographyMat function returns 2 unique solutions and their "opposites" for a total of 4 solutions. If we have access to the sets of points visible in the camera frame before and after the homography transformation is applied, we can determine which are the true potential solutions and which are the opposites by verifying which diff --git a/samples/cpp/tutorial_code/features2D/Homography/pose_from_homography.cpp b/samples/cpp/tutorial_code/features2D/Homography/pose_from_homography.cpp index 37ebcac7be..ae86fcfaa2 100644 --- a/samples/cpp/tutorial_code/features2D/Homography/pose_from_homography.cpp +++ b/samples/cpp/tutorial_code/features2D/Homography/pose_from_homography.cpp @@ -109,9 +109,18 @@ void poseEstimationFromCoplanarPoints(const string &imgPath, const string &intri //! [polar-decomposition-of-the-rotation-matrix] cout << "R (before polar decomposition):\n" << R << "\ndet(R): " << determinant(R) << endl; - Mat W, U, Vt; + Mat_ W, U, Vt; SVDecomp(R, W, U, Vt); R = U*Vt; + double det = determinant(R); + if (det < 0) + { + Vt.at(2,0) *= -1; + Vt.at(2,1) *= -1; + Vt.at(2,2) *= -1; + + R = U*Vt; + } cout << "R (after polar decomposition):\n" << R << "\ndet(R): " << determinant(R) << endl; //! [polar-decomposition-of-the-rotation-matrix] From dd7b9000ada172fa3c8954a89339dcf6249b8a59 Mon Sep 17 00:00:00 2001 From: Kumataro Date: Tue, 21 Jun 2022 03:42:50 +0900 Subject: [PATCH 4/7] Merge pull request #22064 from Kumataro:3.4-fix22052 * imgcodecs: jpeg: add IMWRITE_JPEG_SAMPLING_FACTOR parameter * fix compile error * imgcodecs: jpeg: add CV_LOG_WARNING() and fix how to initilize Mat * imgcodecs: jpeg: fix for C++98 mode. * samples: imgcodec_jpeg: Remove license --- .../imgcodecs/include/opencv2/imgcodecs.hpp | 11 +++ modules/imgcodecs/src/grfmt_jpeg.cpp | 32 +++++++ modules/imgcodecs/test/test_jpeg.cpp | 92 +++++++++++++++++++ samples/cpp/imgcodecs_jpeg.cpp | 82 +++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 samples/cpp/imgcodecs_jpeg.cpp diff --git a/modules/imgcodecs/include/opencv2/imgcodecs.hpp b/modules/imgcodecs/include/opencv2/imgcodecs.hpp index ba63e9934b..49f76826b9 100644 --- a/modules/imgcodecs/include/opencv2/imgcodecs.hpp +++ b/modules/imgcodecs/include/opencv2/imgcodecs.hpp @@ -89,6 +89,7 @@ enum ImwriteFlags { IMWRITE_JPEG_RST_INTERVAL = 4, //!< JPEG restart interval, 0 - 65535, default is 0 - no restart. IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is -1 - don't use. IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is -1 - don't use. + IMWRITE_JPEG_SAMPLING_FACTOR = 7, //!< For JPEG, set sampling factor. See cv::ImwriteJPEGSamplingFactorParams. IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting). IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE. IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0. @@ -102,12 +103,22 @@ enum ImwriteFlags { IMWRITE_TIFF_COMPRESSION = 259 //!< For TIFF, use to specify the image compression scheme. See libtiff for integer constants corresponding to compression formats. Note, for images whose depth is CV_32F, only libtiff's SGILOG compression scheme is used. For other supported depths, the compression scheme can be specified by this flag; LZW compression is the default. }; +enum ImwriteJPEGSamplingFactorParams { + IMWRITE_JPEG_SAMPLING_FACTOR_411 = 0x411111, //!< 4x1,1x1,1x1 + IMWRITE_JPEG_SAMPLING_FACTOR_420 = 0x221111, //!< 2x2,1x1,1x1(Default) + IMWRITE_JPEG_SAMPLING_FACTOR_422 = 0x211111, //!< 2x1,1x1,1x1 + IMWRITE_JPEG_SAMPLING_FACTOR_440 = 0x121111, //!< 1x2,1x1,1x1 + IMWRITE_JPEG_SAMPLING_FACTOR_444 = 0x111111 //!< 1x1,1x1,1x1(No subsampling) + }; + + enum ImwriteEXRTypeFlags { /*IMWRITE_EXR_TYPE_UNIT = 0, //!< not supported */ IMWRITE_EXR_TYPE_HALF = 1, //!< store as HALF (FP16) IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default) }; + //! Imwrite PNG specific flags used to tune the compression algorithm. /** These flags will be modify the way of PNG image compression and will be passed to the underlying zlib processing stage. diff --git a/modules/imgcodecs/src/grfmt_jpeg.cpp b/modules/imgcodecs/src/grfmt_jpeg.cpp index d9e056f1a8..9500e196f5 100644 --- a/modules/imgcodecs/src/grfmt_jpeg.cpp +++ b/modules/imgcodecs/src/grfmt_jpeg.cpp @@ -44,6 +44,8 @@ #ifdef HAVE_JPEG +#include + #ifdef _MSC_VER //interaction between '_setjmp' and C++ object destruction is non-portable #pragma warning(disable: 4611) @@ -640,6 +642,7 @@ bool JpegEncoder::write( const Mat& img, const std::vector& params ) int rst_interval = 0; int luma_quality = -1; int chroma_quality = -1; + uint32_t sampling_factor = 0; // same as 0x221111 for( size_t i = 0; i < params.size(); i += 2 ) { @@ -687,6 +690,27 @@ bool JpegEncoder::write( const Mat& img, const std::vector& params ) rst_interval = params[i+1]; rst_interval = MIN(MAX(rst_interval, 0), 65535L); } + + if( params[i] == IMWRITE_JPEG_SAMPLING_FACTOR ) + { + sampling_factor = static_cast(params[i+1]); + + switch ( sampling_factor ) + { + case IMWRITE_JPEG_SAMPLING_FACTOR_411: + case IMWRITE_JPEG_SAMPLING_FACTOR_420: + case IMWRITE_JPEG_SAMPLING_FACTOR_422: + case IMWRITE_JPEG_SAMPLING_FACTOR_440: + case IMWRITE_JPEG_SAMPLING_FACTOR_444: + // OK. + break; + + default: + CV_LOG_WARNING(NULL, cv::format("Unknown value for IMWRITE_JPEG_SAMPLING_FACTOR: 0x%06x", sampling_factor ) ); + sampling_factor = 0; + break; + } + } } jpeg_set_defaults( &cinfo ); @@ -699,6 +723,14 @@ bool JpegEncoder::write( const Mat& img, const std::vector& params ) if( optimize ) cinfo.optimize_coding = TRUE; + if( (channels > 1) && ( sampling_factor != 0 ) ) + { + cinfo.comp_info[0].v_samp_factor = (sampling_factor >> 16 ) & 0xF; + cinfo.comp_info[0].h_samp_factor = (sampling_factor >> 20 ) & 0xF; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + } + #if JPEG_LIB_VERSION >= 70 if (luma_quality >= 0 && chroma_quality >= 0) { diff --git a/modules/imgcodecs/test/test_jpeg.cpp b/modules/imgcodecs/test/test_jpeg.cpp index 9b516a9aba..b7932a0020 100644 --- a/modules/imgcodecs/test/test_jpeg.cpp +++ b/modules/imgcodecs/test/test_jpeg.cpp @@ -178,6 +178,98 @@ TEST(Imgcodecs_Jpeg, encode_decode_rst_jpeg) EXPECT_EQ(0, remove(output_normal.c_str())); } +//================================================================================================== + +static const uint32_t default_sampling_factor = static_cast(0x221111); + +static uint32_t test_jpeg_subsampling( const Mat src, const vector param ) +{ + vector jpeg; + + if ( cv::imencode(".jpg", src, jpeg, param ) == false ) + { + return 0; + } + + if ( src.channels() != 3 ) + { + return 0; + } + + // Find SOF Marker(FFC0) + int sof_offset = 0; // not found. + int jpeg_size = static_cast( jpeg.size() ); + for ( int i = 0 ; i < jpeg_size - 1; i++ ) + { + if ( (jpeg[i] == 0xff ) && ( jpeg[i+1] == 0xC0 ) ) + { + sof_offset = i; + break; + } + } + if ( sof_offset == 0 ) + { + return 0; + } + + // Extract Subsampling Factor from SOF. + return ( jpeg[sof_offset + 0x0A + 3 * 0 + 1] << 16 ) + + ( jpeg[sof_offset + 0x0A + 3 * 1 + 1] << 8 ) + + ( jpeg[sof_offset + 0x0A + 3 * 2 + 1] ) ; +} + +TEST(Imgcodecs_Jpeg, encode_subsamplingfactor_default) +{ + vector param; + Mat src( 48, 64, CV_8UC3, cv::Scalar::all(0) ); + EXPECT_EQ( default_sampling_factor, test_jpeg_subsampling(src, param) ); +} + +TEST(Imgcodecs_Jpeg, encode_subsamplingfactor_usersetting_valid) +{ + Mat src( 48, 64, CV_8UC3, cv::Scalar::all(0) ); + const uint32_t sampling_factor_list[] = { + IMWRITE_JPEG_SAMPLING_FACTOR_411, + IMWRITE_JPEG_SAMPLING_FACTOR_420, + IMWRITE_JPEG_SAMPLING_FACTOR_422, + IMWRITE_JPEG_SAMPLING_FACTOR_440, + IMWRITE_JPEG_SAMPLING_FACTOR_444, + }; + const int sampling_factor_list_num = 5; + + for ( int i = 0 ; i < sampling_factor_list_num; i ++ ) + { + vector param; + param.push_back( IMWRITE_JPEG_SAMPLING_FACTOR ); + param.push_back( sampling_factor_list[i] ); + EXPECT_EQ( sampling_factor_list[i], test_jpeg_subsampling(src, param) ); + } +} + +TEST(Imgcodecs_Jpeg, encode_subsamplingfactor_usersetting_invalid) +{ + Mat src( 48, 64, CV_8UC3, cv::Scalar::all(0) ); + const uint32_t sampling_factor_list[] = { // Invalid list + 0x111112, + 0x000000, + 0x001111, + 0xFF1111, + 0x141111, // 1x4,1x1,1x1 - unknown + 0x241111, // 2x4,1x1,1x1 - unknown + 0x421111, // 4x2,1x1,1x1 - unknown + 0x441111, // 4x4,1x1,1x1 - 410(libjpeg cannot handle it) + }; + const int sampling_factor_list_num = 8; + + for ( int i = 0 ; i < sampling_factor_list_num; i ++ ) + { + vector param; + param.push_back( IMWRITE_JPEG_SAMPLING_FACTOR ); + param.push_back( sampling_factor_list[i] ); + EXPECT_EQ( default_sampling_factor, test_jpeg_subsampling(src, param) ); + } +} + #endif // HAVE_JPEG }} // namespace diff --git a/samples/cpp/imgcodecs_jpeg.cpp b/samples/cpp/imgcodecs_jpeg.cpp new file mode 100644 index 0000000000..b3abc49286 --- /dev/null +++ b/samples/cpp/imgcodecs_jpeg.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include + +using namespace std; +using namespace cv; + +int main(int /*argc*/, const char** /* argv */ ) +{ + Mat framebuffer( 160 * 2, 160 * 5, CV_8UC3, cv::Scalar::all(255) ); + + Mat img( 160, 160, CV_8UC3, cv::Scalar::all(255) ); + + // Create test image. + { + const Point center( img.rows / 2 , img.cols /2 ); + + for( int radius = 5; radius < img.rows ; radius += 3.5 ) + { + cv::circle( img, center, radius, Scalar(255,0,255) ); + } + cv::rectangle( img, Point(0,0), Point(img.rows-1, img.cols-1), Scalar::all(0), 2 ); + } + + // Draw original image(s). + int top = 0; // Upper images + { + for( int left = 0 ; left < img.rows * 5 ; left += img.rows ){ + Mat roi = framebuffer( Rect( left, top, img.rows, img.cols ) ); + img.copyTo(roi); + + cv::putText( roi, "original", Point(5,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar::all(0), 2, 4, false ); + } + } + + // Draw lossy images + top += img.cols; // Lower images + { + struct test_config{ + string comment; + uint32_t sampling_factor; + } config [] = { + { "411", IMWRITE_JPEG_SAMPLING_FACTOR_411 }, + { "420", IMWRITE_JPEG_SAMPLING_FACTOR_420 }, + { "422", IMWRITE_JPEG_SAMPLING_FACTOR_422 }, + { "440", IMWRITE_JPEG_SAMPLING_FACTOR_440 }, + { "444", IMWRITE_JPEG_SAMPLING_FACTOR_444 }, + }; + + const int config_num = 5; + + int left = 0; + + for ( int i = 0 ; i < config_num; i++ ) + { + // Compress images with sampling factor parameter. + vector param; + param.push_back( IMWRITE_JPEG_SAMPLING_FACTOR ); + param.push_back( config[i].sampling_factor ); + vector jpeg; + (void) imencode(".jpg", img, jpeg, param ); + + // Decompress it. + Mat jpegMat(jpeg); + Mat lossy_img = imdecode(jpegMat, -1); + + // Copy into framebuffer and comment + Mat roi = framebuffer( Rect( left, top, lossy_img.rows, lossy_img.cols ) ); + lossy_img.copyTo(roi); + cv::putText( roi, config[i].comment, Point(5,155), FONT_HERSHEY_SIMPLEX, 0.5, Scalar::all(0), 2, 4, false ); + + left += lossy_img.rows; + } + } + + // Output framebuffer(as lossless). + imwrite( "imgcodecs_jpeg_samplingfactor_result.png", framebuffer ); + + return 0; +} From ef94275eb67bbf662f2d2597f1d513b5b772756b Mon Sep 17 00:00:00 2001 From: Zihao Mu Date: Wed, 22 Jun 2022 21:08:48 +0800 Subject: [PATCH 5/7] bug fixed of GEMM node in ONNX_importer --- modules/dnn/src/onnx/onnx_importer.cpp | 8 ++++---- modules/dnn/test/test_onnx_importer.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/dnn/src/onnx/onnx_importer.cpp b/modules/dnn/src/onnx/onnx_importer.cpp index e4cbe02840..7a0532fcf4 100644 --- a/modules/dnn/src/onnx/onnx_importer.cpp +++ b/modules/dnn/src/onnx/onnx_importer.cpp @@ -1759,15 +1759,15 @@ void ONNXImporter::parseBatchNormalization(LayerParams& layerParams, const openc addLayer(layerParams, node_proto); } +// A * B + C = Y, we require that the dimension of A is [m, k], and the dimension of B is [n, k]. +// And the dim of output Y is [m, n] void ONNXImporter::parseGemm(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) { CV_Assert(node_proto.input_size() >= 2); layerParams.type = "InnerProduct"; Mat weights = getBlob(node_proto, 1); - int ind_num_out = 0; - if (layerParams.has("transB") && !layerParams.get("transB")) { + if (!layerParams.get("transB", 0)) { transpose(weights, weights); - ind_num_out = 1; } layerParams.blobs.push_back(weights); @@ -1789,7 +1789,7 @@ void ONNXImporter::parseGemm(LayerParams& layerParams, const opencv_onnx::NodePr addLayer(constParams, proto); } - layerParams.set("num_output", layerParams.blobs[0].size[ind_num_out]); + layerParams.set("num_output", layerParams.blobs[0].size[0]); layerParams.set("bias_term", node_proto.input_size() == 3); addLayer(layerParams, node_proto); } diff --git a/modules/dnn/test/test_onnx_importer.cpp b/modules/dnn/test/test_onnx_importer.cpp index 60473ede58..56203cba56 100644 --- a/modules/dnn/test/test_onnx_importer.cpp +++ b/modules/dnn/test/test_onnx_importer.cpp @@ -1389,6 +1389,12 @@ TEST_P(Test_ONNX_layers, DivConst) testONNXModels("div_const"); } +TEST_P(Test_ONNX_layers, Gemm) +{ + testONNXModels("gemm_no_transB"); + testONNXModels("gemm_transB_0"); +} + TEST_P(Test_ONNX_layers, OutputRegistration) { testONNXModels("output_registration", npy, 0, 0, false, true, 2); From 9faefa0c96960dee08e13d50ee1257797861058c Mon Sep 17 00:00:00 2001 From: lamm45 <96844552+lamm45@users.noreply.github.com> Date: Fri, 24 Jun 2022 13:49:40 -0400 Subject: [PATCH 6/7] Fix minor errors in the first documentation page (Introduction) This markdown file corresponds to the first link on the landing page of OpenCV documentation. --- modules/core/doc/intro.markdown | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/core/doc/intro.markdown b/modules/core/doc/intro.markdown index 901c11d706..c78ccbfbb1 100644 --- a/modules/core/doc/intro.markdown +++ b/modules/core/doc/intro.markdown @@ -71,7 +71,7 @@ data sharing. A destructor decrements the reference counter associated with the The buffer is deallocated if and only if the reference counter reaches zero, that is, when no other structures refer to the same buffer. Similarly, when a Mat instance is copied, no actual data is really copied. Instead, the reference counter is incremented to memorize that there is another owner -of the same data. There is also the Mat::clone method that creates a full copy of the matrix data. +of the same data. There is also the cv::Mat::clone method that creates a full copy of the matrix data. See the example below: ```.cpp // create a big 8Mb matrix @@ -159,11 +159,11 @@ grayscale conversion. Note that frame and edges are allocated only once during t of the loop body since all the next video frames have the same resolution. If you somehow change the video resolution, the arrays are automatically reallocated. -The key component of this technology is the Mat::create method. It takes the desired array size and -type. If the array already has the specified size and type, the method does nothing. Otherwise, it -releases the previously allocated data, if any (this part involves decrementing the reference +The key component of this technology is the cv::Mat::create method. It takes the desired array size +and type. If the array already has the specified size and type, the method does nothing. Otherwise, +it releases the previously allocated data, if any (this part involves decrementing the reference counter and comparing it with zero), and then allocates a new buffer of the required size. Most -functions call the Mat::create method for each output array, and so the automatic output data +functions call the cv::Mat::create method for each output array, and so the automatic output data allocation is implemented. Some notable exceptions from this scheme are cv::mixChannels, cv::RNG::fill, and a few other @@ -247,9 +247,9 @@ Examples: // matrix (10-element complex vector) Mat img(Size(1920, 1080), CV_8UC3); // make a 3-channel (color) image // of 1920 columns and 1080 rows. - Mat grayscale(image.size(), CV_MAKETYPE(image.depth(), 1)); // make a 1-channel image of - // the same size and same - // channel type as img + Mat grayscale(img.size(), CV_MAKETYPE(img.depth(), 1)); // make a 1-channel image of + // the same size and same + // channel type as img ``` Arrays with more complex elements cannot be constructed or processed using OpenCV. Furthermore, each function or method can handle only a subset of all possible array types. Usually, the more complex @@ -269,14 +269,14 @@ extended in future based on user requests. ### InputArray and OutputArray Many OpenCV functions process dense 2-dimensional or multi-dimensional numerical arrays. Usually, -such functions take cppMat as parameters, but in some cases it's more convenient to use +such functions take `cv::Mat` as parameters, but in some cases it's more convenient to use `std::vector<>` (for a point set, for example) or `cv::Matx<>` (for 3x3 homography matrix and such). To avoid many duplicates in the API, special "proxy" classes have been introduced. The base "proxy" class is cv::InputArray. It is used for passing read-only arrays on a function input. The derived from InputArray class cv::OutputArray is used to specify an output array for a function. Normally, you should not care of those intermediate types (and you should not declare variables of those types explicitly) - it will all just work automatically. You can assume that instead of -InputArray/OutputArray you can always use `Mat`, `std::vector<>`, `cv::Matx<>`, `cv::Vec<>` or `cv::Scalar`. When a +InputArray/OutputArray you can always use `cv::Mat`, `std::vector<>`, `cv::Matx<>`, `cv::Vec<>` or `cv::Scalar`. When a function has an optional input or output array, and you do not have or do not want one, pass cv::noArray(). @@ -288,7 +288,7 @@ the optimization algorithm did not converge), it returns a special error code (t boolean variable). The exceptions can be instances of the cv::Exception class or its derivatives. In its turn, -cv::Exception is a derivative of std::exception. So it can be gracefully handled in the code using +cv::Exception is a derivative of `std::exception`. So it can be gracefully handled in the code using other standard C++ library components. The exception is typically thrown either using the `#CV_Error(errcode, description)` macro, or its @@ -297,7 +297,7 @@ printf-like `#CV_Error_(errcode, (printf-spec, printf-args))` variant, or using satisfied. For performance-critical code, there is #CV_DbgAssert(condition) that is only retained in the Debug configuration. Due to the automatic memory management, all the intermediate buffers are automatically deallocated in case of a sudden error. You only need to add a try statement to catch -exceptions, if needed: : +exceptions, if needed: ```.cpp try { From 2366f2cb2ec8266e660a397968db832b839981dd Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 25 Jun 2022 15:12:59 +0200 Subject: [PATCH 7/7] issues-22126 --- modules/videoio/src/cap_ffmpeg_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp index a724d7f724..442eb7e4b8 100644 --- a/modules/videoio/src/cap_ffmpeg_impl.hpp +++ b/modules/videoio/src/cap_ffmpeg_impl.hpp @@ -1408,7 +1408,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* img_convert_ctx, picture->data, picture->linesize, - 0, video_st->codec->coded_height, + 0, picture->height, rgb_picture.data, rgb_picture.linesize );