用canvas 實(shí)現(xiàn)個(gè)圖片三角化(LOW POLY)效果
之前無意中看到Ovilia 用threejs做了個(gè)LOW POLY,也就是圖片平面三角化的效果,覺得很驚艷,然后就自己花了點(diǎn)時(shí)間嘗試了一下。
我是沒怎么用過threejs,所以就直接用canvas的2d繪圖API來做,因?yàn)楦杏X似乎這效果也用不上threejs。
直接上demo先:http://whxaxes.github.io/canvas-test/src/Funny-demo/lowpoly/index.html (也可以在移動(dòng)端看,不過因?yàn)橛?jì)算量比較大,移動(dòng)設(shè)備計(jì)算起來會(huì)比PC要多花些時(shí)間。)
做這種效果主要需要把圖片三角化,以及對(duì)圖片進(jìn)行邊緣化檢測(cè)。這兩個(gè),第一個(gè)用到的delaunay三角化算法,第二個(gè)用到的sobel邊緣檢測(cè)算法。聽起來偷挺高大上的,索性兩個(gè)算法都有相應(yīng)的開源組件可以直接拿來用:ironwallaby的delaunay組件 以及 Miguel Mota的sobel組件。
這兩個(gè)算法sobel還好一點(diǎn),delaunay就有點(diǎn)復(fù)雜了,待日后可以研究一下。不過目前只為做出個(gè)效果的話,還是可以用這些組件的。
兩個(gè)最重要的組件都有了,剩下的事就很簡(jiǎn)單了:
先將圖片繪制到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計(jì)算返回新的imgData
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); var newImgData = Sobel(imgData);
如果我們把newImgData放到canvas上,就會(huì)發(fā)現(xiàn),彩色圖片變成了這樣的灰度圖片:
由于上面說的那個(gè)Sobel組件不是很適合自己的用法,同時(shí)代碼也有不恰當(dāng)?shù)牡胤剑宰约鹤隽诉m當(dāng)修改和優(yōu)化,優(yōu)化了循環(huán)方法,加快了運(yùn)算速度,同時(shí)加入了回調(diào)函數(shù)。詳見該項(xiàng)目github中的sobel.js文件
在Sobel方法中對(duì)imgData.data進(jìn)行遍歷的時(shí)候,會(huì)調(diào)用回調(diào)函數(shù),在回調(diào)中把顏色值大于40(也就是灰度為rgb(40,40,40)以上的)的坐標(biāo)點(diǎn)記錄下來。然后隨機(jī)獲取一部分邊緣點(diǎn),再加入一些隨機(jī)出來的坐標(biāo) 以及 四個(gè)邊角的坐標(biāo)值。這樣,我們就可以獲取到我們需要的坐標(biāo)點(diǎn)了
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); // 收集色值大于40的邊緣像素點(diǎn) var collectors = []; Sobel(imgData , function(value , x , y){ if(value > 40){collectors.push([x , y]);} }); // 添加一些隨機(jī)點(diǎn) for(var i=0;i<300;i++){particles.push([Math.random()*canvas.width , Math.random()*canvas.height]);} // 添加隨機(jī)邊緣點(diǎn),數(shù)量為邊緣點(diǎn)數(shù)量除于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); } // 添加四頂點(diǎn)坐標(biāo) particles.push([0,0] , [0,canvas.height] , [canvas.width,0] , [canvas.width,canvas.height]);
獲取到坐標(biāo)點(diǎn)后,就可以通過delaunay組件計(jì)算,獲取到拍好次序的三角坐標(biāo)數(shù)組,對(duì)這些數(shù)組里的點(diǎn)進(jìn)行連線,就可以出現(xiàn)這樣的效果:
當(dāng)然,我們要的效果不是連線,而是對(duì)所有三角形進(jìn)行顏色填充,也就是獲取三角形的三個(gè)坐標(biāo),然后計(jì)算出中心點(diǎn)的坐標(biāo),再根據(jù)中心點(diǎn)坐標(biāo)在imgData里獲取到相應(yīng)的rgb的顏色值,然后填充到三角區(qū)域就可以了:
// 使用delaunay三角化獲取三角坐標(biāo) 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]; // 獲取三角形中心點(diǎn)坐標(biāo) cx = ~~((x1 + x2 + x3) / 3); cy = ~~((y1 + y2 + y3) / 3); // 獲取中心點(diǎn)坐標(biāo)的顏色值 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(); }
上面有一點(diǎn)要注意,獲取到的中心點(diǎn)坐標(biāo)一定要取整,才能夠獲取到正確的顏色參數(shù),如果想著不取整,而是在獲取rgb索引的時(shí)候再取整,獲取到的顏色值就是錯(cuò)的。因?yàn)檫@樣獲取到的那個(gè)像素點(diǎn)就不是我們要的中心像素點(diǎn)。
顏色也獲取到后,就是簡(jiǎn)單的連線,然后填充操作了,最后出來的效果就是:
以上內(nèi)容給大家介紹了用canvas 實(shí)現(xiàn)個(gè)圖片三角化(LOW POLY)效果 ,希望對(duì)大家有所幫助!
- Javascript保存網(wǎng)頁(yè)為圖片借助于html2canvas庫(kù)實(shí)現(xiàn)
- javascript結(jié)合canvas實(shí)現(xiàn)圖片旋轉(zhuǎn)效果
- JavaScript+html5 canvas實(shí)現(xiàn)圖片破碎重組動(dòng)畫特效
- HTML5+Canvas調(diào)用手機(jī)拍照功能實(shí)現(xiàn)圖片上傳(上)
- HTML5+Canvas調(diào)用手機(jī)拍照功能實(shí)現(xiàn)圖片上傳(下)
- HTML5 canvas 9繪制圖片實(shí)例詳解
- Canvas + JavaScript 制作圖片粒子效果
- canvas實(shí)現(xiàn)圖片根據(jù)滑塊放大縮小效果
- canvas壓縮圖片轉(zhuǎn)換成base64格式輸出文件流
- 一步步教你利用Canvas對(duì)圖片進(jìn)行處理
相關(guān)文章
js動(dòng)態(tài)創(chuàng)建表格,刪除行列的小例子
這篇文章介紹了js動(dòng)態(tài)創(chuàng)建表格,刪除行列的實(shí)例代碼,有需要的朋友可以參考一下2013-07-07基于Bootstrap+jQuery.validate實(shí)現(xiàn)表單驗(yàn)證
這篇文章主要為大家詳細(xì)介紹了基于Bootstrap+jQuery.validate實(shí)現(xiàn)表單驗(yàn)證,感興趣的小伙伴們可以參考一下2016-05-05js 完美圖片新聞?shì)嗈D(zhuǎn)效果,騰訊大粵網(wǎng)首頁(yè)圖片輪轉(zhuǎn)改造而來
找過很多圖片輪詢效果,和我的要求總是有些出入,不能十全十美。不是功能不全,就是太多花哨。本想自己開發(fā)一個(gè),鑒于瑣事拖延,遲遲未能開始2011-11-11原生javascript實(shí)現(xiàn)的全屏滾動(dòng)功能示例
這篇文章主要介紹了原生javascript實(shí)現(xiàn)的全屏滾動(dòng)功能,涉及javascript事件響應(yīng)及頁(yè)面元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-09-0910個(gè)功能強(qiáng)大的JavaScript動(dòng)畫庫(kù)分享
動(dòng)畫,從人群中脫穎而出、吸引訪客注意力的絕佳方式,本文將給大家分享10 個(gè)功能強(qiáng)大的 JavaScript 動(dòng)畫庫(kù),有了這 10 個(gè)功能強(qiáng)大的 JavaScript 庫(kù),創(chuàng)建動(dòng)畫再簡(jiǎn)單不過了,感興趣的同學(xué)可以參考閱讀2023-09-09vscode工具函數(shù)idGenerator使用深度解析
這篇文章主要為大家介紹了vscode工具函數(shù)idGenerator使用深度解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03表現(xiàn)、結(jié)構(gòu)、行為分離的選項(xiàng)卡效果
2008-01-01