从BMP或SVG获取顶点/边缘(C#)

时间:2015-10-13 19:21:12

标签: c# algorithm svg pixels bezier

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

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

顶点

顶点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(右)中绘制它们。

Example 1 (Easier)

所以,例如,我可以告诉角顶点是粗略的: (10,10),(290,10),(290,190)和(10,190)。

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

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

Example 2 (Harder)

与以前类似,很明显顶点“应该”在哪里,但是,由于线条厚度,有许多像素群首先需要“平滑”,等等。我不确定如何进行此操作并自动识别顶点/边缘的过程。

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

  • 转换为黑/白
  • 扫描每个像素以查看颜色< =阈值,如果它是“黑色”则保存(X,Y)
  • 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"/>

我知道它遵循Cubic Bezier Spline,但我想知道是否有任何现有算法来处理“路径”代码并提取相关坐标等。

感谢您的帮助!!

1 个答案:

答案 0 :(得分:2)

SVG路径解析并不那么难(除非你有复杂的SVG,似乎不是这样)

  1. 查找路径

    路径以<path标记开头,通常以/>结束,因此找到路径的开始/结束,然后只使用内部的字符串。

  2. 找到d="

    这是路径字符串数据(所以你跳过格式化等...)这个结尾用"标记,所以再次只用字符串

  3. 处理路径字符串

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

      • M表示绝对移动,因此x,y跟随cursor = (x,y);
      • m表示相对移动,因此x,y跟随cursor+= (x,y);
      • L表示绝对行,因此x,y跟随add_line(cursor,(x,y)); cursor = (x,y);
      • l表示相对行,因此x,y跟随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

  4. 就是这样。所以你需要的只是简单的字符串解析,能够读取尾数/指数形式的数字,如-125.547e-99和滑动空格/制表符。您不需要仅对路径解码整个SVG。

    因为每个SVG可以有很多路径,然后在解析第一个<path之后找到另一个解析它...直到没有人离开。有时<path包含转换矩阵,甚至包含所有者tag usualy <g,因此可能会堆叠一些转换,但我认为如果没有这些转换,您的导出很简单。