0. 低多边形风格概述

0.0. 定义及简介

视觉艺术中,采取尽量少的多边形对某一特定形象进行表现的艺术风格称为低多边形风格.低多边形风格以其硬件友好,视觉冲击(高对比度)强,风格简约而在近年来受到越来越多的设计者的青睐.现今该艺术风格领域的元老级人物属Timothy J.Reynolds,这里是他的一些作品

0.1. 发展历史

低多边形艺术风格最初可以追溯到计算机性能不足以支持大规模3d渲染的年代,那时的游戏模型等等往往不能做到十分精细.由于计算机进行3d模型的渲染是以三角形面片为单位进行的,过多的三角形面片往往会带来巨大的渲染负担,因此,low poly(低多边形)是当时迫于3d渲染技术不佳而被迫采取的手段.
时至今日,低多边形的美术风格仍然可见于诸多需要进行实时3d渲染的设备,甚至是动画成片中,但是其意义已不同于以往.虽然现今部分场合仍需要快速实时的3d渲染,但硬件设备的发展也能在一定程度上满足这种需要,因此低多边形艺术风格的再兴起很大程度上是跟随了审美取向的变化的.随着生活节奏的加快,近年来简约的艺术风格往往能迅速的抓住审美者的眼球,使我们暂时忘记琐碎的生活,同时兴起的metro风格也是一个佐证.

lowPoly风格在3d领域有着越来越广的应用,如游戏<纪念碑谷>,<纸境奇缘>(见上图)等均采取了这一艺术风格.随着低多边形风格在3d领域获得越来越多的青睐,平面设计领域也逐渐尝试引入该风格(见下图,ppt模板).

1. 滤镜思路

1.0. 总述

我们的目的是对一张给定的图片进行低多边形风格化处理,输入一张图片,输出一张处理后的图片.该处理应当包含如下两个步骤:

  1. 从输入图片中按一定方式选点,并按一定方式连接这些点,实现网格化.
  2. 对网格内的点和边界(分割线)上的点着色,着色应接近原图对应区域色调

为使得输出图片尽可能真实还原原图的表现内容,我们应当设计合理的

  • 选点算法
  • 连线算法
  • 着色方法

由于我们只需要处理单张图片,因此处理速度不是我们优先考虑的问题,采用Matlab实现该滤镜.

1.1. 选点算法

选择多边形的顶点位置,这里需要注意的问题有如下几点:

  • 选点贴合原图轮廓,避免连线后表现内容走形
  • 选点不能过于密集,避免产生大量小色块
  • 选点不能过于疏散,避免出现过大的色块

对于第一个问题,首先需要描绘原图中的形象轮廓,所谓轮廓就是指颜色突变处.这里只需用核 [-0.7,-2.1,-0.7;0,0,0;0.7,2.1,0.7]及其转置 对原图的RGB通道分别进行卷积即可(相当于计算3*3区域内上下/左右像素点RGB通道亮度之差),这里我们考虑了原图的色调可能比较一致,即某一通道或者某几个通道的特定组合上色彩区分不大,因此可以自定义这些通道对轮廓描绘过程的权重影响.代码如下:

% 读入图像
inputImg=imread('Lenna.jpg')
% 设置描边卷积核(边界检验范围)
edgeKernel=[-0.7,-2.1,-0.7;0,0,0;0.7,2.1,0.7];
% 设置RGB通道边界权重
weight=[0.2989,0.5807,0.1140];
% 拆分RGB通道并描边
R=inputImg(:,:,1); G=inputImg(:,:,2); B=inputImg(:,:,3); [l,h,~]=size(inputImg);
rEdge=(weight(1)*imfilter(R,edgeKernel,'conv')+weight(1)*imfilter(R,edgeKernel','conv'));
gEdge=(weight(2)*imfilter(G,edgeKernel,'conv')+weight(2)*imfilter(G,edgeKernel','conv'));
bEdge=(weight(3)*imfilter(B,edgeKernel,'conv')+weight(3)*imfilter(B,edgeKernel','conv'));

我们可以基于这些轮廓生成一张优先级热图,在高优先级区(数值较大)的位置优先选点,当然我们也可以为这种选择添加一定的随机性(利用轮廓生成热图时矩阵的每个元素乘以一个随机数,随机数的范围可以自定义).另外,我们有必要在图像外部选择一些点,它们与图像内的点的连线可以让图像上下左右四个边界处的表现不显得突兀,因此该热图应为轮廓矩阵的增广.除此之外,为了避免选点过密的问题,每当一个点被选中,都应该降低优先级热图上此点和此点附近的点的数值(即潜在被选优先级).代码如下:

% 设置选点个数:
pick_count=750;%正常选点个数(这些点的连线用于勾勒边缘)
% 设置噪点权重(0~1)
noise_weight=0.1;
% 设置概率缩减核(大小必须是奇数*奇数,这样可以使得被选中点处在核的正中):
possibility_density_shrinker=[...1 1 1 1 1 2 3 2 1 1 1 1 11 1 1 2 2 3 4 3 2 2 1 1 11 1 2 3 4 4 9 4 4 3 2 1 11 2 3 4 9 9 9 9 9 4 3 2 11 2 4 9 9 9 9 9 9 9 4 2 12 3 4 9 9 9 9 9 9 9 4 3 23 4 9 9 9 9 9 9 9 9 9 4 32 3 4 9 9 9 9 9 9 9 4 3 21 2 4 9 9 9 9 9 9 9 4 2 11 2 3 4 9 9 9 9 9 4 3 2 11 1 2 3 4 4 9 4 4 3 2 1 11 1 1 2 2 3 4 3 2 2 1 1 11 1 1 1 1 2 3 2 1 1 1 1 1].^2;
% 生成原始概率图(应为增广矩阵),基于此图的概率选边缘点
[hf,lf]=size(possibility_density_shrinker);
probMap=double(rEdge+gEdge+bEdge); averange_pos=mean(probMap(:)); lt=4*lf+l; ht=4*hf+h;
probMap=[zeros(lf,ht);zeros(lf,hf),(2+2*noise_weight)*averange_pos*rand(lf,ht-2*hf),zeros(lf,hf);zeros(l,hf),(2+2*noise_weight)*averange_pos*rand(l,hf),probMap,(2+2*noise_weight)*averange_pos*rand(l,hf),zeros(l,hf);zeros(lf,hf),(2+2*noise_weight)*averange_pos*rand(lf,ht-2*hf),zeros(lf,hf);zeros(lf,ht)];
probMap=double(probMap).*(1-noise_weight+noise_weight*rand(size(probMap)));
figure,imshow(uint8(probMap));
segPoint=zeros(size(probMap));
coordList=zeros(pick_count,2);
%开始选点:
for i=1:pick_count[~,sub]=max(probMap(:));coordX=ceil(sub/(lt)); coordY=mod(sub,lt);segPoint(coordY,coordX)=1;coordList(i,1)=coordX; coordList(i,2)=coordY;% 缩减已选点附近的点被选中的概率(避免选点过密及重复选点)probMap(coordY-(hf-1)/2:coordY+(hf-1)/2,coordX-(lf-1)/2:coordX+(lf-1)/2)=probMap(coordY-(hf-1)/2:coordY+(hf-1)/2,coordX-(lf-1)/2:coordX+(lf-1)/2)./double(possibility_density_shrinker); probMap(coordY,coordX)=0;
end

雷娜图原图及处理结果如下:

1.2. 连线算法

选择完毕所有点后就可以开始连线了,这里提供两种连线思路:

1.2.1 Delaunay三角剖分
该方法是十分经典的有限元网格剖分方法,其最大化最小角的目标总能使得剖分出的三角形色块在视觉上表现的较为饱满.比较经典的剖分方法是Bowyer-Watson方法,该算法的基本流程如下:

  1. 构造超级三角形,覆盖所有散点,将此超级三角形放入三角形链表
  2. 插入一个散点,检查三角形链表中”外接圆包含该散点”的三角形,删去它们的公共边,然后连接该散点和这些三角形的端点,形成新的三角形
  3. 根据优化准则优化新三角形并将结果存储在三角形链表中
  4. 回到第2步,继续检查其它散点,直至全部散点插入完成

Delaunay三角剖分的实现代码如下:

%% 多边形剖分
tri=delaunay(coordList(:,1),coordList(:,2));
divMap=segPoint;
for i=1:length(tri)divMap=plotLine(divMap,coordList(tri(i,1),1),coordList(tri(i,1),2),coordList(tri(i,2),1),coordList(tri(i,2),2),1);divMap=plotLine(divMap,coordList(tri(i,2),1),coordList(tri(i,2),2),coordList(tri(i,3),1),coordList(tri(i,3),2),1);divMap=plotLine(divMap,coordList(tri(i,3),1),coordList(tri(i,3),2),coordList(tri(i,1),1),coordList(tri(i,1),2),1);
end

其中,plotLine是我们自定义的连线函数:

function img=plotLine(img,x1,y1,x2,y2,marker)dx=x1-x2;dy=y1-y2;if abs(dx)>=abs(dy)trykk=dy/dx;catchimg(y1:y2,x1)=img(y1:y2,x1)+marker;returnendif x2>x1for i=x1:x2img(round(y1+kk*(i-x1)),i)=img(round(y1+kk*(i-x1)),i)+marker;endelsefor i=x2:x1img(round(y2+kk*(i-x2)),i)=img(round(y2+kk*(i-x2)),i)+marker;endendelsetrykk=dx/dy;catchimg(y1,x1:x2)=img(y1,x1:x2)+marker;returnendif y2>y1for i=y1:y2img(i,round(x1+kk*(i-y1)))=img(i,round(x1+kk*(i-y1)))+marker;endelsefor i=y2:y1img(i,round(x2+kk*(i-y2)))=img(i,round(x2+kk*(i-y2)))+marker;endendend
end

plotLine函数中try-catch的使用是为了避开斜率趋∞∞\infty的情况,当然该函数仍然可以使用诸如Bresenham连线等经典算法代替,只需对代码稍加修改即可,相关算法是计算机图形学基础内容,不再赘述.
雷娜图的连线结果如下:

1.2.2 连线-贪心优化
为了更好地使得多边形的边界接近于原图中表现对象的轮廓,我们也可以考虑对连线进行适当的优化.我们可以定义一个偏离值来描述多边形边界与原图中轮廓线的偏离程度.理论上,原图轮廓上所有的像素点到多边形边界的最小距离的平均数(按轮廓灰度加权平均)可以充当偏离值,实际上这种做法十分费时.为此我们可以在原图轮廓线上随机选点构成校验点集,仅仅计算这些校验点到多边形边界的最小距离均值即可.优化思路如下:

  1. 选择两个具有公共边的三角形,且它们能够组成凸四边形,删去此公共边,连接原三角形的非公共顶点,形成两个新三角形.
  2. 比照新旧两种剖分方法带来的偏离值大小,若新方法带来的偏离值较小则使用新方法,反之舍弃.
  3. 重新选择两个三角形,返回步骤1,直至尝试次数足够或偏离值在满意的范围内.

1.3. 着色算法:

低多边形风格艺术中,色块内的颜色较为统一,这种统一有同色系内渐变(如明暗变化)和完全相同(所有像素的RGB值完全相同),无论是哪种着色方式,着色都是以色块为单位进行的,这就要求我们先标记出某一色块内所有的像素点.完成色块内的着色后还应对多边形的边界线进行着色,这里只需要取其相邻色块的颜色即可.
1.3.1 色块标记
色块内的像素点是相连的,这些像素点构成了一个连通域.这里我们需要确定并标记剖分后的四连通域(即认为每一个像素点是和上下左右相连的,斜对角方向的不算做相连,由全部这样相连的点构成的一块区域叫做四连通域).连通域判定最常用的算法是Haralick于1992年在其书中提出的方法(Haralick, Robert M., and Linda G. Shapiro, Computer and Robot Vision, Volume I, Addison-Wesley, 1992, 28-48),Matlab的内置函数bwlabel正是采用这一算法.我们这里直接采用该函数进行连通域判定(由于我们遇到的连通域都是凸的,这里仍有优化余地 //然而工头催收了……):

divMap=divMap(2*lf+1:2*lf+l,2*hf+1:2*hf+h);
% 先去掉之前添加的边框
[divDomain,domainCount]=bwlabel(2-divMap,4);
% 直接判定四连通域,输出分割图和连通域个数

1.3.2 对各连通域的内点着色
我们直接计算每个连通域内RGB通道亮度的算术均值(各点平权)作为目标图像中连通域内每个点的颜色,这种着色方法的优势在于迅速,缺点在于色块内没有颜色过渡,这里应视需要决定是否采用此方法.遍历各个连通域并按上述方法着色的代码如下:

outputImgR=zeros(size(R));
outputImgG=zeros(size(G));
outputImgB=zeros(size(B));
for i=1:domainCount
% 这里不要采用find函数,否则会拖慢处理速度outputImgR(divDomain==i)=mean(R(divDomain==i));outputImgB(divDomain==i)=mean(B(divDomain==i));outputImgG(divDomain==i)=mean(G(divDomain==i));
end

完成连通域内点着色后的图像如下:

【滤镜算法】低多边形风格介绍及Matlab实现相关推荐

  1. Blender从头开始装配和动画制作低多边形风格的FPS手臂

    Rigging and Animating Low Poly FPS Arms in Blender MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch 语言:英语 ...

  2. PS轻松打造低多边形风格图像

    大家好,今天来教大家一个低多边形风格的图像处理.低多边形风格介于抽象与象形之间,是一种表现力很强的插画类型,用于LOGO的设计也未尝不可.它的绘制过程也非常简单,尤其在AI中,利用三角色块一个个拼缀而 ...

  3. java lowpoly低多边形风格图片生成

    lowpoly风格的图片生成,java实现. 闲着没事干刷知乎,刷到这样一个问题http://www.zhihu.com/question/29856775 看看觉得还是挺好看的,那么,我也想提高b格 ...

  4. 低多边形(Low Poly)风格会不会成为移动游戏时代的8bit像素

    在iPhone进入游戏市场之前,大家都认为PC和主机游戏的画面的进化趋势是变得越来越逼真.有越来越多的多边形数.让游戏更贴近现实是游戏的核心进化趋势,所以制作者们在游戏中塞进更多的多边形,以实现更逼真 ...

  5. 绘制多边形_PS学习教程!教你绘制低多边形星空效果熊猫头像

    低多边形风格介于抽象与象形之间,是一种表现力很强的插画类型,用于LOGO的设计也未尝不可.它的绘制过程也非常简单,尤其在AI中,利用三角色块一个个拼缀而成即可,设计师要做的是对色彩的选择和控制,以便能 ...

  6. 【有利可图网】PS教程:制造低多边形熊猫头像

    低多边形风格介于抽象与象形之间,是一种表现力很强的插画类型,用于LOGO的设计也未尝不可.它的绘制过程也非常简单,尤其在AI中,利用三角色块一个个拼缀而成即可,设计师要做的是对色彩的选择和控制,以便能 ...

  7. 详细介绍用MATLAB实现基于A*算法的路径规划(附完整的代码,代码逐行进行解释)(一)--------A*算法简介和环境的创建

       本系列文章主要介绍基于A*算法的路径规划的实现,并使用MATLAB进行仿真演示.本文作为本系列的第一篇文章主要介绍如何进行环境的创建,还有一定要记得读前言!!! 本系列文章链接: ------- ...

  8. 模拟退火算法介绍及matlab实现

    模拟退火算法介绍及matlab实现 参数 待求解参数维度:D x i L x_{\text{i}}^L xiL​, x i U x_{\text{i}}^U xiU​:待求解参数的上下限 L:每一温度 ...

  9. matlab 思维进化算法,差分进化算法介绍及matlab实现

    引言 差分进化算法是基于群体智能理论的优化算法,是通过群体内个体间的合作与竞争而产生的智能优化搜索算法,它保留了基于种群的全局搜索策略,采用实数编码.基于差分的简单变异操作和"一对一&quo ...

最新文章

  1. linux日期日增,Linux日期
  2. 祝博客园里的所有朋友 新年快乐!
  3. 配置文件没有关闭保护模式_配置文件:PS自带的海量滤镜 | 照片调色宝典13
  4. MySQL安装步骤及相关问题解决
  5. Protocol Buffers java
  6. php日志导出oracle,一个php导出oracle库的php代码
  7. MySQL修改数据表存储引擎的3种方法介绍
  8. IoT---(1) 窄带物联网NB-IoT协议必须要了解的几个问题
  9. 一文读懂python数据分析_一文读懂聚类算法
  10. 第5章、解析Hello,world!知其然,更要知其所以然(从零开始学Android)
  11. 嵌入式物联网系统软硬件基础知识大全
  12. 手机点击android出现N,“安卓N”登场,会给手机带来哪些新功能
  13. 重装系统要钱吗?电脑重装系统需要多少钱?
  14. java心形动画效果_java swing实现动态心形图案的代码下载
  15. 浙江大学机械系制造所2010届毕业生…
  16. [QDialog]qt虚拟键盘的实现以及qdateedit实现打开虚拟键盘
  17. 沸点大前端组正式成员面试小问题
  18. 2.2.1 Nginx高性能负载均衡器
  19. 浏览器选择 html,select的最佳预设打造全兼容各浏览器select
  20. 关于POS终端安全 PCI做了哪些要求?

热门文章

  1. 下一轮WiFi革命来临:详解高通MU-MIMO技术(Multi-User Multiple-Input Multiple-Output多用户多入多出技术)
  2. 【华为机试真题 Python实现】机器人走迷宫
  3. minigui相关硬件加速添加方法
  4. 软件测试管理工具——禅道(安装、讲解)
  5. 跳跳棋【LCA】【二分】
  6. 算法笔记习题 7-1小节
  7. 百度为何力推直达号?为了移动商业化
  8. mysql随机日期_mysql插入随机日期
  9. 音频信号的基波和谐波介绍
  10. 基站定位查询api使用接口