OpenCV相机标定与3D重建(37)计算两幅图像之间单应性矩阵(Homography Matrix)的函数findHomography()的使用

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

算法描述

找到两个平面之间的透视变换。

cv::findHomography 是 OpenCV 库中用于计算两幅图像之间单应性矩阵(Homography Matrix)的函数。单应性矩阵描述了两个平面之间的投影变换关系,它在计算机视觉中用于图像校正、拼接和增强现实等任务。

函数原型

cpp 复制代码
Mat cv::findHomography	
(
	InputArray 	srcPoints,
	InputArray 	dstPoints,
	int 	method = 0,
	double 	ransacReprojThreshold = 3,
	OutputArray 	mask = noArray(),
	const int 	maxIters = 2000,
	const double 	confidence = 0.995 
)		

参数

  • 参数srcPoints:原平面中点的坐标,可以是类型为 CV_32FC2 的矩阵或 vector。
  • 参数dstPoints:目标平面中点的坐标,可以是类型为 CV_32FC2 的矩阵或 vector。
  • 参数method:用于计算单应性矩阵的方法。可能的方法包括:
    • 0:常规方法,使用所有点,即最小二乘法。
    • RANSAC:基于RANSAC的稳健方法。
    • LMEDS:最小中值(Least-Median)稳健方法。
    • RHO:基于PROSAC的稳健方法。
  • ransacReprojThreshold:仅用于 RANSAC 和 RHO 方法。这是允许的最大重投影误差,用于将一对点视为内点。也就是说,如果
    ∥ dstPoints i − convertPointsHomogeneous ( H ⋅ srcPoints i ) ∥ 2 > ransacReprojThreshold \| \texttt{dstPoints} _i - \texttt{convertPointsHomogeneous} ( \texttt{H} \cdot \texttt{srcPoints} _i) \|_2 > \texttt{ransacReprojThreshold} ∥dstPointsi−convertPointsHomogeneous(H⋅srcPointsi)∥2>ransacReprojThreshold
    则认为点 i 是离群点。如果 srcPoints 和 dstPoints 以像素为单位测量,则通常将此参数设置在1到10之间是有意义的。
  • 参数mask:由稳健方法(如 RANSAC 或 LMEDS)设置的可选输出掩码。注意输入掩码值被忽略。
  • 参数maxIters:RANSAC的最大迭代次数。
  • 参数confidence:置信水平,介于0和1之间。

该函数找到并返回源平面和目标平面之间的透视变换矩阵 H H H

s i [ x i ′ y i ′ 1 ] ∼ H [ x i y i 1 ] s_i \begin{bmatrix} x'_i \\ y'_i \\ 1 \end{bmatrix} \sim H \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix} si xi′yi′1 ∼H xiyi1

从而最小化反投影误差:
∑ i ( x i ′ − ( h 11 x i + h 12 y i + h 13 ) h 31 x i + h 32 y i + h 33 ) 2 + ( y i ′ − ( h 21 x i + h 22 y i + h 23 ) h 31 x i + h 32 y i + h 33 ) 2 \sum_i \left( \frac{x'i - (h{11}x_i + h_{12}y_i + h_{13})}{h_{31}x_i + h_{32}y_i + h_{33}} \right)^2 + \left( \frac{y'i - (h{21}x_i + h_{22}y_i + h_{23})}{h_{31}x_i + h_{32}y_i + h_{33}} \right)^2 i∑(h31xi+h32yi+h33xi′−(h11xi+h12yi+h13))2+(h31xi+h32yi+h33yi′−(h21xi+h22yi+h23))2

如果 method 参数设置为默认值 0,则函数使用所有点对通过简单的最小二乘方案计算初始单应性估计。

然而,如果并非所有的点对(srcPoints_i, dstPoints_i)都符合刚性的透视变换(即存在一些离群点),这个初始估计将会较差。在这种情况下,你可以使用三种稳健方法之一。RANSAC、LMEDS 和 RHO 方法尝试许多不同的随机子集(每次四个点对,共线点对被丢弃),使用这个子集和简单的最小二乘算法估计单应性矩阵,然后计算所估计单应性的质量/优度(对于RANSAC来说是内点的数量,对于LMEDS来说是最小中值重投影误差)。最佳子集随后用于生成单应性矩阵的初始估计和内点/离群点的掩码。

无论是否使用稳健方法,计算出的单应性矩阵都会进一步优化(在稳健方法的情况下仅使用内点),以Levenberg-Marquardt方法减少重投影误差。

RANSAC 和 RHO 方法可以处理几乎任何比例的离群点,但需要一个阈值来区分内点和离群点。LMEDS 方法不需要任何阈值,但只有当内点超过50%时才能正确工作。最后,如果没有离群点且噪声较小,使用默认方法(method=0)。

该函数用于找到初始的内部和外部矩阵。单应性矩阵确定至一个尺度。因此,它被标准化以使 h 33 = 1 h_{33}=1 h33=1。需要注意的是,每当无法估计 H 矩阵时,将返回一个空矩阵。

代码示例

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

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    // 创建虚拟的匹配点数据(假设我们有4对匹配点)
    vector< Point2f > srcPoints = { Point2f( 56.0f, 65.0f ), Point2f( 368.0f, 52.0f ), Point2f( 28.0f, 387.0f ), Point2f( 389.0f, 390.0f ) };

    vector< Point2f > dstPoints = { Point2f( 0.0f, 0.0f ), Point2f( 300.0f, 0.0f ), Point2f( 0.0f, 300.0f ), Point2f( 300.0f, 300.0f ) };

    // 定义输出的单应性矩阵和掩码
    Mat homographyMatrix, mask;

    // 使用 RANSAC 方法计算单应性矩阵
    homographyMatrix = findHomography( srcPoints, dstPoints,
                                       RANSAC,   // 使用RANSAC方法
                                       3.0,      // 点到投影模型的最大重投影误差
                                       mask,     // 输出掩码
                                       2000,     // 最大迭代次数
                                       0.995 );  // 置信水平

    // 打印结果
    cout << "Homography Matrix:\n" << homographyMatrix << endl;

    // 打印哪些点被认为是内点
    cout << "Inliers mask:\n";
    for ( size_t i = 0; i < mask.total(); ++i )
    {
        if ( mask.at< uchar >( i ) )
        {
            cout << "Point " << i + 1 << " is an inlier." << endl;
        }
        else
        {
            cout << "Point " << i + 1 << " is an outlier." << endl;
        }
    }

    return 0;
}

运行结果

bash 复制代码
Homography Matrix:
[1.055873761296419, 0.09181510967794945, -65.09691276166618;
 0.04690100493754324, 1.125624118501043, -75.79202397907012;
 0.0001832514481695185, 0.0005133370013304123, 0.9999999999999999]
Inliers mask:
Point 1 is an inlier.
Point 2 is an inlier.
Point 3 is an inlier.
Point 4 is an inlier.
相关推荐
kkkkkkkkkkaZZL3 小时前
图片拼接|横向拼接|竖向拼接|正方形拼接|其他模式拼接 python
python·opencv·计算机视觉
知识在于积累3 小时前
Matplotlib中隐藏坐标轴但保留坐标轴标签的3D图
3d·matplotlib·隐藏坐标轴·显式坐标标签
有Li3 小时前
AutoFOX:一种冠状动脉X线造影与OCT的自动化跨模态3D融合框架|文献速递-视觉大模型医疗图像应用
运维·3d·自动化
小成晓程4 小时前
PyQt6+OpenCV 项目练习
人工智能·opencv·计算机视觉
小码贾5 小时前
OpenCV-Python实战(11)——边缘检测
人工智能·opencv·计算机视觉
没学上了8 小时前
加强版十六章视频读写
opencv·计算机视觉
云飞云共享云桌面12 小时前
如何让企业研发设计团队低配电脑流畅做3D大装配设计?
服务器·3d·电脑
winfredzhang15 小时前
meshy的文本到3d的使用
3d·动画·贴图·obj·重拓扑·文生模型
是十一月末17 小时前
opencv实现KNN算法识别图片数字
人工智能·python·opencv·算法·k-近邻算法