【问题标题】:Incomplete Delaunay triangulation不完整的 Delaunay 三角剖分
【发布时间】:2022-01-12 02:51:11
【问题描述】:

我正在使用 C++ 和 OpenCV 从图像上用户指定的样本点创建 Delaunay 三角形网格(然后将使用相关 ODE 的 FEM 跨域外推)。

由于(矩形)图像的 4 个角位于提供给 Subdiv2D 的顶点列表中,因此我希望三角剖分的外部凸包能够跟踪图像的周长。但是,外部经常缺少元素。

有时我可以通过微调某些点的坐标来避免高纵横比的三角形来获得预期的结果。但这不是一个解决方案,因为通常用户最能够指定任何有效坐标。

示例输出如下所示:CV Output。元素为带有黑色边缘的白色。在底部和右侧边缘,没有添加任何三角形,您可以看到黑色背景。

请问如何使三角剖分的外凸包跟踪图像周边而没有间隙?

这是一个 MWE(包括绘图功能):

#include <opencv2/opencv.hpp>
#include <vector>

void DrawDelaunay(cv::Mat& image,cv::Subdiv2D& subdiv);

int main(int argc,char** argv)
{
    // image dim
    int width=3440;
    int height=2293;
    
    // sample coords
    std::vector<int> x={0,width-1,width-1,0,589,1015,1674,2239,2432,3324,2125,2110,3106,3295,1298,1223,277,208,54,54,1749,3245,431,1283,1397,3166};
    std::vector<int> y={0,0,height-1,height-1,2125,1739,1154,817,331,143,1377,2006,1952,1501,872,545,812,310,2180,54,2244,2234,1387,1412,118,1040};

    // add delaunay nodes
    cv::Rect rect(0,0,width,height);
    cv::Subdiv2D subdiv(rect);
    for(size_t i=0;i<x.size();++i)
    {
        cv::Point2f p(x[i],y[i]);
        subdiv.insert(p);
    }
    
    // draw elements
    cv::Mat image(height,width,CV_8U);
    DrawDelaunay(image,subdiv);
    cv::resize(image,image,cv::Size(),0.3,0.3);
    cv::imshow("Delaunay",image);

    cv::waitKey(0);
    return 0;
}

void DrawDelaunay(cv::Mat& image,cv::Subdiv2D& subdiv)
{
    std::vector<cv::Vec6f> elements;
    subdiv.getTriangleList(elements);
    std::vector<cv::Point> pt(3);

    for(size_t i=0;i<elements.size();++i)
    {
        // node coords
        cv::Vec6f t=elements[i];
        pt[0]=cv::Point(cvRound(t[0]),cvRound(t[1]));
        pt[1]=cv::Point(cvRound(t[2]),cvRound(t[3]));
        pt[2]=cv::Point(cvRound(t[4]),cvRound(t[5]));

        // element edges
        cv::Scalar black(0,0,0);
        cv::line(image,pt[0],pt[1],black,3);
        cv::line(image,pt[1],pt[2],black,3);
        cv::line(image,pt[2],pt[0],black,3);

        // element fill
        int nump=3;
        const cv::Point* pp[1]={&pt[0]};
        cv::fillPoly(image,pp,&nump,1,cv::Scalar(255,0,0));
    }
}

如果相关,我首先在 Matlab 中对此进行了编码,其中 Delaunay 三角测量完全符合我的预期。

【问题讨论】:

    标签: c++ opencv convex-hull delaunay


    【解决方案1】:

    我通过Tinfour 项目的演示应用程序运行了您的数据点,得到了如下所示的结果。看起来你的数据很好。不幸的是,Tinfour 项目是用 Java 编写的,而您使用的是 C++,所以它对您的价值有限。

    由于您计划使用有限元方法,您可能想看看是否有任何方法可以对数据运行 Delaunay 细化操作以改进几何。使用 FEM 软件时,细三角形有时会导致数值问题。

    【讨论】:

    • 感谢您的建议。一般来说,你是对的,高 AR 三角形会导致 FEM 中的数值问题。然而,我正在使用相当基本的线性三角形元素来计算泊松方程。如果它们不是完全“平坦的”,它们看起来就像你得到的一样健壮。然而,这些高 AR 三角形导致了 Delaunay 算法的这种实现问题。我最近的改进是用一个间隔相当均匀的节点(不是样本位置)网格覆盖域,除了扩大网格域,三角形看起来更好。
    【解决方案2】:

    我的解决方案是在提供给 cv::Subdiv2D 的“cv::Rect rect”周围添加一个边框,使其在宽度和高度上大于图像(大 20% 似乎效果很好)。

    然后,我没有在图像的角上添加节点,而是在这个扩大的 'cv::Rect rect' 变量的边界上添加了 4 个角节点和 4 个边缘节点,该变量包含 Delaunay 点。

    这似乎解决了问题。我认为正在发生的事情是,如果用户将任何样本放在图像边缘附近,则会导致边缘处出现高纵横比三角形。这个ticket 表明在 Delaunay 算法的 OpenCV 实现中存在一个错误。

    希望我的解决方案意味着角节点和边缘节点永远不会太靠近用户样本,从而回避问题。

    我还没有对此进行广泛的测试。我不确定解决方案会变得多么强大。到目前为止,它已经奏效了。

    我仍然有兴趣了解其他解决方案。

    【讨论】:

      猜你喜欢
      • 2015-01-07
      • 2019-04-18
      • 2021-05-14
      • 2013-05-12
      • 1970-01-01
      • 2019-09-28
      • 2016-02-08
      • 2014-01-21
      • 2011-11-10
      相关资源
      最近更新 更多