从像斑点一样的图像的(内部和外部)边缘创建路径



我正在寻找一种方法来创建一个类似svg的路径从二进制图像(只有黑色和白色像素)。图像本身将是一个不规则形状的斑点,其中可能有洞。

如果没有孔,我只需要一个边界路径来重建blob的边界。当斑点中有洞时,我可以使用额外的路径(因为单独的路径无法重新创建这个,我猜)。最后,我只需要知道哪条路径是外部路径,哪些是洞。

我已经找到了这些:

  • 如何在JavaScript画布中添加描边/轮廓到透明PNG图像
  • 从图像边缘创建路径
  • 我如何在二维矩阵中找到洞?

另外,我需要检测洞。对于我来说,结果是多边形还是路径并不重要。我只需要有足够高的精度的点,曲线保持弯曲:)

如果有人有一个想法,甚至一些进一步的来源,那就太好了。

PS:我正在使用画布和javascript (fabricJS),如果这有任何区别。

最后,我成功地使用了markE描述的另一个选项(尽管它稍作修改)。我使用Marching Squares Algorithm (MSA)Floodfill Algorithm (FFA)来实现这一点。通过Ramer–Douglas–Peucker Algorithm (RDPA)简化所得点。

  • MAA: https://stackoverflow.com/a/25875512/2577116
  • FFA: http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool/
  • RDPA: https://stackoverflow.com/a/22516982/2577116
  • (平滑:https://stackoverflow.com/a/7058606/2577116)

我把所有东西放在这个jsFiddle中。


步骤:

  1. 在用户完成自由绘图后获取路径对象
  2. 从base64路径创建图像
  3. 转换为二值图像(只有0和255像素,不透明)
  4. 在0,0位置应用FFA,颜色随机,保存颜色
  5. 转到下一个像素
  6. 如果像素已知泛洪填充颜色或路径颜色(黑色),移动到下一个
  7. 否则用新的随机颜色填充,保存颜色
  8. 移动所有像素,重复5 -7。
  9. 删除索引1上保存的颜色(它是路径轮廓周围的颜色(填充),所以它既不是路径也不是洞)
  10. 对所有其他颜色应用MSA并简化结果点(使用DPA)
  11. 从简化点创建多边形或…
  12. …平滑点并创建路径
  13. 添加到画布,删除输入路径
  14. :完成)

为了更简单的代码,我的随机颜色目前只创建灰色阴影。R=G=B和A=255允许更简单的检查。另一方面,这个解限制了轮廓的最大值。254个孔(256个灰度-路径颜色(0)-填充颜色(无孔))。如果需要更多,扩展代码以创建R, G, B甚至a的随机值也没有问题。不要忘记采用相应的颜色检查;)

整个算法可能没有针对性能进行优化,但老实说,我认为目前没有必要这样做。对于我的用例来说已经足够快了。无论如何,如果有人有关于优化的提示,我很高兴听到/读到:)

最佳选择

如果你用你的代码画Blobs,那么最简单的&最好的方法是将每个blob(和子blob)分解成它的组成部分Bezier曲线。FabricJS是开源的,所以你可以看到他们是如何创建曲线的——因此你可以如何分解曲线。结果将是一打左右的贝塞尔曲线,很容易重画或导航。如果你需要导航贝塞尔曲线的帮助,请参阅本教程,介绍沿着路径导航。

其他选择

你需要得到像素信息,所以你需要context.drawImage你的织物Blob到本地画布上,并使用context.getImagedata来获取像素信息。

假设:

  • 所有像素不是白色就是黑色。
  • 斑点为黑色:rgba(0,0,0,255)
  • 斑点外部为白色:rgba(255,255,255,255)
  • 斑点中的孔为白色:rgba(255,255,255,255)

寻找blob &孔路径:

  1. 加载imageData: context.getImageData(0,0,canvas.width,canvas.height)

  2. 在图像的周长上找到一个白色像素

  3. 使用泛洪填充算法(FFA)将外层白色替换为透明

  4. 使用行进方块算法(MSA)找到最外层的blob周长并保存blob路径

  5. 使用泛洪填充算法来填充你在#4中发现的斑点。这使得外部斑点对下一轮MSA"不可见"。在这一点上,你只有白洞——其他一切都是透明的。

  6. 使用行进平方算法(MSA)找到下一个白洞的周长并保存该洞的路径

  7. 使用泛洪填充算法用透明度填充#6中的白洞。这使得下一轮MSA无法看到这个洞

  8. 重复#6 找到每一个剩下的白洞

  9. 如果MSA报告没有像素,则完成。

为了提高效率,可以在后续步骤中重复使用步骤#1中的imageData。您可以在完成所有步骤后放弃imageData。

因为blob是曲线,你会发现你的blob路径包含许多点。您可以使用路径点缩减算法将这些点简化为更少的点。

最新更新