2

OpenCV 中的 findHomography() 函数查找两个平面之间的透视变换。使用 Levenberg-Marquardt 方法进一步细化计算出的单应矩阵(仅在稳健方法的情况下使用内点),以进一步减少重投影误差。任何人都可以提供任何指向 Levenberg Marquardt 算法的 C/C++ 代码链接,这是最小化误差函数所需的,因为它将帮助我理解算法背后的数学。(网络上到处都只上传了库或特定代码,但没有上传算法的详细代码)。

4

2 回答 2

3

我知道这不是 C/C++,但 Matlab 文件交换中的文件可能有可以帮助您的源代码:

http://www.mathworks.com/matlabcentral/fileexchange/16063

如果您了解 C/C++,您可能对 Matlab 的理解不会有任何问题,特别是如果您正在查看源代码以加深理解。

于 2012-12-27T06:28:54.777 回答
3

openCV 代码是开放的,因此请检查模块。openCV的备忘单有 Levenberg Marquardt 公式,请参阅第 1 页第 3 列。您可以使用 grep 搜索该备忘单公式或仅搜索方法的名称:

grep -rnw . -e "Levenberg"

例如,您可以在 modules/legacy 文件夹中发现很多 levmar*.c 文件。使用 RANSAC 求解线性方程组后使用 LMA 的原因是因为前者的线性方程优化了错误的度量 - Homography 参数中的代数误差。更好的度量标准是点坐标的残差平方和。在这个指标中,解决方案是非线性的,必须迭代地找到。线性解用于初始化非线性算法并增加其收敛到全局最小值的机会。

然而,查看代码并不总是理解复杂概念的最简单方法。这是优化算法的“进化”系列,希望可以帮助您理解:

  1. 优化总是可以作为成本或残差的最小化
  2. 如果函数是凸的(碗形),它只有一个全局最小值,可以通过向下滑动找到。由于梯度向上,我们用减号表示:

    param[t+1]=param[t]-k*cost',其中 t-iteration, k-step 和 ' 代表梯度或导数 wrt 参数

  3. 到目前为止一切都很好,但在某些情况下(想象一个看起来像滑雪管的成本函数)沿着梯度移动会使你从山谷的一侧到另一侧的过冲和曲折,而只会慢慢下降(到全局最小值) . 解决方案 - 使用更好的函数逼近(泰勒展开到二阶导数)来达到这个

    param[t+1]=param[t]-(k/cost'') *cost',其中 '' 是二阶导数

直观的快速函数意味着大的二阶导数,因此我们通过减少步长(将其除以一个大数)来减慢收敛速度,反之亦然。
4. 对于通常表示残差平方和或一些距离的二次误差,我们可以提出二阶导数的近似值作为一阶导数的乘积(称为雅可比矩阵,表示为 J,通常是一个矩阵);二阶导数或 Hessian = J T J,所以优化看起来像

param[t+1]=param[t]-(J T J) -1 *cost' - 称为 Gauss-Newton

在这里,为了简单起见,我们删除了 k ;比较这个和以前的公式,我们差不多了!另请注意,在维基百科和其他网站中,您可能会看到他们使用残差 yi-f(x, param) 而不是 k,但您现在也可以忽略它。仅当您对最后一种配方感到满意时,才能走得更远。
5. Levenberg 来了,他说 - 它很棒,但可能不稳定。我们对那些二阶导数做了太多假设,最好抛弃它们并使事情看起来像以前一样的一阶导数。为此,我们添加了一个倾倒因子,可以使优化看起来像

param[t+1]=param[t]-(J T J + lambda*I) -1 *cost',其中 I 是单位矩阵,lambda 是标量

请注意,当 lambda 很大时,您可以丢弃 J T J 并留下标准梯度下降。他们在收敛速度减慢时这样做,否则他们使用小的 lambda,这使得算法看起来更像 Gauss-Newton。注意 J = d_z/d_param, cost'=d_f/d_param and f=z T *z

Marquardt 来了,他说,很好,但我喜欢我们的梯度下降速度更快 - 对于小对角线(J T J),我想要更大的步长,因此最终的公式中我们除以小对角线元素,从而在梯度缓慢时收敛更快:

param[t+1]=param[t]-(J T J + lambda*diagonal(J T J)) -1 *cost'

下面是一个使用速降滑雪类比的快速总结,其中我们展示了参数变化 param[t+1]-param[t] 的表达式:
1. 梯度 J 指向上方,但您想滑雪向下,因此反对梯度 -kJ;
2. 如果在“雪管”中的锯齿形以与二阶导数(H)相反的步长移动;希望你能更快地直线下降: -H -1 J
3. 用一阶导数的乘积近似二阶导数 -(J T J) -1 J ;
4. 如果它太多就转储它并返回一阶导数 -(J T J + lambda I) -1 J;
5.不想卡在平坦的斜坡上?将您的步长反向缩放到近似 Hessian 的对角线:-(J TJ + λ
诊断(J T J)) -1 J

这是一个很大的谜,为什么所有这些工作,因为我的直觉在一段时间后放弃了。也许现在是从哲学角度看待这个问题并应用奥卡姆剃刀原则的好时机——我们假设越少越好,但如果假设太少,我们可能不会走得太远。我们所做的只是预测(假设)函数在本地查看它的全局行为(想象在一起 1 周后结婚)。使用 Hessian 就像在其众多参数方面有更多假设,而不是更保守的雅可比矩阵,它有几个参数(假设)。最后,我们可能希望在保守或冒险方面保持灵活,这就是 Levenberg-Marquardt 方法试图实现的目标。

于 2014-03-14T01:31:00.140 回答