OpenCV相机标定与3D重建(26)计算两个二维点集之间的部分仿射变换矩阵(2x3)函数 estimateAffinePartial2D()的使用

  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

计算两个2D点集之间的具有4个自由度的最优有限仿射变换。

cv::estimateAffinePartial2D 是 OpenCV 库中的一个函数,用于计算两个二维点集之间的部分仿射变换矩阵(2x3)。与完整的仿射变换不同,部分仿射变换仅估计旋转、平移和均匀缩放,而不包括剪切变形。这使得它适用于保持平行线和平行性的情况,例如处理相机的平移和旋转运动。

函数原型

cpp 复制代码
cv::Mat cv::estimateAffinePartial2D	
(
	InputArray 	from,
	InputArray 	to,
	OutputArray 	inliers = noArray(),
	int 	method = RANSAC,
	double 	ransacReprojThreshold = 3,
	size_t 	maxIters = 2000,
	double 	confidence = 0.99,
	size_t 	refineIters = 10 
)		

参数

  • 参数from 第一个输入的2D点集。
  • 参数to 第二个输入的2D点集。
  • 参数inliers 输出向量,指示哪些点是内点(1-内点,0-外点)。
  • 参数method 用于计算变换的鲁棒方法。可能的方法包括:
    • RANSAC - 基于RANSAC的鲁棒方法
    • LMEDS - 最小中位数鲁棒方法
    • 默认方法为 RANSAC。
  • 参数ransacReprojThreshold 在RANSAC算法中,考虑一个点为内点的最大重投影误差。仅适用于RANSAC。
  • 参数maxIters 鲁棒方法的最大迭代次数。
  • 参数confidence 对估计变换的置信水平,在0和1之间。通常0.95到0.99之间的值就足够了。过于接近1的值可能会显著减慢估计过程。低于0.8-0.9的值可能导致变换估计不准确。
  • 参数refineIters 精化算法(Levenberg-Marquardt)的最大迭代次数。传递0将禁用精化,因此输出矩阵将是鲁棒方法的输出。

返回值

输出 2D 仿射变换(4个自由度)矩阵 2×3,如果无法估计变换则返回空矩阵。

该函数估计一个具有4个自由度的最优2D仿射变换,限于平移、旋转和均匀缩放的组合。使用选定的鲁棒算法进行估计。

计算出的变换随后会进一步通过Levenberg-Marquardt方法进行精化(仅使用内点),以进一步减少重投影误差。

估计的变换矩阵为:

[ cos ⁡ ( θ ) ⋅ s − sin ⁡ ( θ ) ⋅ s t x sin ⁡ ( θ ) ⋅ s cos ⁡ ( θ ) ⋅ s t y ] \begin{bmatrix} \cos(\theta) \cdot s & -\sin(\theta) \cdot s & t_x \\ \sin(\theta) \cdot s & \cos(\theta) \cdot s & t_y \end{bmatrix} [cos(θ)⋅ssin(θ)⋅s−sin(θ)⋅scos(θ)⋅stxty]

其中 θ 是旋转角度,s 是缩放因子,tx 和 ty 分别是 x 轴和 y 轴上的平移量。

注释

RANSAC 方法实际上可以处理任意比例的外点,但需要一个阈值来区分内点和外点。LMeDS 方法不需要任何阈值,但它只有在内点超过50%的情况下才能正确工作。

代码示例

cpp 复制代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>

using namespace cv;
using namespace std;

int main()
{
    // 定义两组对应的2D点 (x, y) - 源点集和目标点集
    vector< Point2f > from = { Point2f( 0, 0 ), Point2f( 1, 0 ), Point2f( 0, 1 ), Point2f( 1, 1 ) };
    vector< Point2f > to   = { Point2f( 2, 2 ), Point2f( 3, 2 ), Point2f( 2, 3 ), Point2f( 3, 3 ) };

    // 定义一个 Mat 来接收输出的部分仿射变换矩阵
    Mat affinePartialMatrix;

    // 定义一个 Mat 来接收内点信息
    vector< uchar > inliers;

    // 调用 estimateAffinePartial2D 函数
    affinePartialMatrix = estimateAffinePartial2D( from, to, inliers );

    if ( !affinePartialMatrix.empty() )
    {
        cout << "Estimated Partial Affine Matrix:\n" << affinePartialMatrix << endl;

        // 打印哪些点被认为是内点
        for ( size_t i = 0; i < inliers.size(); ++i )
        {
            if ( inliers[ i ] )
            {
                cout << "Point pair (" << from[ i ] << ", " << to[ i ] << ") is an inlier.\n";
            }
            else
            {
                cout << "Point pair (" << from[ i ] << ", " << to[ i ] << ") is an outlier.\n";
            }
        }
    }
    else
    {
        cout << "Failed to estimate partial affine transformation." << endl;
    }

    return 0;
}

运行结果

bash 复制代码
Estimated Partial Affine Matrix:
[1, -0, 2;
 0, 1, 2]
Point pair ([0, 0], [2, 2]) is an inlier.
Point pair ([1, 0], [3, 2]) is an inlier.
Point pair ([0, 1], [2, 3]) is an inlier.
Point pair ([1, 1], [3, 3]) is an inlier.
相关推荐
西猫雷婶4 小时前
python学opencv|读取图像(二十一)使用cv2.circle()绘制圆形进阶
开发语言·python·opencv
supermapsupport4 小时前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
湫ccc5 小时前
《Opencv》基础操作详解(3)
人工智能·opencv·计算机视觉
火星机器人life5 小时前
基于ceres优化的3d激光雷达开源算法
算法·3d
yinqinggong7 小时前
从源码编译支持FFmpeg的OpenCV
opencv·ffmpeg
864记忆9 小时前
关于opencv、Qt、msvc编译器之间的关系
人工智能·qt·opencv
aworkholic9 小时前
opencv sdk for java中提示无stiching模块接口的问题
java·c++·opencv·jni·opencv4android·stiching
pk_xz1234569 小时前
OpenCV实现实时人脸检测和识别
人工智能·opencv·计算机视觉
是十一月末10 小时前
Opencv实现图片和视频的加噪、平滑处理
人工智能·python·opencv·计算机视觉·音视频