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

Merge pull request #27950 from ismailabouzeidx:feat/estimate-translation2d

[calib3d] Add estimateTranslation2D() #27950

Merge with opencv_extra PR: opencv/opencv_extra#1286

### **Description**

This PR adds a new API, `cv::estimateTranslation2D()`, to the **calib3d** module.  
It computes a **pure 2D translation** between two sets of corresponding points using robust methods (`RANSAC` and `LMedS`).  
The function mirrors the interface and behavior of `estimateAffine2D()` and `estimateAffinePartial2D()`, but constrains the transformation to translation only.

This model is particularly useful for cases where the motion between images is purely translational, such as:
- Aerial stitching and planar mosaics.  
- Image alignment in fixed-camera systems.  
- Lightweight pipelines where affine or homography models are unnecessarily complex.

The implementation introduces a new internal class `Translation2DEstimatorCallback` and integrates seamlessly into OpenCV’s existing robust estimation framework (`PointSetRegistrator`).

---

### **Key Features**
- Implements `cv::estimateTranslation2D()` in the `calib3d` module.
- Supports robust methods **RANSAC** and **LMedS**.  
- Adds accuracy and performance tests.  
- Provides full **C++ and Python bindings**.  
- Includes **Doxygen documentation** consistent with OpenCV’s standards.  
- Verified correctness across noise, outlier, and datatype variations.

---
### **Testing & Verification**

**Unit Tests** (`modules/calib3d/`)

- **Minimal sample:**  
  `test1Point` validates that a single correspondence recovers the correct translation under both **RANSAC** and **LMedS** across 500 randomized trials.  
- **Robustness to noise and outliers:**  
  `testNPoints` generates 100 correspondences, injects noise and outliers (≤40% for RANSAC, ≤50% for LMedS), and verifies that:  
  - Estimated **T** closely matches ground truth (`cvtest::norm(..., NORM_L2)`).  
  - Inlier mask consistency and correctness are maintained.  
- **Datatype conversion:**  
  `testConversion` checks mixed input datatypes (integer → float) to ensure correct conversion and consistent results.  
- **Input immutability:**  
  `dont_change_inputs` confirms that input arrays remain unchanged after function execution, mirroring affine behavior.

**Performance Tests** (`modules/calib3d/`)

- `EstimateTranslation2DPerf` benchmarks **RANSAC** and **LMedS** using:  
  - Point counts: 1000  
  - Confidence levels: 0.95  
  - Refinement iterations: 10, 0  
  
These tests confirm **numerical stability**, **performance scaling**, and **consistency** across datatypes and noise levels.

---
### 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 (`4.x`)
- [x] There is a clear description, motivation, and validation summary in this PR
- [x] There are accuracy and performance tests in the calib3d module
- [x] The feature is well documented and sample code can be built with CMake
- [x] The feature has Python bindings and verified documentation output
- [x] There is test data or sample code in the opencv_extra repository (if applicable)
- [ ] There is a reference to the original bug report or related issue (if applicable)
This commit is contained in:
Ismail Abou Zeid
2025-11-08 16:27:54 +02:00
committed by GitHub
parent 9921531fa4
commit 5fb4ce482c
4 changed files with 640 additions and 0 deletions
@@ -3362,6 +3362,78 @@ CV_EXPORTS_W cv::Mat estimateAffinePartial2D(InputArray from, InputArray to, Out
size_t maxIters = 2000, double confidence = 0.99,
size_t refineIters = 10);
/** @brief Computes a pure 2D translation between two 2D point sets.
It computes
\f[
\begin{bmatrix}
x\\
y
\end{bmatrix}
=
\begin{bmatrix}
1 & 0\\
0 & 1
\end{bmatrix}
\begin{bmatrix}
X\\
Y
\end{bmatrix}
+
\begin{bmatrix}
t_x\\
t_y
\end{bmatrix}.
\f]
@param from First input 2D point set containing \f$(X,Y)\f$.
@param to Second input 2D point set containing \f$(x,y)\f$.
@param inliers Output vector indicating which points are inliers (1-inlier, 0-outlier).
@param method Robust method used to compute the transformation. The following methods are possible:
- @ref RANSAC - RANSAC-based robust method
- @ref LMEDS - Least-Median robust method
RANSAC is the default method.
@param ransacReprojThreshold Maximum reprojection error in the RANSAC algorithm to consider
a point as an inlier. Applies only to RANSAC.
@param maxIters The maximum number of robust method iterations.
@param confidence Confidence level, between 0 and 1, for the estimated transformation. Anything
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.80.9 can result in an incorrectly estimated transformation.
@param refineIters Maximum number of iterations of the refining algorithm. For pure translation
the least-squares solution on inliers is closed-form, so passing 0 is recommended (no additional refine).
@return A 2D translation vector \f$[t_x, t_y]^T\f$ as `cv::Vec2d`. If the translation could not be
estimated, both components are set to NaN and, if @p inliers is provided, the mask is filled with zeros.
\par Converting to a 2x3 transformation matrix:
\f[
\begin{bmatrix}
1 & 0 & t_x\\
0 & 1 & t_y
\end{bmatrix}
\f]
@code{.cpp}
cv::Vec2d t = cv::estimateTranslation2D(from, to, inliers);
cv::Mat T = (cv::Mat_<double>(2,3) << 1,0,t[0], 0,1,t[1]);
@endcode
The function estimates a pure 2D translation between two 2D point sets using the selected robust
algorithm. Inliers are determined by the reprojection error threshold.
@note
The RANSAC method can handle practically any ratio of outliers but needs a threshold to
distinguish inliers from outliers. The method LMeDS does not need any threshold but works
correctly only when there are more than 50% inliers.
@sa estimateAffine2D, estimateAffinePartial2D, getAffineTransform
*/
CV_EXPORTS_W cv::Vec2d estimateTranslation2D(InputArray from, InputArray to, OutputArray inliers = noArray(),
int method = RANSAC,
double ransacReprojThreshold = 3,
size_t maxIters = 2000, double confidence = 0.99,
size_t refineIters = 0);
/** @example samples/cpp/tutorial_code/features2D/Homography/decompose_homography.cpp
An example program with homography decomposition.