用canvas 实现个图片三角化(LOW POLY)效果


Posted in Javascript onFebruary 18, 2016

之前无意中看到Ovilia 用threejs做了个LOW POLY,也就是图片平面三角化的效果,觉得很惊艳,然后就自己花了点时间尝试了一下。

我是没怎么用过threejs,所以就直接用canvas的2d绘图API来做,因为感觉似乎这效果也用不上threejs。

直接上demo先:http://whxaxes.github.io/canvas-test/src/Funny-demo/lowpoly/index.html (也可以在移动端看,不过因为计算量比较大,移动设备计算起来会比PC要多花些时间。)

做这种效果主要需要把图片三角化,以及对图片进行边缘化检测。这两个,第一个用到的delaunay三角化算法,第二个用到的sobel边缘检测算法。听起来偷挺高大上的,索性两个算法都有相应的开源组件可以直接拿来用:ironwallaby的delaunay组件 以及 Miguel Mota的sobel组件。

这两个算法sobel还好一点,delaunay就有点复杂了,待日后可以研究一下。不过目前只为做出个效果的话,还是可以用这些组件的。

两个最重要的组件都有了,剩下的事就很简单了:

先将图片绘制到canvas上:

canvas.width = (img.width > 800) ? 800 : img.width;
canvas.height = img.height * canvas.width/img.width;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

然后获取到canvas的imgData,再通过sobel计算返回新的imgData

var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var newImgData = Sobel(imgData);

如果我们把newImgData放到canvas上,就会发现,彩色图片变成了这样的灰度图片:

用canvas 实现个图片三角化(LOW POLY)效果

由于上面说的那个Sobel组件不是很适合自己的用法,同时代码也有不恰当的地方,所以自己做了适当修改和优化,优化了循环方法,加快了运算速度,同时加入了回调函数。详见该项目github中的sobel.js文件

在Sobel方法中对imgData.data进行遍历的时候,会调用回调函数,在回调中把颜色值大于40(也就是灰度为rgb(40,40,40)以上的)的坐标点记录下来。然后随机获取一部分边缘点,再加入一些随机出来的坐标 以及 四个边角的坐标值。这样,我们就可以获取到我们需要的坐标点了

var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// 收集色值大于40的边缘像素点
var collectors = [];
Sobel(imgData , function(value , x , y){
if(value > 40){collectors.push([x , y]);}
});
// 添加一些随机点
for(var i=0;i<300;i++){particles.push([Math.random()*canvas.width , Math.random()*canvas.height]);}
// 添加随机边缘点,数量为边缘点数量除于50
var length = ~~(collectors.length/50), random;
for(var l=0;l<length;l++){
random = (Math.random()*collectors.length)<<0;
particles.push(collectors[random]);
collectors.splice(random , 1);
}
// 添加四顶点坐标
particles.push([0,0] , [0,canvas.height] , [canvas.width,0] , [canvas.width,canvas.height]);

获取到坐标点后,就可以通过delaunay组件计算,获取到拍好次序的三角坐标数组,对这些数组里的点进行连线,就可以出现这样的效果:

用canvas 实现个图片三角化(LOW POLY)效果

当然,我们要的效果不是连线,而是对所有三角形进行颜色填充,也就是获取三角形的三个坐标,然后计算出中心点的坐标,再根据中心点坐标在imgData里获取到相应的rgb的颜色值,然后填充到三角区域就可以了:

// 使用delaunay三角化获取三角坐标
var triangles = Delaunay.triangulate(particles);
var x1,x2,x3,y1,y2,y3,cx,cy;
for(var i=0;i < triangles.length; i+=3) {
x1 = particles[triangles[i]][0];
x2 = particles[triangles[i+1]][0];
x3 = particles[triangles[i+2]][0];
y1 = particles[triangles[i]][1];
y2 = particles[triangles[i+1]][1];
y3 = particles[triangles[i+2]][1];
// 获取三角形中心点坐标
cx = ~~((x1 + x2 + x3) / 3);
cy = ~~((y1 + y2 + y3) / 3);
// 获取中心点坐标的颜色值
index = (cy*imgData.width + cx)*4;
var color_r = imgData.data[index];
var color_g = imgData.data[index+1];
var color_b = imgData.data[index+2];
// 绘制三角形
ctx.save();
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.closePath();
ctx.fillStyle = "rgba("+color_r+","+color_g+","+color_b+",1)";
ctx.fill();
ctx.restore();
}

上面有一点要注意,获取到的中心点坐标一定要取整,才能够获取到正确的颜色参数,如果想着不取整,而是在获取rgb索引的时候再取整,获取到的颜色值就是错的。因为这样获取到的那个像素点就不是我们要的中心像素点。

颜色也获取到后,就是简单的连线,然后填充操作了,最后出来的效果就是:

用canvas 实现个图片三角化(LOW POLY)效果

用canvas 实现个图片三角化(LOW POLY)效果

以上内容给大家介绍了用canvas 实现个图片三角化(LOW POLY)效果 ,希望对大家有所帮助!

Javascript 相关文章推荐
由浅到深了解JavaScript类
Sep 08 Javascript
JSONP 跨域共享信息
Aug 16 Javascript
jQuery中prepend()方法使用详解
Aug 11 Javascript
深入理解jQuery中的事件冒泡
May 24 Javascript
html+js+highcharts绘制圆饼图表的简单实例
Aug 04 Javascript
基于JavaScript实现在新的tab页打开url
Aug 04 Javascript
JS判断form内所有表单是否为空的简单实例
Sep 09 Javascript
JS ES6中setTimeout函数的执行上下文示例
Apr 27 Javascript
React Native使用fetch实现图片上传的示例代码
Mar 07 Javascript
angular5 httpclient的示例实战
Mar 12 Javascript
解析vue data不可以使用箭头函数问题
Jul 03 Javascript
JavaScript字符和ASCII实现互相转换
Jun 03 Javascript
Js实现简单的小球运动特效
Feb 18 #Javascript
JavaScript与jQuery实现的闪烁输入效果
Feb 18 #Javascript
js实现简单的省市县三级联动效果实例
Feb 18 #Javascript
XML、HTML、CSS与JS的区别整理
Feb 18 #Javascript
jQuery插件实现适用于移动端的地址选择器
Feb 18 #Javascript
AngularJS 2.0新特性有哪些
Feb 18 #Javascript
JavaScript+canvas实现七色板效果实例
Feb 18 #Javascript
You might like
vBulletin HACK----显示话题大小和打开新窗口于论坛索引页
2006/10/09 PHP
php对数组内元素进行随机调换的方法
2015/05/12 PHP
PHP实现的统计数据功能详解
2016/12/06 PHP
PHP simplexml_import_dom()函数讲解
2019/02/03 PHP
js实现全屏漂浮广告移入光标停止移动
2013/12/02 Javascript
js自调用匿名函数的三种写法(推荐)
2016/08/19 Javascript
基于百度地图实现产品销售的单位位置查看功能设计与实现
2016/10/21 Javascript
Bootstrap 模态框(Modal)插件代码解析
2016/12/21 Javascript
Js面试算法详解
2018/04/08 Javascript
利用es6 new.target来对模拟抽象类的方法
2019/05/10 Javascript
小程序实现分类页
2019/07/12 Javascript
[02:10]DOTA2 TI10勇士令状玩法及不朽Ⅰ展示:焕新世界,如你所期
2020/05/29 DOTA
python实现的简单RPG游戏流程实例
2015/06/28 Python
python生成式的send()方法(详解)
2017/05/08 Python
读取本地json文件,解析json(实例讲解)
2017/12/06 Python
python 删除列表里所有空格项的方法总结
2018/04/18 Python
Python cookbook(字符串与文本)针对任意多的分隔符拆分字符串操作示例
2018/04/19 Python
python smtplib模块实现发送邮件带附件sendmail
2018/05/22 Python
Numpy 将二维图像矩阵转换为一维向量的方法
2018/06/05 Python
Python解决线性代数问题之矩阵的初等变换方法
2018/12/12 Python
Python更新所有已安装包的操作
2020/02/13 Python
Python内存泄漏和内存溢出的解决方案
2020/09/26 Python
Python 爬取淘宝商品信息栏目的实现
2021/02/06 Python
Python如何telnet到网络设备
2021/02/18 Python
CSS3 @font-face属性使用指南
2014/12/12 HTML / CSS
详解CSS3中@media的实际使用
2015/08/04 HTML / CSS
浅谈three.js中的needsUpdate的应用
2012/11/12 HTML / CSS
机电专业大学生求职信
2013/10/04 职场文书
幼师自荐信范文
2013/10/06 职场文书
《画杨桃》教学反思
2014/04/13 职场文书
实验室标语
2014/06/21 职场文书
教师群众路线教育实践活动学习笔记
2014/11/05 职场文书
小学重阳节活动总结
2015/03/24 职场文书
党员证明信
2015/06/19 职场文书
幼儿园中班教育随笔
2015/08/14 职场文书
Win10服务主机占用内存怎么办?Win10服务主机进程占用大量内存解决方法
2022/09/23 数码科技