canvas影象處理——實現濾鏡效果
實現濾鏡效果
點選按鈕出現不同濾鏡效果
首先,我們分析濾鏡的具體,主要就是對圖片的每個具體畫素進行處理,先拿到畫素,處理後再將畫素放回去。
1.怎樣拿到畫素
通過getImageData可以拿到圖片的imageData,imageData包含3個內容:width,height,data;
width,height指的是圖片的寬和高
data指的是圖片內部所有資訊。
context.getImageData(x, y, w, h),從x,y座標處爬取圖片寬為w,高為h
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
獲取圖片data,將其儲存在pixelData中。
這裡有一個問題就是本地圖片使用getImageData方法的話會產生一個圖片跨域的問題。
解決方法1.使用伺服器,將圖片放在伺服器中;
2.使用火狐瀏覽器
2.使用不同的濾鏡演算法
我們在這個demo中使用了5個濾鏡演算法
灰度濾鏡:計算出圖片每個畫素點的灰度值
function grey(){ var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height); var pixelData = imageData.data; for (var i = 0; i < canvasb.width*canvasb.height; i++) { var r = pixelData[i*4+0] var g = pixelData[i*4+1] var b = pixelData[i*4+2] var grey = r*0.3+g*0.59+b*0.11//圖片灰度值 pixelData[i*4+0] = grey pixelData[i*4+1] = grey pixelData[i*4+2] = grey } cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height) }
黑白濾鏡:圖片中沒有灰色,只有黑與白,灰度值大於255/2,則顯示為黑色,否則為白色
function black(){//黑白濾鏡即圖片中沒有灰色
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
for (var i = 0; i < canvasb.width*canvasb.height; i++) {
var r = pixelData[i*4+0]
var g = pixelData[i*4+1]
var b = pixelData[i*4+2]
var grey = r*0.3+g*0.59+b*0.11//圖片灰度值
if (grey >255/2) {
v = 255
}
else{
v = 0
}
pixelData[i*4+0] = v
pixelData[i*4+1] = v
pixelData[i*4+2] = v
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
反色濾鏡:圖片每個畫素點的顏色變為原來顏色的255-原
function reverse(){//圖片中每個畫素的rgb都是255-原
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
for (var i = 0; i < canvasb.width*canvasb.height; i++) {
var r = pixelData[i*4+0]
var g = pixelData[i*4+1]
var b = pixelData[i*4+2]
pixelData[i*4+0] = 255-r
pixelData[i*4+1] = 255-g
pixelData[i*4+2] = 255-b
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
模糊濾鏡:計算一個畫素點及其周圍畫素點的平均值
function blur(){//要參考周圍的畫素
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
//建立作為參考的畫素
var tmpImageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var tmpPixelData = tmpImageData.data;
var blurR = 3
var totalnum = (2*blurR+1)*(2*blurR+1)
//此處迴圈需從1開始,..-1結束,否則在裡面的二層迴圈(dx=-1,dy=-1)就會越界
for (var i = blurR; i < canvasb.height-blurR; i++) {
for (var j = blurR; j < canvasb.width-blurR; j++) {
var totalr = 0,totalg = 0,totalb = 0;
//一個畫素點周圍的加上自身
for (var dx = -blurR; dx <= blurR; dx++) {
for(var dy = -blurR; dy<=blurR; dy++){
var x = i+dx;
var y = j+dy;
var p = x*canvasb.width+y
totalr += tmpPixelData[p*4+0]
totalg += tmpPixelData[p*4+1]
totalb += tmpPixelData[p*4+2]
}
}
var p = i*canvasb.width+j//每個畫素點
pixelData[p*4+0] = totalr/totalnum
pixelData[p*4+1] = totalg/totalnum
pixelData[p*4+2] = totalb/totalnum
}
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
馬賽克濾鏡:和模糊濾鏡類似,只是馬賽克濾鏡是計算每一塊的平均值,在這裡,需要計算圖片的寬與高來確定方塊的邊長
如程式碼中:var size = 25,因為我用的圖片是500*375的,25可以整除。
function mosaic(){//要參考周圍的畫素
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
//建立作為參考的畫素
var tmpImageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var tmpPixelData = tmpImageData.data;
var size = 25//馬賽克方塊的邊長
var totalnum = size*size
//此處迴圈需從1開始,..-1結束,否則在裡面的二層迴圈(dx=-1,dy=-1)就會越界
for (var i = 0; i < canvasb.height; i+=size) {
for (var j = 0; j < canvasb.width; j+=size) {
var totalr = 0,totalg = 0,totalb = 0;
//一個畫素點周圍的加上自身
for (var dx = 0; dx < size; dx++) {
for(var dy = 0; dy<size; dy++){
var x = i+dx;
var y = j+dy;
var p = x*canvasb.width+y
totalr += tmpPixelData[p*4+0]
totalg += tmpPixelData[p*4+1]
totalb += tmpPixelData[p*4+2]
}
}
var p = i*canvasb.width+j//每個畫素點
var resr = totalr/totalnum
var resg = totalg/totalnum
var resb = totalb/totalnum
for (var dx = 0; dx < size; dx++) {
for(var dy = 0; dy<size; dy++){
var x = i+dx;
var y = j+dy;
var p = x*canvasb.width+y
pixelData[p*4+0] = resr
pixelData[p*4+1] = resg
pixelData[p*4+2] = resb
}
}
}
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
3.將處理後的畫素點放回圖片中
放置imageData
context.putImageData(imageData, dx, dy, dirtyX, dirtyY, dirtyW, dirtyH)
dx,dy在畫布上的初始偏移
總體效果:
所有程式碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>濾鏡練習</title>
</head>
<body>
<div style="margin: 20px auto; width: 1500px;">
<canvas id="canvasa" width="500" height="375" style="display:block;border: 1px solid #aaa;float: left;"></canvas>
<canvas id="canvasb" width="500" height="375" style="display:block;border: 1px solid #aaa;margin: 20px auto" ></canvas>
</div>
<div style="text-align: center;margin-top: 50px; font-size: 20px;">
<a href="javascript:grey()">灰度濾鏡</a>
<a href="javascript:black()">黑白濾鏡</a>
<a href="javascript:reverse()">反色濾鏡</a>
<a href="javascript:blur()">模糊濾鏡</a>
<a href="javascript:mosaic()">馬賽克濾鏡</a>
</div>
<script type="text/javascript">
var canvasa = document.getElementById('canvasa');
var cxta = canvasa.getContext('2d');
var canvasb = document.getElementById('canvasb');
var cxtb = canvasb.getContext('2d');
var image = new Image();
window.onload = function(){
image.src = 'img/1.jpg';
image.onload = function(){
cxta.drawImage(image, 0, 0, canvasa.width, canvasa.height)
}
}
function grey(){
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
for (var i = 0; i < canvasb.width*canvasb.height; i++) {
var r = pixelData[i*4+0]
var g = pixelData[i*4+1]
var b = pixelData[i*4+2]
var grey = r*0.3+g*0.59+b*0.11//圖片灰度值
pixelData[i*4+0] = grey
pixelData[i*4+1] = grey
pixelData[i*4+2] = grey
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
function black(){//黑白濾鏡即圖片中沒有灰色
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
for (var i = 0; i < canvasb.width*canvasb.height; i++) {
var r = pixelData[i*4+0]
var g = pixelData[i*4+1]
var b = pixelData[i*4+2]
var grey = r*0.3+g*0.59+b*0.11//圖片灰度值
if (grey >255/2) {
v = 255
}
else{
v = 0
}
pixelData[i*4+0] = v
pixelData[i*4+1] = v
pixelData[i*4+2] = v
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
function reverse(){//圖片中每個畫素的rgb都是255-原
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
for (var i = 0; i < canvasb.width*canvasb.height; i++) {
var r = pixelData[i*4+0]
var g = pixelData[i*4+1]
var b = pixelData[i*4+2]
pixelData[i*4+0] = 255-r
pixelData[i*4+1] = 255-g
pixelData[i*4+2] = 255-b
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
function blur(){//要參考周圍的畫素
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
//建立作為參考的畫素
var tmpImageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var tmpPixelData = tmpImageData.data;
var blurR = 3
var totalnum = (2*blurR+1)*(2*blurR+1)
//此處迴圈需從1開始,..-1結束,否則在裡面的二層迴圈(dx=-1,dy=-1)就會越界
for (var i = blurR; i < canvasb.height-blurR; i++) {
for (var j = blurR; j < canvasb.width-blurR; j++) {
var totalr = 0,totalg = 0,totalb = 0;
//一個畫素點周圍的加上自身
for (var dx = -blurR; dx <= blurR; dx++) {
for(var dy = -blurR; dy<=blurR; dy++){
var x = i+dx;
var y = j+dy;
var p = x*canvasb.width+y
totalr += tmpPixelData[p*4+0]
totalg += tmpPixelData[p*4+1]
totalb += tmpPixelData[p*4+2]
}
}
var p = i*canvasb.width+j//每個畫素點
pixelData[p*4+0] = totalr/totalnum
pixelData[p*4+1] = totalg/totalnum
pixelData[p*4+2] = totalb/totalnum
}
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
function mosaic(){//要參考周圍的畫素
var imageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var pixelData = imageData.data;
//建立作為參考的畫素
var tmpImageData = cxta.getImageData(0, 0, canvasa.width, canvasa.height);
var tmpPixelData = tmpImageData.data;
var size = 25//馬賽克方塊的邊長
var totalnum = size*size
//此處迴圈需從1開始,..-1結束,否則在裡面的二層迴圈(dx=-1,dy=-1)就會越界
for (var i = 0; i < canvasb.height; i+=size) {
for (var j = 0; j < canvasb.width; j+=size) {
var totalr = 0,totalg = 0,totalb = 0;
//一個畫素點周圍的加上自身
for (var dx = 0; dx < size; dx++) {
for(var dy = 0; dy<size; dy++){
var x = i+dx;
var y = j+dy;
var p = x*canvasb.width+y
totalr += tmpPixelData[p*4+0]
totalg += tmpPixelData[p*4+1]
totalb += tmpPixelData[p*4+2]
}
}
var p = i*canvasb.width+j//每個畫素點
var resr = totalr/totalnum
var resg = totalg/totalnum
var resb = totalb/totalnum
for (var dx = 0; dx < size; dx++) {
for(var dy = 0; dy<size; dy++){
var x = i+dx;
var y = j+dy;
var p = x*canvasb.width+y
pixelData[p*4+0] = resr
pixelData[p*4+1] = resg
pixelData[p*4+2] = resb
}
}
}
}
cxtb.putImageData(imageData,0, 0, 0, 0, canvasb.width, canvasb.height)
}
</script>
</body>
</html>