您的位置  > 互联网

J.,:低多边形风格概述..定义及简介

在视觉艺术中,使用尽可能少的多边形来表达特定图像的艺术风格称为低多边形风格。 低多边形风格因其对硬件友好、视觉冲击力强(高对比度)、风格简洁等特点,近年来越来越流行。 越来越多的设计师青睐它。 今天这个艺术风格领域的资深人物是J.,以下是他的一些作品

0.1。 发展历程

低多边形艺术风格最初可以追溯到计算机性能不足以支持大规模3D渲染的时代。 当时游戏模型等往往都不能很详细。 因为计算机以三角形面片为单位渲染 3D 模型。 ,过多的三角形面片往往会带来巨大的渲染负担。 因此,Low Poly(低多边形)是当时由于3D渲染技术较差而被迫采取的方法。

时至今日,低多边形艺术风格在很多需要实时3D渲染的设备中,甚至在动画电影中仍然可以看到,但它的含义与过去有所不同。 虽然有些场合仍然需要快速的实时3D渲染,但硬件设备的发展也能在一定程度上满足这种需求,因此低多边形美术风格的回潮很大程度上跟随了审美取向的变化。 随着生活节奏的加快,近年来简约的艺术风格往往能够迅速抓住美学家的眼球,让我们暂时忘记生活的琐碎。 Metro风格同时兴起也是一个证明。

该风格在3D领域有越来越多的应用,比如游戏,(见上图)等都采用了这种艺术风格。 随着低多边形风格在3D领域越来越受到青睐,平面设计领域也逐渐尝试引入这种风格(见下图,ppt模板)。

1. 过滤想法1.0。 概述

我们的目的是对给定图像进行低多边形​​风格化,输入图像,并输出处理后的图像。 处理应包括以下两个步骤:

按照一定的方式从输入图像中选择点,并将这些点按照一定的方式连接起来,从而实现网格的形成。 对网格内的点和边界(分割线)上的点进行着色,着色应接近原图像相应区域的色调。

为了使输出图像尽可能真实地还原原始图像的表现内容,我们应该设计合理的

由于我们只需要处理单个图像,处理速度不是我们的首要任务,因此我们实现了这个过滤器。

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 1
    1 1 1 2 2 3 4 3 2 2 1 1 1
    1 1 2 3 4 4 9 4 4 3 2 1 1
    1 2 3 4 9 9 9 9 9 4 3 2 1
    1 2 4 9 9 9 9 9 9 9 4 2 1
    2 3 4 9 9 9 9 9 9 9 4 3 2
    3 4 9 9 9 9 9 9 9 9 9 4 3
    2 3 4 9 9 9 9 9 9 9 4 3 2
    1 2 4 9 9 9 9 9 9 9 4 2 1
    1 2 3 4 9 9 9 9 9 4 3 2 1
    1 1 2 3 4 4 9 4 4 3 2 1 1
    1 1 1 2 2 3 4 3 2 2 1 1 1
    1 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 三角测量

该方法是一种非常经典的有限元网格划分方法。 其以最小角度最大化为目标,总能让分割出来的三角形色块在视觉上显得更加饱满。 比较经典的网格划分方法是-法,其算法基本流程如下:

构造一个覆盖所有散点的超三角形,将这个超三角形放入三角形链表中,插入散点,检查三角形链表中“外接圆包含散点”的三角形,删除它们的公共边,然后连接这些三角形的散点和端点形成新的三角形。 根据优化准则对新三角形进行优化,并将结果存储在三角形链表中。 返回步骤2,继续检查其他散点,直到插入所有散点。

三角测量的实现代码如下:

%% 多边形剖分
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

其中,就是我们自定义的连接函数:

function img=plotLine(img,x1,y1,x2,y2,marker)
    dx=x1-x2;dy=y1-y2;
    if abs(dx)>=abs(dy)
        try
            kk=dy/dx;
        catch
            img(y1:y2,x1)=img(y1:y2,x1)+marker;return
        end
        if x2>x1
            for i=x1:x2
                img(round(y1+kk*(i-x1)),i)=img(round(y1+kk*(i-x1)),i)+marker;
            end
        else
            for i=x2:x1
                img(round(y2+kk*(i-x2)),i)=img(round(y2+kk*(i-x2)),i)+marker;
            end
        end
    else
        try
            kk=dx/dy;
        catch
            img(y1,x1:x2)=img(y1,x1:x2)+marker;return
        end
        if y2>y1
            for i=y1:y2
                img(i,round(x1+kk*(i-y1)))=img(i,round(x1+kk*(i-y1)))+marker;
            end
        else
            for i=y2:y1
                img(i,round(x2+kk*(i-y2)))=img(i,round(x2+kk*(i-y2)))+marker;
            end
        end
    end
end

函数中使用try-catch是为了避免出现斜率趋于无穷大的情况。 当然,该函数仍然可以用连接线等经典算法代替,只需对代码稍作修改即可。 相关算法是计算机图形学的基础内容。 ,不再。

的连接结果如下:

1.2.2 连线贪婪优化

为了更好地使多边形边界更加接近原始图像中所表示的物体的轮廓,我们还可以考虑对连接进行适当的优化。 我们可以定义一个偏差值来描述多边形边界与原始图像中轮廓线的偏差。 理论上,可以将原始图像轮廓上的所有像素点到多边形边界的最小距离的平均值(根据轮廓灰度进行加权平均)作为偏差值。 事实上,这种方法非常耗时。 为此,我们可以在原始图像轮廓上添加一个值,随机选择点,形成检查点集,只需计算这些检查点到多边形边界的平均最小距离即可。 优化思路如下:

选择两个具有共同边的三角形,可以形成凸四边形。 删除原来三角形的公共边,将原来三角形的非公共顶点连接起来,形成两个新三角形。 比较新旧划分方法带来的偏差值,如果新方法带来的偏差值较小,则使用新方法,否则丢弃。 再次选择两个三角形,返回步骤1,直到尝试次数足够或偏差值在满意的范围内。 1.3. 着色算法:

在低多边形风格的艺术中,色块内的颜色相对均匀。 这种统一包括同一色系内的渐变(如明暗变化)和同一颜色(所有像素的RGB值完全相同)。 无论采用哪种着色方式,着色都是以色块为单位进行的,这就需要我们首先标记某个色块内的所有像素点。 完成色块内的着色后,我们还应该对多边形的边界线进行着色。 这里我们只需要取相邻色块的值即可。 只是颜色。

1.3.1 色块标记

色块中的像素是相连的,这些像素构成一个连通域。 这里需要确定并标记所划分的四连通域(即每个像素点上下左右方向都认为是连通的,对角线不认为是连通的,所有这样的连通域组成的一个区域)点称为四连通域)。 最常用的确定连通域的算法是他在 1992 年的书中提出的方法(M., and Linda G., and Robot, I, -, 1992, 28-48),内置函数使用该算法。 我们这里直接用这个函数来确定连通域(由于我们遇到的连通域都是凸的,所以还有优化的空间//不过工头催促...):

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

对连通域中的点着色后的图像如下: