简介
本系统是由粒子系统组成的图像自动生成系统,单个粒子在画面内自由游走,粒子间彼此相连,最后可生成网状的风格化图片,产生“粒子编织”的丝网效果。用户可以选择更改图片,重新绘制,更改粒子群数量,更改粒子初始位置,更改粒子连线数,更改颜色模式等与粒子系统交互。最后呈现出一幅用户期望的风格化作品。
用户可以直观地看到粒子游走聚合的过程
部分作品展示:
操作指南
系统起始默认进行2200个点的图像生成,需要耐心等待,所有粒子位置确定后可以进行按钮选择交互。
系统亮点
1.将《代码本色》中粒子系统框架,自治智能体思想以及细胞自动机思想用来生成风格化图片,生成图片的过程中,每个粒子都像一个独立地生命体,产生一种“群体编织”生成图片的视觉效果。
2.系统具有随机性,虽然生成图片效果类似,但是每张图片又不尽相同,增加了生成效果的多样性,而不是单一的。
3.操作界面简洁友好。
创作过程及技术要点
创作的初始我是想基于遗传算法做一些可视化的艺术效果,仔细阅读了《代码本色》遗传算法那一章的内容之后,因为遗传算法都是基于一定的标准对种群进行筛选,最后达到一个目标,筛选出一个符合目标的群体,所以我首先想到的是对图片的拟合。于是我首先读入了一张图片,然后把它分成很多格,读取每一格内的RGB(注:一开始不知道怎么直接读取RGB值,只能读到color类型的值,后来发现其实只要利用red()函数就可以转换R值了),紧接着我就发现了问题,遗传算法难以直接拟合整张图,因为整张图的颜色无法作为一个筛选的标准,只能以每一格的RGB值作为筛选标准,也就是说为每一格都要创造一个群体,rgb的范围是0到255,这样每一格的遗传进化就要很久并且有很大计算量,何况一张图片还有那么多的格子。所以只好放弃了遗传算法拟合图片的想法,但是却因此想到了利用粒子系统去拟合图片的想法。结合《代码本色》全书:“以程序模仿自然生命系统 ”的思想,我想到制作一个有“生命力”的图像风格化(拟合)系统。
于是我想到《代码本色》中多次出现的模仿种群的粒子系统,于是我仔细阅读了《代码本色》第四章粒子系统,并仿写了程序,作为本系统的总框架。
编写粒子系统的要点在于,我首先编写了一个Point类,用来定义每一个粒子的行为,在其中编入Position(位置),Velocity(速度)和Acceleration(加速度)性质,并且加入update函数刷新粒子的位置,控制每个粒子的移动。然后编写了PointSystem类用来管理整个粒子系统。然后利用一个长度可变数组ArrayList来存放粒子。ArrayList类,这是一种更高级的对象列表管理方法,可以动态管理数组。在《代码本色》中提到正向遍历的过程中删除元素可能导致遍历漏掉一个元素,所以利用ArrayList遍历数组同时需要添加删除其中内容时,最好采用反向遍历。(同时,《代码本色》还着重讲解了迭代器 iterator() 的应用,但是不知道为什么,我的processing始终显示不存在 iterator() 所以我的代码中没有用到迭代器。)
在每次刷新时,我都会利用PVector.random2D()创建新的加速度方向(random2D()函数返回一个长度为1、方向随机的向量),再利用random函数修改加速度大小,最后更新速度和位置,同时设置topspeed限制速度大小。
然后我就获得了一个会在空间中随机游走的粒子系统。计算每个粒子间的距离,小于40就进行连线,一开始的连线都是纯色,后来想到距离越大透明度越大,效果好了很多。
然后就是如何去拟合图片了,参考细胞自动机的思想,那么我们需要设定一个规则来控制每个粒子的运动。之前看过一个关于利用processing滤镜和蒙版风格化图片的文章(http://blog.sina.com.cn/s/blog_c27fbb1b0101yj96.html)里面用到portrait.filter(GRAY),将 图片变成灰阶,然后用portrait.filter(POSTERIZE,4),进一步把图像分色,即图片原本含有很多种灰阶颜色,这一步把所有这些颜色归纳为4种。于是我想到也可以利用这种方法将图片分色,深色的地方聚集粒子多,浅色的地方聚集粒子相对较少。我首先写的是,在粒子游走的过程中让粒子实时判断自己所处位置的颜色,如果灰度超过一定的值就会停止更新位置,因为初始位置随机,这样会呈现一些聚集性,但是这显然是不够的。每个范围内粒子的总数量是没办法通过粒子本身洞见的,怎么创造一个适用于单个粒子的规则呢?于是我想到了细胞自动机,通过判断邻居的状态调整自己的状态,我也可以为这个系统中的粒子添加邻居,颜色越深的地方邻居可以越多,颜色越浅的地方邻居越少,每个粒子通过判断当前位置的灰度值和邻居的数量就可以判断自己是否需要停下。
于是我在PointSystem类中的DrawLine(连线函数)中加入计算邻居的语句,如果两点距离小于4,就调用该粒子的AddNeighbor 函数。然后在Point类中的Update函数里添加判断
点出现了一定的聚集性。通过调整参数,修改背景颜色等等,拟合度也就越来越好。
接下来就是对系统的优化,首先我发现在背景放大以后,有很多粒子位于画面边缘或者逃出界面。所以在Update中增加判断代码,如果点的位置位于规定范围外就重新初始化位置位于图片内。减少了点的逃逸,画面的拟合度进一步提升。
考虑到可能有一些点处于点比较密集的部分,可能在附近兜兜转转很久都找不到合适的位置,于是我增加了生存时间属性,每一帧增加1,如果点的生存时间超过500次,就给加速度一个很大的反向值,不限制最大速度,让该粒子大调一次位置。
然后就是对于运行算法的优化,我的粒子群数量都在2000左右,计算量很大,系统不可避免地变慢,有什么办法可以减少系统的负担呢。我一开始只有DrawLine函数,即使在所有粒子位置都确定的情况下,还是会不断计算两点距离进行连线。于是我想到先判断所有点是否停止运动,如果全部停止运动,就把最后一次进行连线的点以及距离存入动态数组,然后利用DrawLineStop函数进行直接绘制,不必再计算每个点间的距离。这样的优化一定程度上加快运行结束后使用UI的响应时间。
本来是想用鼠标与“织网”进行一些弹力交互的,虽然尽力优化了系统速度,但是点数这么多的粒子系统响应速度还是非常慢的,显然不可能进行很复杂的交互了。所以我就把交互的重点都放在UI上了。
本来是想使用controlP5的GUI的,但是试了一下发现不能修改上面的字体和大小,风格和目前的系统也不太搭。索性就自己写了简单的UI,是排列在下方的,一排颜色协调的圆,鼠标移到上面,显示功能,点击实现功能,具体功能在操做介绍里都有。
这里的技术点就是在调整UI的位置和颜色时可以使用processing的调整模式,可以实时看到效果。在写鼠标响应时我一开始是判断mouseclick和位置,如果鼠标按下了并且位置满足按钮的位置就调用函数。在粒子数量不多时没有问题,但是粒子数量一多,响应变慢,就出现你可能在那个位置点击了鼠标,但是你看到没反应就移开了,系统就发现按鼠标的位置不在按钮内,也就不执行。于是我就改成了在mouseclick函数内检测鼠标位置,判断是否点击了按钮位置,虽然依然响应很慢,但不会出现点击了不执行的情况。
以上就是本系统的技术实现过程,当然在编写过程中遇到的问题远不止这些,还有很多繁琐的细节逻辑问题,这里不再一一赘述。
待解决问题
虽然完全自己一点点编写出一个图像生成系统,过程不易也很有成就感,但还是要承认自己编写的系统不够成熟,存在一些问题。
虽然尽己所能优化了计算,但是在点数量多的时候响应速度还是会很慢;粒子是基于颜色灰度进行聚集的,这就代表选取图片需要有比较高的对比度区分度,如果是画面杂乱的图片是难以进行风格化的;程序还是略显杂乱;
参考文献
《代码本色:用编程模拟自然系统》——Daniel Shiffman
Processing中用滤镜和蒙版做出文字头像(text portrait)——http://blog.sina.com.cn/s/blog_c27fbb1b0101yj96.html
https://processing.org/
http://complexification.net/gallery/
iprocessing.cn/
其他同学的优秀作品
《Magic Network》:一个小孩都能玩的神经网络交互系统
链接:https://blog.csdn.net/leonardwyh789/article/details/89600881
系统设计的切入点非常好,选在了概念比较抽象的深度学习方面,并且通过可视化的交互方式引导用户去搭建神经网络,可以很好的帮助用户了解神经网络,极具现实意义;操作界面友好,拉近用户和神经网络的距离感;
用Processing制作一个「生态瓶」
链接:https://zhuanlan.zhihu.com/p/64726213
很好的将代码本色的核心内容加以运用,很好地体现了用编程模仿生态系统的想法;系统操做友好,并且趣味性强。
Processing || FREE CLOTH自由布料
链接:https://mp.weixin.qq.com/s/c5GOP1Yv13Ko3xVeTkJoKQ
介绍了processing中toxilibs库,实现了非常迷幻绚丽的物理效果,增加了我对processing可能性的认识;博文中有一些自己的思考,基于原本的例子尝试增加了更好的效果。