将最佳多边形拟合到离散轮廓

计算科学 计算几何 曲线拟合
2021-12-20 17:07:29

我有一个由一组点表示的离散轮廓。轮廓看起来像一个多边形,但如果你放大你会看到边缘是崎岖不平的(那是因为它是在有限差分网格上工作时获得的)

我想将多边形拟合到这个轮廓(在最小二乘意义上最接近)。是否有任何简单的已知算法可以做到这一点?

在此处输入图像描述

4个回答

我很惊讶为什么没有人提到著名的Douglas Peucker 算法来简化折线。由于您手头有轮廓点,因此您可以直接从中受益。OpenCV 中的轮廓近似使用这种方法。请参阅此处了解用法,您还可以在此处此处找到 MATLAB 实现

霍夫变换是一种用于提取图像特征的图像处理算法。该算法的经典版本旨在从二进制图像中提取线条(例如this)。

有了这样做的能力,您就可以相当容易地编写脚本。这是在 Matlab 中使用霍夫变换(和相关实用程序)的一个。它可能需要图像处理工具箱,但希望你能找到它。

此代码中存在的唯一快捷方式是我告诉“houghpeaks”函数搜索 4 行。通过在霍夫空间中执行其他峰值检测方法,您可以比这更聪明(如果您不熟悉霍夫变换的输出,请阅读 wiki,https://en.wikipedia.org/wiki/Hough_transform)。

一个警告是霍夫变换只会给你整行。您必须对它们进行后处理才能获得线段。由于输入是一个凸多边形,其顶点位于/靠近图像的边缘,因此此示例在没有任何这些的情况下效果特别好。

clear all
close all
clc

% Load image (I suspect your input may be different, but the same ideas hold)
img = imread('polygon.png');

% Make a black/white image using the "blue" as the new white values
bw = img(:,:,1) ~= 255;

% Use hough transform to find lines
[H,theta,rho] = hough(bw);
P = houghpeaks(H,4);
lines = houghlines(bw,theta,rho,P);

% Visualization
imagesc(bw); colormap gray;
hold on;
for l = 1:length(lines)
    plot([lines(l).point1(1) lines(l).point2(1)], ...
         [lines(l).point1(2) lines(l).point2(2)],'r');
end

有一种使用离散几何概念的方法离散几何是一门学科,它处理定义为试图模仿其标准对应物的像素集的对象。它定义了离散段、离散圆、离散平面等......在你的情况下,有一个算法 [1] 定义了离散段是什么,并且在输入图像中重建了最大段的集合,即无法通过向其添加新像素来进一步扩展的片段。另见模糊数据的扩展[2,3]。该方法成功地应用于多视图图像的 3D 重建 [4]

[1] I. DEBLED-Rennesson, J.-P. REVEILLES,数字曲线分割的线性算法,国际模式识别和人工智能杂志,第 9 卷,第 6 期,1995 年 12 月。

[2] I. DEBLED-Rennesson,J.-L。REMY 和 J. ROUYER-DEGLI,将离散曲线线性分割成模糊段,离散应用数学,151:122-137,2005 年 10 月。

[3] I. DEBLED-Rennesson、F. FESCHET 和 J. ROUYER-DEGLI,线性时间噪声形状的最佳模糊分段分解,计算机与图形,30(1),2006。

[4] https://hal.inria.fr/inria-00349084

我不会说它简单,但本文提供了数据与多边形的最小二乘拟合。如果您正在寻找准确性,这可能是最佳选择。

https://www.researchgate.net/publication/303329343_Least-squares_Fitting_of_Polygons

主动形状模型是这种场景的巧妙算法。

另一种方法是将其分解为 4 个单独的线性回归问题。你有尖角,所以创建一个点数组,应用基本的平滑算法,并查看每个点与其邻居的斜率(即导数)。或者,如果您没有尖角,请拟合 catmull-rom 样条曲线(boost c++ 库对此进行了实现)并遍历样条曲线,查看导数以确定分割点。

如果您正在寻找简单快速的方法,我同意 Douglas Peuker 算法,但它需要针对您尝试拟合的数据集进行调整,否则它可能会在错误的线段上拾取角点,从而允许不需要的错误。您可以使用使用多个阈值的迭代方法,测量误差,并尝试在误差最小的点之间进行更精细的迭代。

如评论中所述,霍夫变换和凸包/凸缺陷在 OpenCV 中具有易于使用的实现,并且可能也有帮助。