实现SLIC算法生成像素画
前言
像素风最早出现在8bit的电子游戏中,受制于电脑内存大小以及显示色彩单一, 只能使用少量像素来呈现内容,却成就了不少经典的像素游戏。随着内存容量与屏幕分辨率的提升,内存与显示媒介的限制不再是问题,而像素风也慢慢演变成一种独特的创作风格。
像素画的一般的绘制流程包括了勾线、填色等,而逐个像素的绘制需要大量时间。一些流行的艺术方式,比如线描与绘画领域,都逐渐出现了自动化或半自动化生成的方法。本文将从零开始实现SLIC
[1]算法,并实现一款生成像素画工具。
什么是SLIC算法
像素画的绘制之所以不简单,是因为直接的下采样并不能准确的捕获关键像素,且容易导致丢失边缘信息,生成的像素画往往不尽人意。手工的勾线、填色,都是为了选取合适的像素点。由此,我们的问题变成了如何选取合适的像素点进行填色。
首先,引入一个概念——超像素。超像素是 2003 年 Xiaofeng Ren 提出和发展起来的图像分割技术,是指具有相似纹理、颜色、亮度等特征的相邻像素构成的有一定视觉意义的不规则像素块[1]。
通过将图片分割为超像素,可以得到相似的像素簇,相似的像素使用同一个颜色进行填充,得到的像素画会更合理。
超像素点分割的方法包括了提取轮廓、聚类、梯度上升等多种。论文[1]
提出的SLIC
超像素点分割算法(简单线性迭代聚类,simple linear iterative clustering
)就是其中一种,它基于K-means
聚类算法,根据像素的颜色和距离特征进行聚类来实现良好的分割结果,与若干种超像素点分割算法相比,SLIC
具有简单灵活、效果好、处理速度快等优势。
如何实现SLIC算法
SLIC
的基本流程如下:
图像预处理。
将图像从
RGB
颜色空间转换到CIE-Lab
颜色空间,Lab
颜色空间更符合人类对颜色的视觉感知。这个空间里的距离能反映人感觉到的颜色差别,相关计算更为准确。Lab
颜色空间同样具有三个通道,分别是l
,a
,b
,其中l
代表亮度,数值范围为[0,100]
,a
表示从绿色到红色的分量,数值范围为[-128,127]
,b
表示蓝色到黄色的分量,数值范围为[-128,127]
。RGB
和LAB
之间没有直接的转换公式,需要将RGB
转为XYZ
颜色空间再转为LAB
,代码见文末完整代码。初始化聚类中心。
根据参数确定超像素的数目,也就是需要划分为多少个区域。假设图片有
N
个像素点,预计分割为K
个超像素,每个超像素大小为N/K
,相邻中心距离为S=Sqr(N/K)
,得到K
个聚类坐标。优化初始聚类中心。在聚类中心的
3*3
邻域内选择梯度最小的像素点作为新的聚类中心。把图像看成二维离散函数,梯度也就是这个函数的求导,当相邻像素值有变化就会存在梯度,而在边缘上的像素点的梯度最大。将聚类中心挪到梯度最小的地方可以避免其落到边缘轮廓上,影响聚类效果。
离散梯度的梯度计算这里不做详细推导了,由于其中包含了若干*方与开方,计算量较大,一般会简化为用绝对值来*似*方和*方根的操作。简化后的计算坐标为
(i,j)
的像素点的梯度公式为:其中
(i+1,j)
与(i,j+1)
为像素右侧点与像素下方点的坐标。l(a,b)
为(a,b)
坐标上像素的亮度通道值l
。计算像素点与聚类中心的距离。
在聚类中心距离S的区域内
2S*2S
的邻域内计算像素点与每个聚类中心的距离。这里的距离使用的是欧式距离,总距离
D
由dc
颜色距离与ds
空间距离两部分组成。公式如下:如果直接将
l
,a
,b
,x
,y
拼接成一个矢量计算距离,当超像素的大小变化时,x
,y
的值可以取到非常大 ,比如如果一张图1000*1000
,空间距离可以达到1000*Sqr(2)
,而颜色距离最大仅10*Sqr(2)
,导致最终计算得到的距离值中,空间距离ds
权重占比过大。所以需要进行归一化,除以最大值即超像素点的初始宽度
S
,将值映射到[0,1]
。而颜色空间距离也会给到一个固定的值
m
来调节颜色距离与空间距离的影响权重,m
取值范围为[1,40]
。距离公式即变成了
当
m
越大,颜色空间除以m
后的值越小,即空间距离的权重越大,生成的像素会更为形状规则,当m
越小,颜色距离权重更大,超像素会在边缘更为紧凑,而形状大小较为不规则。像素点分类。
标记每个像素点的类别为距离其最小的聚类中心的类别。
重新计算聚类中心。
计算属于同一个聚类的所有像素点的*均向量值,重新得到聚类中心 。
迭代
4~6
的过程。直到旧聚类中心与新聚类中心的距离小于一定阈值或者达到一定迭代次数,一般来说,当迭代次数到达
10
,算法能够达到收敛。聚类优化。
迭代到最后,可能会出现与聚类中心不属于同一连通域的孤立像素点,可以使用到连通算法将其分配到最*的聚类标签。
论文中并未给出具体的实现算法。而本文的应用场景是生成像素画,会对像素进行下取样,并不会细化到每个像素,由此,本文不做聚类优化处理。
小小总结一下,SLIC算法流程大体与K-means
是一致的,不断迭代计算距离最小的聚类簇,不同的是只对聚类中心的S
距离内像素点进行计算,减少了不少的计算量。
生成像素画
基于SLIC
算法,我们已经可以把一张图划分为N
个超像素点。每个超像素中像素都是相*的。也就是说,每个像素都被归类为一个超像素,有一个聚类中心。那么将像素的颜色赋值为其聚类中心的颜色即得到我们想要的效果。
设定一定步长stride
,使用Canvas
,每隔stride
个像素,将像素赋值为其聚类中心的颜色,即得到最终的像素化结果。
而每个人对于像素画的主观感受是不一致的,为了让用户有更多的选择,得到自己满意的结果。可以暴露更多的人工干预参数,比如取消聚类优化的终止条件,改为由用户来设置迭代次数,以及最终取像素值的步长。人工设定的参数包括了
- 超像素点大小
blocksize
;blocksize
越小,超像素点分割越细腻。 - 迭代次数
iters
;iters
越大,分割结果更精准,计算时间越长。 - 颜色空间权重
weight
;weight
越大,颜色对于分割结果的影响越大。 - 取像素点步长
stride
;stride
越小,生成的像素图越接*超像素点,也就越细腻。
实现用户交互界面
作为一个工具,自然需要用户交互界面,前端界面基于HTML/Javascript/CSS
搭建,使用Canvas API
绘制图像内容,而用户交互面板选择的是dat.gui
[3] 库。dat.gui
是一个轻量级的图像化界面库,非常适用于参数的修改,常用作可视化 Demo 的演示。支持的参数类型包括了Number
、String
、Boolean
、自定义函数等。可以为不同的属性绑定相应的响应事件,当属性值改变时自动触发事件。
为生成像素化工具添加以下属性与事件:
- 当
iters、stride、blockSize、weight
(颜色空间权重m)参数变化时重新进行SLIC
算法的计算,并重新绘制计算结果; - 添加
Upload image
与Export image
按钮,支持用户上传图片与下载像素化后的图片;
在绘制图像的Canvas
画布层上叠加一层Canvas
画布,对算法的结果进行可视化,添加以下功能
grid
开关控制是否绘制像素网格;Centers
开关控制是否显示聚类中心;Contours
开关控制是否显示聚类边缘轮廓;
其中聚类中心点Centers
的绘制直接使用ctx.fillRect
传入中心点坐标即可。
超像素轮廓Contours
的绘制则需要先计算得到轮廓点。
可以对每个像素点与周围的8
个像素点进行比较,如果聚类中心不同的像素点个数大于2
,则代表着这个像素点周围有两个以上不同类别的点,则这个点为轮廓。效果如下:
最后,就得到一个简单的生成像素画工具了。
参考文献
[1] Achanta R, Shaji A, Smith K, Lucchi A, Fua P, Su ̈sstrunk S. SLIC superpixels. Technical Report. IVRG CVLAB; 2010.
[2] Gerstner T , Decarlo D , Alexa M , et al. Pixelated image abstraction with integrated user constraints[J]. Computers & graphics, 2013.
[3] https://github.com/dataarts/dat.gui
欢迎关注凹凸实验室博客:aotu.io
或者关注凹凸实验室公众号(AOTULabs),不定时推送文章:
实现SLIC算法生成像素画的更多相关文章
- 技术期刊 · 天光台高未百尺 | Uber 工程师的 JS 算法课;大数据时代的个人隐私;设计师的 Github;告别 PPT 工程师;从零开始实现的像素画
蒲公英 · JELLY技术期刊 Vol.42 这是一个最好的时代,多样化的平台给了所有人成长发展的机会,各种需求和解决需求的人让人大开眼界:但这也并不是完美的时代,"前端还需要懂什么算法?& ...
- 【资源分享】Gmod-Expression2 - 自定义像素画生成
*作者:BUI* 可自定义制作属于你的像素画(默认为Sans) 第77行的COLOR可编辑你想要的颜色(RGB值) 1,2,3,4分别代表第77行所定义的颜色(0代表不显示) 视频地址:传送链接 @n ...
- python生成字符画
python生成字符画 这个idea来自于实验楼,非常适合练习PIL的像素处理,更重要的是非常有意思. 环境配置 依赖的第三方库就是PIL(Python Image Library),可以直接使用pi ...
- 算法生成N芒星
前面两个图像生成算法是:道教的太极八卦图和佛教的卐和卍字图.这一节整个洋气的图像:芒星.但愿我别召唤出什么恐怖的禁忌,尤其今晚还是万圣节之夜.平时看玄幻小说,经常读到有关六芒星,七芒星,九芒星的技法. ...
- 机器学习:simple linear iterative clustering (SLIC) 算法
图像分割是图像处理,计算机视觉领域里非常基础,非常重要的一个应用.今天介绍一种高效的分割算法,即 simple linear iterative clustering (SLIC) 算法,顾名思义,这 ...
- ZeroMQ接口函数之 :zmq_z85_decode – 从一个用Z85算法生成的文本中解析出二进制密码
ZeroMQ 官方地址 :http://api.zeromq.org/4-0:zmq_z85_decode zmq_z85_decode(3) ØMQ Manual - ØMQ/4.1 ...
- PHP HMAC_SHA1 算法 生成算法签名
HMAC_SHA1(Hashed Message Authentication Code, Secure Hash Algorithm)是一种安全的基于加密hash函数和共享密钥的消息认证协议. 它可 ...
- 根据twitter的snowflake算法生成唯一ID
C#版本 /// <summary> /// 根据twitter的snowflake算法生成唯一ID /// snowflake算法 64 位 /// 0---0000000000 000 ...
- 在 iPad 上试验从用算法生成法线贴图-到法线映射光照效果
在 iPad 上试验从用算法生成法线贴图-到法线映射光照效果 目录 概述 一般来说, 法线贴图是用高模的法线图, 低模的纹理图, 来生成较好的渲染效果. 而法线图通常是通过图像处理软件来生成的, 这里 ...
随机推荐
- 面试侃集合 | ArrayBlockingQueue篇
面试官:平常在工作中你都用过什么什么集合? Hydra:用过 ArrayList.HashMap,呃-没有了 面试官:好的,回家等通知吧- 不知道大家在面试中是否也有过这样的经历,工作中仅仅用过的那么 ...
- SE_Work0_回顾与展望
项目 内容 课程:北航-2020-春-软件工程 博客园班级博客 要求:阅读推荐博客并回答问题 热身作业阅读部分要求 我在这个课程的目标是 提升团队管理及合作能力,开发一项满意的工程项目 这个作业在哪个 ...
- CMMI V2.0丨如何通过CMMI真正在企业中的实施规模化敏捷开发
在过去的几年中,敏捷开发已经从一个利基概念(利基是指针对企业的优势细分出来的市场,这个市场不大,而且没有得到令人满意的服务.产品推进这个市场,有盈利的基础.)转变为全球许多大公司采用的标准实践. 通过 ...
- golang:数据类型总结
Go语言将数据类型分为四类:基础类型.复合类型.引用类型和接口类型. 基础数据类型包括: 基础类型: - 布尔型.整型.浮点型.复数型.字符型.字符串型.错误类型. 复合数据类型包括: - 指针.数组 ...
- [刷题] 19 Remove Nth Node From End of List
要求 给定一个链表,删除倒数第n个节点 示例 1->2->3->4->5->NULL , n=2 1->2->3->5 边界 n是从0还是从1计 n不合 ...
- 利用jink的驱动软件j-flash 合并两个hex的方法,bootloader+app -(转载)
第一步:先打开第一个hex文件, 第二步:选择 "Merge data file",合并文件 第三步:两个工程有可能地址相同,会有如下提示:(如果在编译的时候设置好Flash的地址 ...
- Scala 字符串插值器
Scala 提供了三种创新的字符串插值方法:s,f和raw,使用他们我们可以方便快捷的组合字符串. s 字符串插值器 在任何字符串前加上s,就可以直接在串中使用变量了,在生成字符串的时候会隐式调用其t ...
- 那些天,shell脚本中曾经踩过的坑
前些天,需要实现一个需求,用脚本轮流kill服务器上的进程,观察内存变化情况,并写日志.脚本逻辑不难,但shell脚本好久不用,看过书里的语法都忘得差不多了,中间踩了不少的坑,特此记录一下,留作后续参 ...
- python3+unittest参考
Python3+Selenium+unittest自动化UI测试框架:https://www.cnblogs.com/G2Bent/p/8376001.html unittest --- 单元测试框架 ...
- CSS设计模式介绍
一. 常见CSS设计模式分析 oocss Object Oriented CSS,面向对象的CSS,旨在编写高可复用.低耦合和高扩展的CSS代码. OOCSS是以面向对象的思想去定义样式,将抽象(结构 ...