【问题标题】:Get Vertices/Edges From BMP or SVG (C#)从 BMP 或 SVG (C#) 获取顶点/边
【发布时间】:2015-10-13 19:21:12
【问题描述】:

我有一个 JPG、BMP 或 SVG 图像(参见下面的示例),我需要一个算法来提取顶点(X、Y)坐标和 egdes(即指示哪些顶点连接的列表)。边可以是每个顶点对的布尔真/假形式,或者只是连接的顶点对的列表。欢迎任何想法。

例如,我想要一个输入图像并输出两个列表的函数(或一系列函数):

顶点

顶点 1:X = 1,Y = 2

顶点 2:X = 3,Y = 5

顶点 3:X = 3,Y = 7

...

边缘

边 1:(顶点 1,顶点 3)

边 2:(顶点 1,顶点 4)

边 3:(顶点 4,顶点 10)

...

顶点坐标系可以是任何坐标系(例如,基于 SVG 坐标的像素),也可以是其他用户定义的坐标系。

例如,我从示例图像(左)中提取了以下坐标(像素)并在 Matlab 中绘制它们(右)。

因此,例如,我可以看出角顶点大致为: (10, 10), (290, 10), (290, 190) 和 (10, 190)。

但我想要一个算法来自动检测这些坐标,并告诉我左上顶点 (10, 190) 和右上顶点 (290, 190) 之间有一条边,等等。我还需要识别内部块的每个顶点和边等。

同样,对于更复杂的图表,我也需要它来工作。例如,我能够提取必要的像素并生成以下 Matlab 图:

与之前类似,顶点“应该”在哪里很清楚,但是,由于线条粗细,有许多像素簇首先需要“平滑”等。我不确定如何着手执行此操作并自动化识别顶点/边的过程。

注1:我用来获取像素坐标的方法基本上是:

  • 转换为黑/白
  • 扫描每个像素以查看颜色是否
  • 在 Matlab 中绘图

我想的一个粗略的算法是:

  • 应用“平滑”以获得单行而不是像素簇
  • “循环”通过不同方向的像素,当发生明显的坡度变化时,将其识别为“顶点”
  • 识别所有顶点后,评估每对顶点之间的线,如果该线大部分为黑色,则将其识别为边

上述算法存在很多问题,所以我希望其他人可能有一些更好的想法或类似的C#代码等。

我希望流程尽可能自动化。

注 2:我还可以将图像转换为 SVG 格式(已经实现)。据我了解,SVG 格式可能非常适合我的应用程序,因为它可以更轻松地自动化该过程;但是,我发现 SVG 结构相当混乱。

我已经阅读了一些关于 SVG 格式的在线文献,并且我了解它是如何工作的,但是我想知道是否有某种已经存在的库或者可以让我非常容易地识别“路径”的顶点的东西在 SVG 文件等中。

例如,我从一个 SVG 文件中获得的“路径”之一是以下形式:

<path d="M70 1810 c0 -91 3 -110 15 -110 12 0 15 17 15 95 l0 95 1405 
0 1405 0 0 -410 0 -411 -87 3 -88 3 -1 35 c0 19 -1 124 -2 233 l-2 197 
-70 0 -70 0 0 -320 0 -320 153 0 c83 0 162 3 175 6 l22 6 0 504 0 504 
-1435 0 -1435 0 0 -110z m2647 -490 c1 -113 2 -217 2 -232 l1 -27 88 -3 
87 -3 0 -70 0 -70  145 0 -145 0 -3 295 c-1 162 0 301 3 308 3 9 21 12 
57 10 l53 -3 2 -205z"/>

我知道这遵循三次贝塞尔样条曲线,但我想知道是否有任何现有的算法可以处理“路径”代码并提取相关坐标等。

感谢您的帮助!!

【问题讨论】:

  • 这是一个很重要的问题。我建议您更严格地指定要求,因为您的问题的解决方案目前不明确。在我们为您完成工作之前,您可以展示任何尝试吗?我们宁愿看到你做出了努力。
  • 最肯定使用 SVG,因为它已经是矢量输出(因此不需要矢量化,这是一项艰巨的任务)。查看SVG refferencepath 实体如何阅读它并不难(除非您添加动画、矩阵等...)M70 1810MoveTo(70,18110) 等... 大字母绝对小是相对跨度>
  • 嗨,本,感谢您的回复/反馈。除了我需要一个顶点和边的列表(在任何坐标系中)之外,真的没有严格的要求。我真的在寻找想法,因为使用 BMP 会导致一些问题(正如 Spektre 所暗示的那样),并且我发现 SVG 很复杂,并假设网上会有一个我尚未找到的通用解决方案。任何建议表示赞赏。我不希望有人为我编写整个代码(尽管我不会抱怨),更多的是一些指导/建议。谢谢!
  • 您好,Spektre,感谢您的意见! SVG 似乎确实是要走的路。但是实现一个解释 SVG 文件的“阅读器”似乎相当复杂,因为有许多不同的可能性/变体等。我可以访问解析的 SVG 文件。因此,对于每条路径,我都有 M-(x,y) 值以及“c”和“m”之后的每个数字等。如果有人对如何使用这些 (x,y) 有很好的参考)、M、m、c 等值来查找方程和/或绘制路径,这将是一个很大的帮助。谢谢!

标签: c# algorithm svg pixels bezier


【解决方案1】:

SVG 路径解析并不难(除非您有复杂的 SVG,但情况似乎并非如此)

  1. 寻找路径

    路径以&lt;path 标记开始,通常以/&gt; 结束,所以找到路径开始/结束,然后只使用里面的字符串。

  2. 找到d="

    那是路径字符串数据(所以你跳过格式化等......)它的结尾用"标记,所以再次只使用里面的字符串

  3. 处理路径字符串

    1. 读取单个字符(跳过空格)
    2. 根据字符读取正确的数字计数并将实体添加到您的矢量表示 例如:

      • M 表示绝对移动所以x,y 跟随所以cursor = (x,y);
      • m 表示相对移动所以x,y 跟随所以cursor+= (x,y);
      • L 表示绝对行,所以 x,yfollows 所以 add_line(cursor,(x,y)); cursor = (x,y);
      • l 表示相对线所以x,yfollows 所以add_line(cursor,cursor+(x,y)); cursor += (x,y);
      • C 表示绝对 BEZIER 立方,所以 x1,y1,x2,y2,x3,y3 遵循所以 add_cubic_BEZIER(cursor,(x1,y1),(x2,y2),(x3,y3)); cursor=(x3,y3)
      • 等...命令m,M,l,L,h,H,v,V,c,C,s,S,q,Q,t,T 仅在点数和曲线/线类型上有所不同
      • z 的意思就是你在结尾处添加从cursor 到起点的行
    3. 如果下一个字符串以数字开头,则将其作为最后一个命令处理并转到 #2

    4. 转到 #1

就是这样。因此,您所需要的只是简单的字符串解析,能够读取尾数/指数形式的数字,例如 -125.547e-99 并跳过空格/制表符。您不需要解码整个 SVG 只是路径。

因为每个 SVG 可以有许多路径,所以在解析第一个 &lt;path 之后找到另一个解析它......直到没有人离开。有时&lt;path 包含变换矩阵甚至所有者tag 通常&lt;g所以可能会有一些变换,但我认为没有这些东西你的导出很简单。

【讨论】:

  • 随机评论:我非常高兴您没有被元问题推迟,并且您实际上正在为此做点什么!继续出色的工作,我希望 SO 中的每个人都像你一样(包括我!);)
  • 感谢您的信息!我会看看它。感谢您的详细回复!
猜你喜欢
  • 2013-05-26
  • 2019-01-09
  • 1970-01-01
  • 2016-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
相关资源
最近更新 更多