前面給大家帶來了操作像素的API,此時此刻,我覺得應該配以小實例來進行進一步的說明和演示,以便給大家帶來更寬廣的視野和靈感,你們看了我的那么多的文章,應該是懂我的風格,廢話不多說,進入正題:
這次給大家帶來的是圖片的馬賽克效果,這種效果你們應該很熟悉了,比如看到一些較污的新聞,關鍵的地方總是有這萬惡的馬賽克擋着,咱們今天就來剖析一下這馬賽克到底是撒東西,是一個什么原理:
大家看看這張圖,這就是馬賽克的效果,整個圖就是一顆顆很大的像素點構成的,當然這里說的像素點指的不是一像素,而是一個像素點可能是由幾個像素或者是十幾個像素構成的,像素點越大,圖像就約模糊,像素點越小,圖片越清晰,什么,你對上圖無感?好吧,我們看一下現實生活中你見過的馬賽克:
看,左邊的大美女,打上馬賽克,立馬變神秘了,那馬賽克糾結是一個什么原理呢?
對比上圖的左右兩個臉,右邊的臉雖然看不清,但還是能看清輪廓的,而且右邊的馬賽克部分像素點非常大,而左邊的呢,幾乎看不到像素點,那么左邊的是不是就不是由像素點構成的呢?我們把圖放大n倍來看看:
上圖是截圖的馬賽克圖片的一部分,放大后可以清除的看到,圖像是由一個個像素點構成的,可以發現,馬賽克的像素顆粒也是由許多的像素點構成的,只是這些顆粒的顏色是一個的,縮小就感覺是一個大的像素顆粒,而偏不的則是一個個小的像素點,各自顏色不一樣,才形象非常細膩的圖像,由此可見,要想做馬賽克效果,只需要將一個區域內的像素的的顏色用里面一個隨機的顏色替代,就會使得圖像模糊,這樣縮小了看就是馬賽克效果了,而且這個區域也大,圖像越模糊,越小,則圖像越清晰!
知道了馬賽克的原理,那么我們就可以通過操作像素來制作馬賽克效果了,怎么做呢?比如將一整張圖做成馬賽克效果,那么,如果我們將這張圖等分成n份,且每一份隨機在這個區域里找一個像素點的顏色,然后將這個區域的顏色都設為這個顏色,全部操作完,馬賽克就做完了,哈哈,挺抽象的,那老規矩,跟着我一步一步的做吧:
首先我們在畫布上引進來一張圖,然后我們建一個函數,用於繪制馬賽克(其目的我再說一般,一是圖片必須加裝完成,才能進行像素操作,二是結構更清晰,便於理解)
var aImg = new Image(); aImg.src = '1.jpg'; aImg.onload = function(){ draw(this); } //此函數用於后面的像素操作 function draw(obj){ ctx.drawImage(obj,0,0,400,400); }
我們將畫布的大小設為圖片的2倍,右邊用於顯示馬賽克的圖
下面就該獲取像素了,不清楚的同學可以先去看看前文的API的第5篇,工欲善其事必先利其器
function draw(obj){ ctx.drawImage(obj,0,0,400,400); var oImg = ctx.getImageData(0,0,400,400); var w = oImg.width; var h = oImg.height; ctx.putImageData(oImg,w,0); }
在右側把圖片用像素操作復制一個放到右邊
一模一樣雙胞胎,哈哈,接下來就是醉關鍵的地方了,就是如何將一個區域的像素點用一個顏色替代,我們畫一個圖來示意一下:
看看上圖,圖畫的很粗糙哈(俗話說圖糙理不糙),比如說圖片是100*100像素的圖,那么原來是由1*1像素的點構成的,現在我們等分成10份,一份的像素點就是10*10,那么這份的像素點在里面隨機設置一個顏色,然后同理操作所有的,就成了一個只顯示10分之一圖像的馬賽克了
這里引用我們原來寫的獲取某一點的顏色的函數和設置某一點的顏色的函數,可以作為通用方法:
function getXY(obj,x,y){ var w = obj.width; var h = obj.height; var d = obj.data; var color = []; color[0] = obj.data[4*(y*w+x)]; color[1] = obj.data[4*(y*w+x)+1]; color[2] = obj.data[4*(y*w+x)+2]; color[3] = obj.data[4*(y*w+x)+3]; return color; } function setXY(obj,x,y,color){ var w = obj.width; var h = obj.height; var d = obj.data; obj.data[4*(y*w+x)] = color[0]; obj.data[4*(y*w+x)+1] = color[1]; obj.data[4*(y*w+x)+2] = color[2]; obj.data[4*(y*w+x)+3] = color[3]; }
接下來就是操作像素了,我們在一個新的ImageData上操作
//創建一個新的ImageData對象 var newImg = ctx.createImageData(obj.width,obj.height); //馬賽克的程度,數字越大越模糊 var num = 5; //等分畫布 var stepW = w/num; var stepH = h/num; //這里是循環畫布的像素點 for(var i=0;i<stepH;i++){ for(var j=0;j<stepW;j++){ //獲取一個小方格的隨機顏色,這是小方格的隨機位置獲取的 var color = getXY(oImg,j*num+Math.floor(Math.random()*num),i*num+Math.floor(Math.random()*num)); //這里是循環小方格的像素點, for(var k=0;k<num;k++){ for(var l=0;l<num;l++){ //設置小方格的顏色 setXY(newImg,j*num+l,i*num+k,color); } } } }
整理所有的代碼就是:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); var aImg = new Image(); aImg.src = '1.jpg'; aImg.onload = function(){ draw(this); } function draw(obj){ ctx.drawImage(obj,0,0,400,400); var oImg = ctx.getImageData(0,0,400,400); var w = oImg.width; var h = oImg.height; //創建一個新的ImageData對象 var newImg = ctx.createImageData(obj.width,obj.height); //馬賽克的程度,數字越大越模糊 var num = 5; //等分畫布 var stepW = w/num; var stepH = h/num; //這里是循環畫布的像素點 for(var i=0;i<stepH;i++){ for(var j=0;j<stepW;j++){ //獲取一個小方格的隨機顏色,這是小方格的隨機位置獲取的 var color = getXY(oImg,j*num+Math.floor(Math.random()*num),i*num+Math.floor(Math.random()*num)); //這里是循環小方格的像素點, for(var k=0;k<num;k++){ for(var l=0;l<num;l++){ //設置小方格的顏色 setXY(newImg,j*num+l,i*num+k,color); } } } } ctx.putImageData(newImg,w,0); } function getXY(obj,x,y){ var w = obj.width; var h = obj.height; var d = obj.data; var color = []; color[0] = obj.data[4*(y*w+x)]; color[1] = obj.data[4*(y*w+x)+1]; color[2] = obj.data[4*(y*w+x)+2]; color[3] = obj.data[4*(y*w+x)+3]; return color; } function setXY(obj,x,y,color){ var w = obj.width; var h = obj.height; var d = obj.data; obj.data[4*(y*w+x)] = color[0]; obj.data[4*(y*w+x)+1] = color[1]; obj.data[4*(y*w+x)+2] = color[2]; obj.data[4*(y*w+x)+3] = color[3]; }
得到的效果:
為了顯得好看一點,我們只是取了一個比較小的值,現在五分之一的像素點,如果是十分之一,得到是就是這樣的,值在num的地方修改:
具體效果看這里——canvas馬賽克效果
這是整張圖做成馬賽克,能不能跟上面的美女一樣,做成局部的馬賽克呢?其實也很簡單,我們起初獲取的是整張圖的像素,現在我們只獲取局部我們想要的部分的像素就可以了:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); var aImg = new Image(); aImg.src = '1.jpg'; aImg.onload = function(){ draw(this); } function draw(obj){ //繪制第一張圖 ctx.drawImage(obj,0,0,400,400); //繪制第二張圖,用作對比 ctx.drawImage(obj,400,0,400,400); //獲取坐邊圖像的局部坐標的部分像素(左圖位置在258,為方便演示,這里設成和馬賽克顯示位置一樣的坐標) var oImg = ctx.getImageData(650,60,50,50); var w = oImg.width; var h = oImg.height; //馬賽克的程度,數字越大越模糊 var num = 10; //等分畫布 var stepW = w/num; var stepH = h/num; //這里是循環畫布的像素點 for(var i=0;i<stepH;i++){ for(var j=0;j<stepW;j++){ //獲取一個小方格的隨機顏色,這是小方格的隨機位置獲取的 var color = getXY(oImg,j*num+Math.floor(Math.random()*num),i*num+Math.floor(Math.random()*num)); //這里是循環小方格的像素點, for(var k=0;k<num;k++){ for(var l=0;l<num;l++){ //設置小方格的顏色 setXY(oImg,j*num+l,i*num+k,color); } } } } ctx.putImageData(oImg,650,60); } function getXY(obj,x,y){ var w = obj.width; var h = obj.height; var d = obj.data; var color = []; color[0] = obj.data[4*(y*w+x)]; color[1] = obj.data[4*(y*w+x)+1]; color[2] = obj.data[4*(y*w+x)+2]; color[3] = obj.data[4*(y*w+x)+3]; return color; } function setXY(obj,x,y,color){ var w = obj.width; var h = obj.height; var d = obj.data; obj.data[4*(y*w+x)] = color[0]; obj.data[4*(y*w+x)+1] = color[1]; obj.data[4*(y*w+x)+2] = color[2]; obj.data[4*(y*w+x)+3] = color[3]; }
是不是跟剛開始的那個美女很像了,可能有的同學注意到,我有時候創建了一個新的ImageData對象,有的時候沒有,那到底什么時候需要創建新的ImageData對象,什么時候不需要呢?原則上說,如果你操作的像素不在原圖上,則需要新創建一個ImageData對象,但是也不是絕對的,你在原圖上操作像素,也是可以創建一個新的ImageData對象的,具體還是看需要!
上面的局部馬賽克效果看這里—— canvas圖片局部馬賽克效果
今天就講到這里,后面要是有時間,在給幾個例子給大家學習一下!