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.
相关推荐
翌日阳15 小时前
二十分之一的压缩比:Spatial Vivid 1.0 把 3DGS 全链路参考实现按 MIT 开源了
3d·开源
Dream-Y.ocean1 天前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
硕迪科技SOLIDWORKS2 天前
SOLIDWORKS Electrical 2027:从线束定义到2D–3D更改分析
3d·solidworks 202
DolitD2 天前
UE像素流与云渲染技术方案对比分析
3d·云原生·ue5·云计算·图形渲染
tealcwu2 天前
【Unity高级】Unity URP:构建同时支持 2D 与 3D 场景的项目完全指南
3d·unity·游戏引擎
Jmyd01232 天前
文物3D数字化的技术选型指南:从WW/T 0115标准到落地工程,一次讲透采集、建档、管理与展示
3d·系统架构·博物馆·数字展厅·博物馆数字化
Martina_03212 天前
AI生成3D模型一合并网格,材质就串色?用6步检查材质槽、UV与图集重映射
图像处理·人工智能·3d·材质·uv·游戏策划·1024程序员节
鹿野素材屋2 天前
U3D切换场景时候变黑怎么处理
数码相机·3d
FlightYe2 天前
视界原理之3D视频(四):裸眼、眼镜和头显
android·linux·c++·3d·ffmpeg·音视频
小豆庄3 天前
本地视频打码:多模型检测、帧间追踪与18种模糊的选型
opencv·目标检测·ai·自然语言处理·音视频·视频