前些天在知乎上看到有一个 《如何使用JavaScript生成lowpoly风格图像?》 的帖子,觉得十分有趣。同时心里想,能不能使用Java来实现呢?要不试试吧!
于是,在摸索了几天之后,终于做出来了。我整理了下,发布到 github 上面,感兴趣的同学可以clone下来玩玩!喜欢的话star一下吧!
原始图:
结果图:
关于生成的过程算法,原作者 羡辙 已经在那个知乎帖子上回答的很详细了,这里稍微整理下。
首先,从最终结果看,其实就是将原图片切割成一个个小三角形,每个三角形使用颜色填充。
显然,我们需要在原图上面先挑选一些点作为三角形的顶点,然后生成一个个小三角形。对于挑选顶点的方法待会再说明,现在假设已经挑选出来一些顶点了,我们应该怎么三角化呢?
你看,即便在顶点集相同的情况下,生成三角形的方式不止一种。经过对比,我们发现当三角形的每个角都基本相同的时候,这些三角形组成的图片最好看。对于上图来说,第一种三角化的结果最理想。
我们可以使用 Delaunay 算法来实现点集的三角化。感兴趣的同学可以深入研究下,这里不展开辣!值得一提的是,在摸索的过程中,我尝试了很多种开源的Delaunay Java实现,但是不知道哪里不对,都没有成功…于是在看了这个 Javascript实现 之后,觉得代码量很小,于是乎便参照它写了个 Java实现 。
现在,三角化的问题我们解决了,那我们应该挑选哪些点作为顶点集呢?随机挑选点的做法会破换掉原图里面的边缘特性,所以应该挑选原图里面边缘上的点。但是如果仅仅挑选边缘点最终三角化后会有很多尖锐的三角形,因此除了挑选边缘上的点,我们还应该挑选一定量的非边缘点。
但怎么确定图片里面的边缘呢?这里我们可以使用 Canny边缘检测算法 ,在实现上我使用了 Tom Gibara 的开源实现。大家如果想了解下这个算法,可以看下 这篇文章 。
这样我们就基本完成low-poly的过程了,总结下就是:
其中第四步中,三角形的颜色可以采用三角形重心的颜色来填充。
以上。