以前無心中看到html
git
github
delaunay組件 以及 Miguel Mota的sobel組件。算法
這兩個算法sobel還好一點,delaunay就有點複雜了,待往後能夠研究一下。不過目前只爲作出個效果的話,仍是能夠用這些組件的。canvas
兩個最重要的組件都有了,剩下的事就很簡單了:數組
先將圖片繪製到canvas上:dom
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上,就會發現,彩色圖片變成了這樣的灰度圖片:優化
因爲上面說的那個Sobel組件不是很適合本身的用法,同時代碼也有不恰當的地方,因此本身作了適當修改和優化,優化了循環方法,加快了運算速度,同時加入了回調函數。詳見該項目github中的sobel.js文件url
在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組件計算,獲取到拍好次序的三角座標數組,對這些數組裏的點進行連線,就能夠出現這樣的效果:
固然,咱們要的效果不是連線,而是對全部三角形進行顏色填充,也就是獲取三角形的三個座標,而後計算出中心點的座標,再根據中心點座標在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索引的時候再取整,獲取到的顏色值就是錯的。由於這樣獲取到的那個像素點就不是咱們要的中心像素點。
顏色也獲取到後,就是簡單的連線,而後填充操做了,最後出來的效果就是:
雖然沒有設計師手動描出來的好看,不過也方便不少,作來玩玩仍是挺有意思的。
源碼地址,有興趣的能夠一看哈:
https://github.com/whxaxes/canvas-test/tree/gh-pages/src/Funny-demo/lowpoly