使用 Accord.NET 进行自动图像拼接






4.98/5 (189投票s)
演示使用 Accord 和 AForge.NET 框架进行自动图像拼接
有关最新版本代码(可能包含最新增强和更正)的信息,请下载最新版本的 Accord.NET Framework。
目录
引言
Accord.NET Framework 最初是作为 AForge.NET 的扩展框架而创建的,AForge.NET 是一个流行的计算机视觉和人工智能框架。然而,Accord.NET 现在实现了 AForge.NET 中没有的许多工具和功能,例如 Kernel Support Vector Machines、判别式和投影分析、隐马尔可夫模型、新的神经网络学习算法、对象检测、成像滤波器以及其他有用的方法和工具。Accord.NET 允许开发自动图像拼接程序,并可能用于自动创建全景图。
全景图是通过将一系列照片组合成一张大照片而形成的。通过组合一系列照片,可以提供单个镜头无法捕捉的区域或位置的完整视图。
在下面的示例中,我们将演示如何使用 Accord.NET 中已有的功能将两张图像拼接在一起,创建一个简单的小全景图。在最后一节中,我们将讨论将该方法推广到多对图像以创建成熟的图像马赛克的方法。
在此演示中,我们将使用从 UFSCar 湖拍摄的这两张照片。照片的拍摄角度彼此相差几度。我们可以看到体育馆仅出现在第二张照片中,而湖的最左侧部分仅出现在第一张照片中。
特征提取
为了创建我们的全景图,总体思路将是识别两张图像之间的共同点,然后将其中一张图像投影到另一张图像上以匹配这些点。为了识别这些点(我们以后将称之为“兴趣点”),我们将使用一种简单的兴趣点检测器,称为 Harris 角点检测器。
虽然 Harris 检测器的完整描述超出了本文的范围(但可以在此处找到),但我认为包含有关角点检测器和 Harris 算子的一些历史信息很有趣。
最早的兴趣点检测算子之一是由 Hans P. Moravec 于 1977 年为他关于机器人穿越簇状环境的自动导航研究开发的。也是 Moravec 定义了图像中“兴趣点”的概念,并得出这些兴趣点可用于在不同图像中查找匹配区域。Moravec 算子被认为是角点检测器,因为它将兴趣点定义为在所有方向上强度变化较大的点。这通常发生在角点处。然而,有趣的是,Moravec 并不特别关注寻找角点,而只是寻找可用于配准连续图像帧的图像中的独特区域。
Harris 和 Stephens 通过直接考虑角点分数相对于方向的微分,改进了 Moravec 的角点检测器。他们需要它作为构建基于图像序列的机器人环境解释的处理步骤。与 Moravec 一样,他们需要一种方法来匹配连续图像帧中的对应点,但他们对跟踪帧之间的角点和边缘都感兴趣。
虽然存在更好的兴趣点检测器,例如 SIFT 和 SURF,但它们不幸地受到专利的限制。为了允许本库的完整商业使用,我决定避免使用它们,而是使用 Harris 检测器。
特征匹配
在检测到兴趣点后,我们需要以某种方式对它们进行关联。为此,我们将使用最大相关规则来确定两张图像之间的匹配。交叉相关通过分析第一张图像中每个点周围的像素窗口,并将其与第二张图像中每个其他点周围的像素窗口进行关联来实现。具有最大双向相关性的点将被视为对应对。
然而,从图中我们可以看到,许多点被错误地关联了。对角线就是这种情况,它们的方向与大多数其他线条不同。尽管如此,我们不必担心这些,原因将在下一节中清楚。
单应性估计
现在我们有了两组关联点,我们所要做的就是定义一个模型,该模型可以将点从一个集合翻译到另一个集合。我们正在寻找的是一种图像变换,可以用于将两张图像中的一张投影到另一张图像上,同时匹配大多数关联的特征点——我们需要一个匹配两张图像的单应性矩阵。
单应性是一种投影变换,是射影几何中使用的一种变换。它描述了当观察者的视角改变时,观察到的物体的位置如何变化。更正式地说,单应性是从实射影平面到射影平面的可逆变换,它将直线映射到直线。
通过使用齐次坐标,可以将单应性矩阵表示为具有 8 个自由度的 3x3 矩阵。
在 System.Drawing
命名空间中,有一个 Matrix
类,它封装了一个 3x3 的仿射矩阵,表示一个几何变换。在 Accord.Imaging 中,MatrixH
类封装了一个 3x3 的齐次矩阵,表示一个投影变换。两个矩阵之间的区别仅在于它们的自由度。
尽管 System.Drawing
的几何变换矩阵是 3x3 的,但只有 6 个自由度,而 Accord.NET 的投影变换有 8 个自由度。在后者中,最后一个值可以解释为尺度参数,并且可以固定为 1,如上图所示。齐次坐标被使用,因为仅靠矩阵乘法无法直接执行透视投影所需的除法。
使用齐次坐标,而不是将图像中每个像素的位置表示为 <x,y>
对,我们将使用 <x,y,w>
元组来表示它,其中 w
也是一个尺度参数。为简单起见,我们将 w
固定为 1。
齐次坐标非常有用,因为它们允许我们仅通过使用标准矩阵乘法执行图像投影变换,如下面的方程和示意图所示。
一旦计算出所有投影点,我们就可以通过将每个点除以其齐次尺度参数,然后删除尺度因子(除法后将设置为 1)来恢复我们的原始坐标系。
通过估计单应性矩阵的正确值,我们可以得到如下变换
这可能最终得到如下投影
既然我们已经定义了单应性是什么以及它的用途,我们就可以开始讨论如何从关联点集中创建这个单应性矩阵。为了从数据中估计一个鲁棒的模型,我们将使用一种称为 RANSAC 的方法。
RANSAC 这个名字实际上是“RANdom SAmple Consensus”(随机样本一致性)的缩写。它是一种迭代方法,用于从可能包含异常值的数据点集中稳健地估计拟合数学模型的参数。该算法不是确定性的,因为它只在一定概率下产生合理的结果,并且随着迭代次数的增加,该概率会增加。RANSAC 算法在计算机视觉中有许多应用,包括同时解决对应问题以及估计与一对立体相机相关的基本矩阵。
该方法的基本假设是,数据由“内点”组成,即其分布可以由某个数学模型解释的数据,以及“异常值”,即不适合模型的数据。异常值可能被视为来自噪声、错误测量或仅仅是错误数据的点。
对于单应性估计问题,RANSAC 的工作方式是尝试使用一些点对来拟合多个模型,然后检查这些模型是否能够关联大部分点。然后选择最佳模型,即产生最高正确匹配数的单应性,作为问题的答案。
RANSAC 执行后,我们可以看到图像中只剩下正确的匹配。这是因为 RANSAC 找到了一个关联大部分点的单应性矩阵,并将错误的匹配作为异常值丢弃。
RANSAC 的完整解释远远超出了本文的范围,但有关 C# 中 RANSAC 实现的更多信息可以在此处找到。
混合
在计算出单应性矩阵后,我们所要做的就是将这两张图像混合在一起。为此,我们将使用从一个图像中心到另一个图像中心的线性渐变 alpha 混合。渐变混合通过模拟一个图像的 alpha 通道在连接两个图像中心的线上的渐变变化来实现。
图像显示了混合滤波器使用的线性渐变。图像最左边的灰色部分代表湖泊的左侧图像。最右边的部分代表湖泊的右侧图像。内部部分显示了将一个图像混合到另一个图像的线性渐变。渐变的第一个,最灰的颜色代表第一个图像,而最深的颜色代表第二个图像。过渡表明在最终混合中每个图像的多少。
结果
应用混合滤波器后,我们最终将得到如下结果
源代码
使用 Accord.NET,图像拼接的代码变得非常简单。请记住,我们需要执行四个步骤:兴趣点检测、相关匹配、鲁棒单应性估计和渐变混合。因此,在进入这些步骤之前,让我们定义一些类变量(此代码来自示例应用程序代码)
// Images we are going to stitch together
private Bitmap img1 = Panorama.Properties.Resources.UFSCar_Lake1;
private Bitmap img2 = Panorama.Properties.Resources.UFSCar_Lake2;
// Fields to store our interest points in the two images
private IntPoint[] harrisPoints1;
private IntPoint[] harrisPoints2;
// Fields to store our correlated points
private IntPoint[] correlationPoints1;
private IntPoint[] correlationPoints2;
// The homography matrix estimated by RANSAC
private MatrixH homography;
本文附带的源代码包含示例应用程序以及 Accord.NET Framework 的一小部分,以避免混乱命名空间。如果您想使用 Accord.NET,请务必从 GitHub 上的项目页面下载最新版本。顺便说一句,示例应用程序假定您只需按正确的顺序单击按钮。如果您在前一个步骤尚未完成的情况下调用某个步骤,您很可能会收到异常。这只是为了反映拼接所需的代码。它也与下一节中显示的完全相同。
兴趣点检测
为了进行兴趣点检测,我们将使用 Accord.Imaging.HarrisCornersDetector
类。为了加快进程,我们可以使用更高的抑制阈值来抑制一些点。在本例中,我们将使用 1000。
private void btnHarris_Click(object sender, EventArgs e)
{
// Step 1: Detect feature points using Harris Corners Detector
HarrisCornersDetector harris = new HarrisCornersDetector(0.04f, 1000f);
harrisPoints1 = harris.ProcessImage(img1).ToArray();
harrisPoints2 = harris.ProcessImage(img2).ToArray();
// Show the marked points in the original images
Bitmap img1mark = new PointsMarker(harrisPoints1).Apply(img1);
Bitmap img2mark = new PointsMarker(harrisPoints2).Apply(img2);
// Concatenate the two images together in a single image (just to show on screen)
Concatenate concatenate = new Concatenate(img1mark);
pictureBox.Image = concatenate.Apply(img2mark);
}
相关匹配
使用 Accord.NET,可以通过使用 Accord.Imaging.CorrelationMatching
类来实现相关性。在本例中,我们将考虑每个点周围 9 个像素的窗口。
private void btnCorrelation_Click(object sender, EventArgs e)
{
// Step 2: Match feature points using a correlation measure
CorrelationMatching matcher = new CorrelationMatching(9);
IntPoint[][] matches = matcher.Match(img1, img2, harrisPoints1, harrisPoints2);
// Get the two sets of points
correlationPoints1 = matches[0];
correlationPoints2 = matches[1];
// Concatenate the two images in a single image (just to show on screen)
Concatenate concat = new Concatenate(img1);
Bitmap img3 = concat.Apply(img2);
// Show the marked correlations in the concatenated image
PairsMarker pairs = new PairsMarker(
correlationPoints1, // Add image1's width to the X points
// to show the markings correctly
correlationPoints2.Apply(p => new IntPoint(p.X + img1.Width, p.Y)));
pictureBox.Image = pairs.Apply(img3);
}
鲁棒单应性估计
在这里,我们将使用 Accord.Imaging.RansacHomographyEstimator
类来使用 RANSAC 估计单应性矩阵。RansacHomographyEstimator
是一个便捷类,封装了用于设置 Accord.MachineLearning.RANSAC
对象的所有逻辑,并提供用于拟合单应性矩阵的参数。
private void btnRansac_Click(object sender, EventArgs e)
{
// Step 3: Create the homography matrix using a robust estimator
RansacHomographyEstimator ransac = new RansacHomographyEstimator(0.001, 0.99);
homography = ransac.Estimate(correlationPoints1, correlationPoints2);
// Plot RANSAC results against correlation results
IntPoint[] inliers1 = correlationPoints1.Submatrix(ransac.Inliers);
IntPoint[] inliers2 = correlationPoints2.Submatrix(ransac.Inliers);
// Concatenate the two images in a single image (just to show on screen)
Concatenate concat = new Concatenate(img1);
Bitmap img3 = concat.Apply(img2);
// Show the marked correlations in the concatenated image
PairsMarker pairs = new PairsMarker(
inliers1, // Add image1's width to the X points to show the markings correctly
inliers2.Apply(p => new IntPoint(p.X + img1.Width, p.Y)));
pictureBox.Image = pairs.Apply(img3);
}
渐变混合
最后一步是创建图像的混合。为此,我们将使用 Accord.Imaging.Blend
滤波器,该滤波器实现为 AForge.NET 图像滤波器。
private void btnBlend_Click(object sender, EventArgs e)
{
// Step 4: Project and blend the second image using the homography
Blend blend = new Blend(homography, img1);
pictureBox.Image = blend.Apply(img2);
}
一次性完成
要一次性执行所有操作,我们可以在单个按钮中使用以下代码
private void btnDoItAll_Click(object sender, EventArgs e)
{
// Do it all
btnHarris_Click(sender, e);
btnCorrelation_Click(sender, e);
btnRansac_Click(sender, e);
btnBlend_Click(sender, e);
}
这样就完成了自动图像拼接所需的所有代码!
示例应用
本文附带的示例应用程序还包含另外两组照片,一组是从 UFSCar 计算系大楼内部拍摄的,另一组是从网上找到的随机壁纸拍摄的。下面是从应用程序拼接计算系两张照片的截图。
但是,为了使用额外的图像,有必要将它们添加到项目资源文件中,然后在代码中选择它们。或者,您可以添加自己的图像加载对话框。我避免使用文件打开对话框,以仅展示一种紧凑直接的拼接方法视图。
备注
RANSAC 是一种概率算法。这意味着它每次执行时可能会产生不同的输出,并且只有在一定概率下才能产生正确答案。因此,如果 RANSAC 参数选择不当,最终结果的质量可能会有很大差异。此外,您可能已经注意到,拼接方法的每个步骤都有许多需要调整的参数。选择正确的参数值可能会直接影响结果的质量和生成结果所需的时间。
已知问题
目前的实现对于照明条件差异很大的图像效果不佳。为了避免这种情况,我们应该在开始方法之前对两张图像进行归一化。
另一个已知问题是混合滤波器的质量。虽然它在侧向位移的图像上效果可能很好,但在对角线位移的图像上效果可能不佳。正如在拼接计算系图片时可以看到的那样,在一张图像和另一张图像之间会有一条明显的水平线。
进一步研究
此代码非常适合一对图像的自动全景图创建。但是,就目前而言,它仍然不能用于使用任意数量的图像创建完整全景图。为了将代码扩展到多图像情况,我们可以通过递归地从总图像集中获取图像对,然后将它们混合形成一个单一图像来创建全景图。
还可以通过在尝试匹配之前考虑两张图像之间的最小相关性阈值来扩展代码以创建图像马赛克,而我们事先不知道图像的正确顺序。这样,一次只拼接具有强对应关系的图像,并且可以通过递归方式再次构建完整的马赛克。
结论
在本文中,我们已经看到了如何使用明确定义的简单处理步骤来实现自动全景图创建。这些步骤已经在 Accord.NET 中可用,Accord.NET 是一个基于 AForge.NET(也是 LGPL)构建的开源(LGPL)框架。有关 Accord.NET 中当前可用功能的完整列表,请参阅项目的介绍页面。
致谢
感谢 Andrew Kirillov,他是出色的 AForge.NET 框架的作者,感谢他构建框架所付出的努力和时间。C# 社区非常需要这样一个伟大的项目。
参考文献
- P. D. Kovesi. 计算机视觉和图像处理的 MATLAB 和 Octave 函数。西澳大利亚大学计算机科学与软件工程学院。
- D. Parks 和 J. P. Gravel. 角点检测器:Harris/Plessey 算子。Web. 2010 年 5 月 11 日。
- J. Hutton 和 B. Dowling. 计算机视觉演示网站。南安普顿大学电子与计算机科学系。
- H. P. Moravec. 走向自动视觉障碍规避。第 5 届国际人工智能联合会议论文集,第 584 页,1977 年。
- H. P. Moravec. 机器人漫游者的视觉测绘。国际人工智能联合会议,第 598-600 页,1979 年。
- C. Harris 和 M. Stephens. 联合角点和边缘检测器。Alvey Vision 会议论文集,曼彻斯特大学,第 147-151 页,1988 年。
- A. Kirillov. AForge.NET 框架。AForge.NET 计算机视觉、人工智能和机器人网站,2010 年。
- Wikipedia 贡献者。“RANSAC” 维基百科,自由的百科全书。
- Wikipedia 贡献者。“角点检测” 维基百科,自由的百科全书。2010 年 5 月 5 日。Web. 2010 年 5 月 11 日。