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>

猜你喜欢

转载自blog.csdn.net/Yvonne_Lu7/article/details/81299291