1. 程式人生 > >canvas影象處理——實現濾鏡效果

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>