【问题标题】:Outline (circumference) polygon extraction from geometry constructed from equal squares从由相等正方形构造的几何图形中提取轮廓(周长)多边形
【发布时间】:2015-11-02 07:54:25
【问题描述】:

我确定必须存在一种方法来执行以下操作,但我不知道它叫什么,所以我无法谷歌它。

我需要一个从 A 到 B 的算法。有人知道它叫什么或有链接吗?

编辑:对不起,我不够清楚。图 A 由正方形组成,我基本上需要一个算法来删除正方形并将其变成多边形(图 B)。 输入是轴对齐正方形的普通列表,输出应该是构成多边形的顶点列表。正方形将始终像在网格上一样对齐,它们不会重叠。

为了更清楚,我想写一个这样的函数(伪代码):

struct Square {
    x, y, size: float
}
struct Polygon {
    vertices_x, vertices_y: float[]
}
function convert_to_polygon(IN squares: Square[]) -> OUT Polygon {
    //The algorithm I need goes here
}

【问题讨论】:

  • 不清楚您要做什么。您真的只想将位图 A 转换为位图 B 吗?或者是否有一个单元格的内部表示有或没有一个正方形? B 的表示是一组单元坐标,还是平面中的一组线?如果正方形表示是连续的但里面有一个方孔怎么办?如果有多个方孔怎么办?如果孔不相邻怎么办?
  • “用轮廓替换正方形平面网格上的图形”?输入是如何给出的,是“做以下”来改变表示还是产生输出?
  • 刚刚回答了同样的问题:stackoverflow.com/questions/50885339/…

标签: algorithm math vector geometry 2d


【解决方案1】:

如果我猜对了,你想获得图像的圆周轮廓。

对于矢量和光栅输入,您可以调整/使用finding holes in 2D point set。无论如何,您想寻找某种 (convex) Hull 算法的 2D 适应 ...

如果您的输入是光栅:

  1. 您可以用不同的颜色(例如蓝色)填充背景
  2. 将蓝色像素旁边的所有像素重新着色(变为红色)
  3. 将所有非红色像素重新着色为白色
  4. 将所有红色像素重新着色为黑色

    如果您需要在项目符号 #2 处停止的矢量输出并创建红点列表。然后应用连接像素分析来检测线在多边形中的顺序...对于正方形,这应该很容易,但对于任意图像,您将需要 line regression霍夫变换 ...

如果您的输入是矢量:

然后删除所有内线。所以被 H 形状的其他线条包围的线条。您还可以检测所有小方块,然后删除重复的线条。

[Edit1] 你的输入/输出是矢量所以

  1. 形成所有行的列表
  2. 删除所有出现多次的行

    如果您的正方形是任意大小,那么您需要通过切割重叠段来更精确地做到这一点......

  3. 将第一行添加到多边形(从行列表中删除)

  4. 查找与最后添加到多边形的线具有相同端点的线
  5. 将其添加到多边形(从行列表中删除)
  6. 循环 #4 直到找不到行...
  7. 如果仍有未使用的有效线表示存在多个多边形,则添加新的空多边形并转到 #3

在 C++ 中我破坏了这样的东西:

// temp structures
struct _pnt  { float x,y;       _pnt(){}; _pnt(_pnt& a){ *this=a; }; ~_pnt(){}; _pnt* operator = (const _pnt *a) { *this=*a; return this; }; /*_pnt* operator = (const _pnt &a) { ...copy... return this; };*/ };
struct _lin  { int p0,p1,n;     _lin(){}; _lin(_lin& a){ *this=a; }; ~_lin(){}; _lin* operator = (const _lin *a) { *this=*a; return this; }; /*_lin* operator = (const _lin &a) { ...copy... return this; };*/ };
// your in/out structures
struct _sqr  { float x,y,s;     _sqr(){}; _sqr(_sqr& a){ *this=a; }; ~_sqr(){}; _sqr* operator = (const _sqr *a) { *this=*a; return this; }; /*_sqr* operator = (const _sqr &a) { ...copy... return this; };*/ };
struct _pol { List<float> x,y;  _pol(){}; _pol(_pol& a){ *this=a; }; ~_pol(){}; _pol* operator = (const _pol *a) { *this=*a; return this; }; /*_pol* operator = (const _pol &a) { ...copy... return this; };*/ };
List<_sqr> sqr; // squares
     _pol  pol; // polygon

void sqr2pol_init()
    {
    _sqr s;
    int i,j,p0,p1,p2,p3;
    float x,y,x0,x1,y0,y1,a=32,d,_zero=1e-3;
    // [init square list to your scenario]
    sqr.num=0; pol.x.num=0; pol.y.num=0;
    s.s=a; s.x=a; s.y=a;
    sqr.add(s); s.x+=a;
    sqr.add(s); s.x+=a;
    sqr.add(s); s.x+=a;
    sqr.add(s); s.x =a; s.y+=a;
    sqr.add(s); s.x =a; s.y+=a;
    sqr.add(s); s.x+=a;
    // [compute point and line lists]
    List<_pnt> pnt; _pnt p;
    List<_lin> lin; _lin l;
    for (pnt.num=0,lin.num=0,i=0;i<sqr.num;i++)
        {
        x=sqr[i].x;
        y=sqr[i].y;
        a=sqr[i].s*0.5;
        x0=x-a; x1=x+a;
        y0=y-a; y1=y+a;
        // add non duplicate points only
        p.x=x0; p.y=y0; for (j=0;j<pnt.num;j++) { x=pnt[j].x-p.x; y=pnt[j].y-p.y; if ((x*x)+(y*y)<=_zero) break; } if (j>=pnt.num) pnt.add(p); p0=j;
        p.x=x0; p.y=y1; for (j=0;j<pnt.num;j++) { x=pnt[j].x-p.x; y=pnt[j].y-p.y; if ((x*x)+(y*y)<=_zero) break; } if (j>=pnt.num) pnt.add(p); p1=j;
        p.x=x1; p.y=y1; for (j=0;j<pnt.num;j++) { x=pnt[j].x-p.x; y=pnt[j].y-p.y; if ((x*x)+(y*y)<=_zero) break; } if (j>=pnt.num) pnt.add(p); p2=j;
        p.x=x1; p.y=y0; for (j=0;j<pnt.num;j++) { x=pnt[j].x-p.x; y=pnt[j].y-p.y; if ((x*x)+(y*y)<=_zero) break; } if (j>=pnt.num) pnt.add(p); p3=j;
        // add non duplicate lines (and update counter n for duplicates)
        l.p0=p0; l.p1=p1; l.n=0; for (j=0;j<lin.num;j++) if (((lin[j].p0==l.p0)&&(lin[j].p1==l.p1))||((lin[j].p0==l.p1)&&(lin[j].p1==l.p0))) { lin[j].n++; break; } if (j>=lin.num) lin.add(l);
        l.p0=p1; l.p1=p2; l.n=0; for (j=0;j<lin.num;j++) if (((lin[j].p0==l.p0)&&(lin[j].p1==l.p1))||((lin[j].p0==l.p1)&&(lin[j].p1==l.p0))) { lin[j].n++; break; } if (j>=lin.num) lin.add(l);
        l.p0=p2; l.p1=p3; l.n=0; for (j=0;j<lin.num;j++) if (((lin[j].p0==l.p0)&&(lin[j].p1==l.p1))||((lin[j].p0==l.p1)&&(lin[j].p1==l.p0))) { lin[j].n++; break; } if (j>=lin.num) lin.add(l);
        l.p0=p3; l.p1=p0; l.n=0; for (j=0;j<lin.num;j++) if (((lin[j].p0==l.p0)&&(lin[j].p1==l.p1))||((lin[j].p0==l.p1)&&(lin[j].p1==l.p0))) { lin[j].n++; break; } if (j>=lin.num) lin.add(l);
        }
    // [copy singular lines only to polygon + connected lines analysis/reorder]
    // add first usable (n==0) line to polygon
    p0=-1;
    for (i=0;i<lin.num;i++)
     if (lin[i].n==0)
        {
        pol.x.add(pnt[lin[i].p0].x);
        pol.y.add(pnt[lin[i].p0].y);
        pol.x.add(pnt[lin[i].p1].x);
        pol.y.add(pnt[lin[i].p1].y);
        p0=lin[i].p0;   // p0 = start of polygon
        p1=lin[i].p1;   // p1 = current end of polygon
        lin[i].n++;     // mark as unusable
        break;
        }
    // add next line to p1 until you can
    for (j=1;j;)
        {
        for (i=0,j=0;i<lin.num;i++)
         if (lin[i].n==0)
            {
            p2=-1;
            if (lin[i].p0==p1) p2=lin[i].p1;
            if (lin[i].p1==p1) p2=lin[i].p0;
            if (p2<0) continue;
            pol.x.add(pnt[p2].x);
            pol.y.add(pnt[p2].y);
            lin[i].n++;     // mark as unusable
            p1=p2;          // update last point
            j=1;            // continue search
            break;
            }
        }
    }
  • List&lt;T&gt; l; 只是动态线性数组模板(类似于std::vector
  • 代表T[l.num] l;
  • l.num 是数组的当前大小
  • l.add(x); 将新项目 x 添加到数组末尾 ...

这是结果:

  • Aqua 线条是原始方块sqr
  • 黄色线是 Polygon pol 输出

【讨论】:

  • 这看起来是一个有趣的解决方案,谢谢。我不认为我理解第 4 步,您能否详细说明“找到具有相同端点的线”的含义?
  • 很容易从多边形内的单线开始。因此,从中取出最后一个点并在列表中搜索从该点开始或结束的线(如果找到),这意味着该线是多边形的延续,因此将其添加到顶点列表(不包括公共点)并再次搜索从新的最后一点...
  • 我想我明白了。所以基本上当所有重复的线路都被删除时,只有一条可能的线路可以与另一条线路连接? 2 号井
  • @WimV 是的。但是如果你有重叠的正方形或大小不同的正方形,那么你需要剪掉线条,只留下只出现一次的部分。这有点难......
  • 是的,但事实并非如此,它们的大小都相同。我已将您的答案标记为已接受。再次感谢
猜你喜欢
  • 2019-05-08
  • 1970-01-01
  • 2014-11-24
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 2012-05-10
  • 2017-03-18
  • 1970-01-01
相关资源
最近更新 更多