用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学习笔记(三) String 字符串类型介绍
Jun 19 Javascript
Javascript图像处理思路及实现代码
Dec 25 Javascript
你必须知道的Javascript知识点之&quot;单线程事件驱动&quot;的使用
Apr 23 Javascript
jQuery把表单元素变为json对象
Nov 06 Javascript
jquery实现界面无刷新加载登陆注册
Jul 30 Javascript
js实现消息滚动效果
Jan 18 Javascript
js时间戳和c#时间戳互转方法(推荐)
Feb 15 Javascript
原生js实现可拖拽效果
Feb 28 Javascript
使用Vue完成一个简单的todolist的方法
Dec 01 Javascript
vue+echarts实现动态绘制图表及异步加载数据的方法
Oct 17 Javascript
Javascript数组方法reduce的妙用之处分享
Jun 10 Javascript
Kettle中使用JavaScrip调用jar包对文件内容进行MD5加密的操作方法
Sep 04 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
PHP下通过系统信号量加锁方式获取递增序列ID
2009/09/25 PHP
基于PHP选项与信息函数的使用详解
2013/05/10 PHP
php环境套包 dedeampz 伪静态设置示例
2014/03/26 PHP
深入理解PHP中的global
2014/08/19 PHP
PHP随机生成唯一HASH值自定义函数
2015/04/20 PHP
JavaScript 面向对象编程(2) 定义类
2010/05/18 Javascript
JavaScript 在网页上单击鼠标的地方显示层及关闭层
2012/12/30 Javascript
通过node-mysql搭建Windows+Node.js+MySQL环境的教程
2016/03/01 Javascript
Javascript获取图片原始宽度和高度的方法详解
2016/09/20 Javascript
KnockoutJS 3.X API 第四章之表单textInput、hasFocus、checked绑定
2016/10/11 Javascript
Vue 2.x教程之基础API
2017/03/06 Javascript
用javascript获取任意颜色的更亮或更暗颜色值示例代码
2017/07/21 Javascript
jquery select插件异步实时搜索实例代码
2017/10/20 jQuery
在Swiper内如何制作CSS3动画效果示例代码
2017/12/07 Javascript
使用vue中的v-for遍历二维数组的方法
2018/03/07 Javascript
vue之父子组件间通信实例讲解(props、$ref、$emit)
2018/05/22 Javascript
jQuery实现的响应鼠标移动方向插件用法示例【附源码下载】
2018/08/28 jQuery
JavaScript学习笔记之基于定时器实现图片无缝滚动功能详解
2019/01/09 Javascript
countUp.js实现数字动态变化效果
2019/10/17 Javascript
python删除列表中重复记录的方法
2015/04/28 Python
详谈python中冒号与逗号的区别
2018/04/18 Python
python分块读取大数据,避免内存不足的方法
2018/12/10 Python
Python利用heapq实现一个优先级队列的方法
2019/02/03 Python
Django csrf 两种方法设置form的实例
2019/02/03 Python
python-itchat 获取微信群用户信息的实例
2019/02/21 Python
十分钟搞定pandas(入门教程)
2019/06/21 Python
HTML里显示pdf、word、xls、ppt的方法示例
2020/04/14 HTML / CSS
2019年c语言经典面试题目
2016/08/17 面试题
数控专业个人求职信范例
2013/11/29 职场文书
2015年元旦文艺晚会总结(学院)
2014/11/28 职场文书
电影红河谷观后感
2015/06/11 职场文书
爱国教育主题班会
2015/08/14 职场文书
2016年端午节校园广播稿
2015/12/18 职场文书
励志语录:你若不勇敢,谁替你坚强
2019/11/08 职场文书
golang日志包logger的用法详解
2021/05/05 Golang
Python趣味挑战之实现简易版音乐播放器
2021/05/28 Python