昨天弄了半天的有限元网格,今天正式开始尝试一下用Mathematica制作一个Low Ploy风格的图片出来,虽然赶不上犀利的图像处理工具,但是抽象艺术谁也说不好嘛。
1.Low Poly
最早知道Low Poly这个图片风格是从doyoudo上面看到的。这个网站做的还是不错的,专门讲解一些图形图像制作和视频编辑的。直到看到了上面的教程,才知道有Low Poly风格这么一说,然后去Google了一下发现果然我平时使用的图片基本都是这种风格的,直接收藏了很多艺术家的作品。
这里下面是一些Low Poly风格的设计大师:
- Timothy J. Reynolds
Website | Dribbble - Jeremiah Shaw
Dribbble - Jona Dinges
Website | Dribbble - JR Schmidt
Cargo | Dribbble - Erwin Kho
Website | Dribbble
那么具体到什么是Low Ploy风格呢,就是以低多边形构建的图形,也就是用基本的三角形和四边形绘制想要的图形,下面这张图就是一张Low Ploy风格的图片。
看上去非常不错吧,但是这张图的构造确实比较简单,用最基本的多边形完成了这张图片的创建。那么我们现在就用Mathematica来创建创建这样风格的图片。
2.基本思路
如果要产生这样一张图片,最基本的是什么呢?其实就是创建最基本的三角形,具体可以看一看doyoudo上面的视频,具体到MMA,需要下面的步骤:
- 图片导入;
- 三角形离散;
- 获得每一个三角形的位置;
- 计算这个三角形区域内平均颜色;
- 采用平均颜色填充三角形区域;
上面是最简单的Low Ploy的流程,需要得到更好的效果肯定是要手动调整,因为在网格离散的过程中不能区分图片中的主要对象。
3.MMA实现
首先我们需要一张图片,我从upsplash上面搜索了一张风景照,这个风景照的原始照片有7M大小,第一次像素替换的时候电脑直接死机了,所以我用图片压缩工具压缩了一下,将图片压缩到238KB左右。然后导入MMA:
1 2 3 |
Clear["Global`*"] Needs["NDSolve`FEM`"] pic = Import[NotebookDirectory[] <> "pic.jpg"] |
得到下面的图片:
这个图片准确来说不适合做Low Ploy风格的图片,因为内容太多了,且山水连成一片。这里只是试验所以就不挑选其他图片了。
获取图片的尺度,并采用BoundaryMeshRegion[ ]函数将相同尺度矩形进行离散:
1 2 3 |
dim = ImageDimensions[pic]; rop = BoundaryMeshRegion[{{0, 0}, {dim[[1]], 0}, {dim[[1]], dim[[2]]}, {0, dim[[2]]}}, Line[{1, 2, 3, 4, 1}]]; oop = TriangulateMesh[rop, MaxCellMeasure -> 20000] |
因为我电脑的运算能力有限,因此这里的MaxCellMeasure值设置的比较大,因此里散出来的网格也是相当的夸张:
接下来的操作相对来说比较复杂一点。一步一步的操作:
1 2 |
{pts, areas} = {MeshCoordinates[oop], MeshCells[oop, 2]}; |
运行过上面的命令后可以到到上面网格图片的坐标和区域的对应图,这样我们可以通过areas计算区域的位置,然后我们要进行一步比较重要的操作,就是用单个区域合成一个alpha通道:
1 2 3 |
newpic = pic; base = ColorReplace[pic, _ -> White]; hg = HighlightImage[base, MeshRegion[pts, areas[[7]]], "HighlightColor" -> Black] |
先将原图复制一份,然后替换图片底色成为白色,之后将三角形区域areas的7号区域与白色叠合,得到下图:
在经过二值化处理后反色,就可得到7号三角形区域的通道图像了:
1 2 |
alpha = ColorNegate[Binarize[hg, 0.5]] |
通道图如下:
经过下面的处理后,我们就可以计算这个通道的平均颜色了,计算完成之后,使用像素替换命令进行像素替换:
1 2 |
mcolor = Mean[PixelValue[newpic, alpha]]; newpic = ReplacePixelValue[newpic, alpha -> RGBColor[mcolor]]; |
这样处理之后图片就变成了下图:
这样我们完成了一步的操作,剩下的就是采用循环调整的三角形区域进行调整了:
上面这张图就是运算完成之后的图片了,这个效果嘛是非常艺术啊。
4.进度条
如果有兴趣的话,可以把文章拖到最后下载文件自己试一试,不过因为我电脑能力有限就不再去试验了,主要原因是这个图片太大了,压缩过了像素也是1920级别的。所以在循环替换的时候,不知道进度怎么样了是很焦虑的,我们需要一个进度条:
1 2 3 |
ProgressIndicator[Dynamic[progress], {1, Length[areas]}] Dynamic[progress] Length[areas] |
将上面的代码放在循环外面,然后将下面的代码放在循环里面:
1 2 |
progress = i; |
这里的循环变量为i,不同的i即可有不同的进度条了:
在循环过程中再也不用一直看着任务管理器了。
5.End小结
这个真是不容易弄出来,主要是在循环替换像素的时候电脑特别卡。虽然效果不怎么样吧,起码也是费了半天劲分析了一下图像的拼合和颜色替换,值得记录一下。本文基本是在看帮助文档的基础上完成了,虽然MMA论坛也是有高手进行颜色替换,但是这个里面最复杂的就是在选定区域内用平均颜色进行替换,这是最难的。
给出一个文中代码的下载链接:UO32m0.zip