1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge pull request #29077 from vrabaud:throw

Homogeneize some calib/3d behavior #29077

- use CV_Check to validate input sizes (thus throwing for invalid inputs)
- return bool to validate a function result

This fixes #22746

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Vincent Rabaud
2026-06-02 07:25:44 +02:00
committed by GitHub
parent 89e0ca8749
commit 1d4d81103e
6 changed files with 71 additions and 38 deletions
@@ -1885,12 +1885,14 @@ an inlier.
between 0.95 and 0.99 is usually good enough. Values too close to 1 can slow down the estimation
significantly. Values lower than 0.8-0.9 can result in an incorrectly estimated transformation.
@return Whether a solution was found.
The function estimates an optimal 3D affine transformation between two 3D point sets using the
RANSAC algorithm.
*/
CV_EXPORTS_W int estimateAffine3D(InputArray src, InputArray dst,
OutputArray out, OutputArray inliers,
double ransacThreshold = 3, double confidence = 0.99);
CV_EXPORTS_W bool estimateAffine3D(InputArray src, InputArray dst,
OutputArray out, OutputArray inliers,
double ransacThreshold = 3, double confidence = 0.99);
/** @brief Computes an optimal affine transformation between two 3D point sets.
@@ -1959,12 +1961,14 @@ CV_EXPORTS_W cv::Mat estimateAffine3D(InputArray src, InputArray dst,
* between 0.95 and 0.99 is usually good enough. Values too close to 1 can slow down the estimation
* significantly. Values lower than 0.8-0.9 can result in an incorrectly estimated transformation.
*
* @return Whether a translation was found.
*
* The function estimates an optimal 3D translation between two 3D point sets using the
* RANSAC algorithm.
* */
CV_EXPORTS_W int estimateTranslation3D(InputArray src, InputArray dst,
OutputArray out, OutputArray inliers,
double ransacThreshold = 3, double confidence = 0.99);
CV_EXPORTS_W bool estimateTranslation3D(InputArray src, InputArray dst,
OutputArray out, OutputArray inliers,
double ransacThreshold = 3, double confidence = 0.99);
/** @brief Computes an optimal affine transformation between two 2D point sets.
+1 -4
View File
@@ -320,13 +320,10 @@ Mat findHomography( InputArray _points1, InputArray _points2,
npoints = p.checkVector(3, -1, false);
if( npoints < 0 )
CV_Error(Error::StsBadArg, "The input arrays should be 2D or 3D point sets");
if( npoints == 0 )
return Mat();
convertPointsFromHomogeneous(p, p);
}
// Need at least 4 point correspondences to calculate Homography
if( npoints < 4 )
CV_Error(Error::StsVecLengthErr , "The input arrays should have at least 4 corresponding point sets to calculate Homography");
CV_CheckGE(npoints, 4, "The input arrays should have at least 4 corresponding point sets to calculate Homography");
p.reshape(2, npoints).convertTo(m, CV_32F);
}
+24 -13
View File
@@ -829,16 +829,18 @@ public:
}
};
int estimateAffine3D(InputArray _from, InputArray _to,
OutputArray _out, OutputArray _inliers,
double ransacThreshold, double confidence)
bool estimateAffine3D(InputArray _from, InputArray _to,
OutputArray _out, OutputArray _inliers,
double ransacThreshold, double confidence)
{
CV_INSTRUMENT_REGION();
Mat from = _from.getMat(), to = _to.getMat();
int count = from.checkVector(3);
CV_Assert( count >= 0 && to.checkVector(3) == count );
CV_CheckGE( count, 0, "Points need to be 3d");
CV_CheckGE( count, 3, "At least 3 points are needed for affine transformation estimation.");
CV_CheckEQ(to.checkVector(3), count, "Point matches need to have the same size");
Mat dFrom, dTo;
from.convertTo(dFrom, CV_32F);
@@ -857,11 +859,13 @@ Mat estimateAffine3D(InputArray _from, InputArray _to,
CV_OUT double* _scale, bool force_rotation)
{
CV_INSTRUMENT_REGION();
Mat from = _from.getMat(), to = _to.getMat();
int count = from.checkVector(3);
CV_CheckGE(count, 3, "Umeyama algorithm needs at least 3 points for affine transformation estimation.");
CV_CheckEQ(to.checkVector(3), count, "Point sets need to have the same size");
CV_CheckGE(count, 3, "At least 3 points are needed for affine transformation estimation.");
CV_CheckEQ(to.checkVector(3), count, "Point matches need to have the same size");
from = from.reshape(1, count);
to = to.reshape(1, count);
if(from.type() != CV_64F)
@@ -933,16 +937,17 @@ Mat estimateAffine3D(InputArray _from, InputArray _to,
return transform;
}
int estimateTranslation3D(InputArray _from, InputArray _to,
OutputArray _out, OutputArray _inliers,
double ransacThreshold, double confidence)
bool estimateTranslation3D(InputArray _from, InputArray _to,
OutputArray _out, OutputArray _inliers,
double ransacThreshold, double confidence)
{
CV_INSTRUMENT_REGION();
Mat from = _from.getMat(), to = _to.getMat();
int count = from.checkVector(3);
CV_Assert( count >= 0 && to.checkVector(3) == count );
CV_CheckGE(count, 0, "Points need to be 3d");
CV_CheckEQ(to.checkVector(3), count, "Point matches need to have the same size");
Mat dFrom, dTo;
from.convertTo(dFrom, CV_32F);
@@ -972,7 +977,9 @@ Mat estimateAffine2D(InputArray _from, InputArray _to, OutputArray _inliers,
bool result = false;
Mat H;
CV_Assert( count >= 0 && to.checkVector(2) == count );
CV_CheckGE(count, 0, "Points need to be 2d");
CV_CheckGE(count, 2, "At least 2 points for partial affine transformation estimation.");
CV_CheckEQ(to.checkVector(2), count, "Point matches need to have the same size");
if (from.type() != CV_32FC2 || to.type() != CV_32FC2)
{
@@ -1108,7 +1115,9 @@ Mat estimateAffinePartial2D(InputArray _from, InputArray _to, OutputArray _inlie
bool result = false;
Mat H;
CV_Assert( count >= 0 && to.checkVector(2) == count );
CV_CheckGE(count, 0, "Points need to be 2d");
CV_CheckGE(count, 2, "At least 2 points for partial affine transformation estimation.");
CV_CheckEQ(to.checkVector(2), count, "Point matches need to have the same size");
if (from.type() != CV_32FC2 || to.type() != CV_32FC2)
{
@@ -1253,7 +1262,9 @@ Vec2d estimateTranslation2D(InputArray _from, InputArray _to,
Mat from = _from.getMat(), to = _to.getMat();
int count = from.checkVector(2);
bool result = false;
CV_Assert(count >= 0 && to.checkVector(2) == count);
CV_CheckGE(count, 0, "Points need to be 2d");
CV_CheckEQ(to.checkVector(2), count, "Point matches need to have the same size");
if (from.type() != CV_32FC2 || to.type() != CV_32FC2) {
Mat tmp1, tmp2;
@@ -50,6 +50,13 @@ static float rngIn(float from, float to) { return from + (to-from) * (float)theR
TEST_P(EstimateAffine2D, test3Points)
{
const int method = GetParam();
for (size_t i = 0; i < 2; ++i)
{
std::vector<cv::Vec2f> fpts(i), tpts(i);
vector<uchar> inliers;
EXPECT_THROW(estimateAffine2D(fpts, tpts, inliers, method), cv::Exception);
}
// try more transformations
for (size_t i = 0; i < 500; ++i)
{
@@ -67,7 +74,7 @@ TEST_P(EstimateAffine2D, test3Points)
transform(fpts, tpts, aff);
vector<uchar> inliers;
Mat aff_est = estimateAffine2D(fpts, tpts, inliers, GetParam() /* method */);
Mat aff_est = estimateAffine2D(fpts, tpts, inliers, method);
EXPECT_NEAR(0., cvtest::norm(aff_est, aff, NORM_INF), 1e-3);
@@ -62,6 +62,13 @@ static Mat rngPartialAffMat() {
TEST_P(EstimateAffinePartial2D, test2Points)
{
const int method = GetParam();
for (size_t i = 0; i < 2; ++i)
{
std::vector<cv::Vec2f> fpts(i), tpts(i);
vector<uchar> inliers;
EXPECT_THROW(estimateAffinePartial2D(fpts, tpts, inliers, method), cv::Exception);
}
// try more transformations
for (size_t i = 0; i < 500; ++i)
{
@@ -77,7 +84,7 @@ TEST_P(EstimateAffinePartial2D, test2Points)
transform(fpts, tpts, aff);
vector<uchar> inliers;
Mat aff_est = estimateAffinePartial2D(fpts, tpts, inliers, GetParam() /* method */);
Mat aff_est = estimateAffinePartial2D(fpts, tpts, inliers, method);
EXPECT_NEAR(0., cvtest::norm(aff_est, aff, NORM_INF), 1e-3);
+20 -13
View File
@@ -354,14 +354,16 @@ No image processing is done to improve to find the checkerboard. This has the ef
execution of the function but could lead to not recognizing the checkerboard if the image
is not previously binarized in the appropriate manner.
@return True if all of the corners are found and placed in a certain order (row by row,
left to right in every row). Otherwise, if the function fails to find all the corners or reorder them,
it returns false.
The function attempts to determine whether the input image is a view of the chessboard pattern and
locate the internal chessboard corners. The function returns a non-zero value if all of the corners
are found and they are placed in a certain order (row by row, left to right in every row).
Otherwise, if the function fails to find all the corners or reorder them, it returns 0. For example,
a regular chessboard has 8 x 8 squares and 7 x 7 internal corners, that is, points where the black
squares touch each other. The detected coordinates are approximate, and to determine their positions
more accurately, the function calls #cornerSubPix. You also may use the function #cornerSubPix with
different parameters if returned coordinates are not accurate enough.
locate the internal chessboard corners. For example, a regular chessboard has 8 x 8 squares and
7 x 7 internal corners, that is, points where the black squares touch each other. The detected
coordinates are approximate, and to determine their positions more accurately, the function
calls #cornerSubPix. You also may use the function #cornerSubPix with different parameters if
returned coordinates are not accurate enough.
Sample usage of detecting and drawing chessboard corners: :
@code
@@ -392,9 +394,12 @@ to create the desired checkerboard pattern.
CV_EXPORTS_W bool findChessboardCorners( InputArray image, Size patternSize, OutputArray corners,
int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE );
/*
Checks whether the image contains chessboard of the specific size or not.
If yes, nonzero value is returned.
/** @brief Checks whether the image contains chessboard of the specific size or not.
@param img Source chessboard view.
@param size Size of the chessboard.
@return Whether a chessboard was found.
*/
CV_EXPORTS_W bool checkChessboard(InputArray img, Size size);
@@ -552,10 +557,12 @@ perspective distortions but much more sensitive to background clutter.
If `blobDetector` is NULL then `image` represents Point2f array of candidates.
@param parameters struct for finding circles in a grid pattern.
return True if all of the centers have been found and they have been placed in a certain order
(row by row, left to right in every row). Otherwise, if the function fails to find all the corners
or reorder them, it returns false.
The function attempts to determine whether the input image contains a grid of circles. If it is, the
function locates centers of the circles. The function returns a non-zero value if all of the centers
have been found and they have been placed in a certain order (row by row, left to right in every
row). Otherwise, if the function fails to find all the corners or reorder them, it returns 0.
function locates centers of the circles.
Sample usage of detecting and drawing the centers of circles: :
@code