canvas图像像素处理- 马赛克/滤镜(一)
一.要注意的问题
在chrome下会发生错误
Uncaught SecurityError:
Failed to execute ‘getImageData’ on ‘CanvasRenderingContext2D’: The canvas has been tainted by cross-origin data.
大概意思就是发生了跨域操作,也就是指图片的来源和当前的网页来源不同时,造成了跨域。
据说放到服务器上加载就会解决这个问题;我放到了本地的服务器环境可以顺利运行。以后凡是用到getImageData函数的地方,一定要使用此方法进行测试,此处不赘述。
二.知识点:
1.图片的加载:
var img=new Image();
img.src = “timg.jpg”;
img.οnlοad=function (){
context.drawImage( image , 0 , 0 );
}
2. getImageData() 从Canvas画板上取得所选区域的像素数据
①图片数据读取完成后,首先将图片数据绘制到Canvas画板上,用getImageData函数从画板上取得像素数据。
var imgData=context.getImageData(x,y,width,height);
x,y开始复制的起点坐标 width,height选择区域的长和宽
② ImageData 对象,该对象拷贝了画布指定矩形的像素数据。
最后分析结果:data: 含有ImageData 对象所有的像素,每个像素都存在着四个值的信息,分别是r,g,b,a
这是一个简单像素处理:var pixelData = imageData.data;
for(var i=0;i<canvas.width*canvas.height;i++){
pixelData[4*i+0]=0;
pixelData[4*i+1]=0;
// pixelData[4*i+2]=0;
}
这是一个简单像素深浅处理:
var pixelData = imageData.data;
for(var i=0;i<canvas.width\*canvas.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;//这个算法是图像学家研究出对RGB深浅的最好值
pixelData\[i\*4+0\] = grey;
pixelData\[i\*4+1\] = grey;
pixelData\[i\*4+2\] = grey;
\}
这是二维数组:遍历每一个像素
for( var i = 0 ; i < canvas.height ; i ++ )
for( var j = 0 ; j < canvas.width ; j ++ ){
//遍历第i行第j列的时候对应canvas的位移
var p = i*canvas.width + j;
//每一个点的像素值
pixelData[p*4+0] = r;
pixelData[p*4+1] =g;
pixelData[p*4+2] = b;
}
}
4.putImageData() 方法函数则表示将所得到的像素数据描画到Canvas画板上形成图形。
context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
其中imgdata为像素数据,dx、dy是绘制图片的定位坐标值,dirtyX、dirtyY是imgdata所要绘制图片的起始位置,dirtyXw、dirtyXh是imgdata所要绘制区域(相对imgdata的dirtyXx和dirtyXy坐标的偏移量)的宽度和高度值。这里面第4个参数以及其后的所有参数都可以省略,如果这些参数都省略了,则表示绘制整个imgdata。
5.getImageData函数从画板上取得像素数据。然后通过 putImageData() 将所取得的像素数据画到Canvas画板上
var imgData=ctx.getImageData(10,10,50,50);
整个像素数据画到Canvas画板上:ctx.putImageData(imgData,10,70);
像素数据的一部分画到Canvas画板上:ctx.putImageData(imgData,200,260,50,50,100,100);
三.特效
<html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style type="text/css"> .clearfix:after,.zn-clearfix:before{content: ""; visibility: hidden; display: block; height: 0; clear: both; } .clearfix{zoom:1;margin: 20px auto; width:1700px;} </style> </head> <body> <div class="clearfix"> <canvas id="canvasa" width="800" height="560" style="display:block;float:left;border:1px solid #aaa;"></canvas> <canvas id="canvasb" width="800" height="560" style="display:block;float:right;border:1px solid #aaa;"></canvas> </div> <script> var canvasa = document.getElementById("canvasa"); var contexta = canvasa.getContext("2d"); var canvasb = document.getElementById("canvasb"); var contextb = canvasb.getContext("2d"); var image = new Image(); window.onload = function(){ image.src = "1.jpg"; image.onload = function(){ contexta.drawImage( image , 0 , 0 , canvasa.width , canvasa.height ); } } </script> </body> </html>
(1).如何在图像中简单图像处理
灰度滤镜:
//灰度影响 function greyEffect(){ //通过 getImageData() 复制画布上指定矩形的像素数据,然后通过 putImageData() 将图像数据放回画布: var imageData = contexta.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;//这个算法是图像学家研究出对RGB深浅的最好值 pixelData[i*4+0] = grey; pixelData[i*4+1] = grey; pixelData[i*4+2] = grey; } contextb.putImageData( imageData , 0 , 0 ,0 , 0 , canvasb.width, canvasb.height); }
黑白滤镜:是指图像上只有白色,黑色;也就是rgb(255,255,255),或是rgb(0,0,0)。
//黑白滤镜:是指图像上只有白色,黑色;也就是rgb(255,255,255),或是rgb(0,0,0)。 function blackEffect(){ var imageData = contexta.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 > 125){ pv = 255; } else{ pv = 0; } pixelData[i*4+0] = pv; pixelData[i*4+1] = pv; pixelData[i*4+2] = pv; } contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasa.width , canvasa.height ); }
反色滤镜:是指图像上的每一个点的RGB值修改为255-原来的值
//反色滤镜:是指图像上的每一个点的RGB值修改为255-原来的值 function reverseEffect(){ var imageData = contexta.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; } contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasb.width , canvasb.height ); }
黑白,反色滤镜的每一个像素修改只需要参照自己当前的像素。
(2).如何在图像中参考一个像素周围的其他像素,进而实现一个图像处理
要注意:要保证周围的像素点不能被算法所修改,所以就不能仅仅使用一个imageData,需要创建一个imageData的拷贝var tmpImageData.
此后就参考tmpImageData,来修改imageData,最终把imageData结果传给putImageData,由此复制在画布上,同时当函数运行putImageData时,tmpImageData也就抛弃了。
模糊滤镜:模糊滤镜则需要参考自己周围的滤镜,图像上的每一个点的RGB值为周围的像素的平均值。
function blurEffect(){ var tmpImageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height ); var tmpPixelData = tmpImageData.data; var imageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height ); var pixelData = imageData.data; var blurR =3;//模糊的半径 //参考多少个像素点(这个区域是正方形的面积) var totalnum = (2*blurR + 1)*(2*blurR + 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;//来计算周围所有的RGB的总和 //一个像素点周围有8个像素点。 //二维循环编辑:基于中心点在x,y方向的位移的变化值,循环走了9次, //下面这个就是点周围的点循环+自身(i,j) 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]; } } //遍历第i行第j列的时候对应canvas的位移 var p = i*canvasb.width + j; //把周围的像素的平均值赋值(i,j) pixelData[p*4+0] = totalr / totalnum; pixelData[p*4+1] = totalg / totalnum; pixelData[p*4+2] = totalb / totalnum; } } contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasb.width , canvasb.height ); }
马赛克滤镜:
马赛克:一块像素的值=这块全部像素平均值
//马赛克:一块像素的值=这块全部像素平均值 function mosaicEffect(){ var tmpImageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height ); var tmpPixelData = tmpImageData.data; var imageData = contexta.getImageData( 0 , 0 , canvasa.width , canvasa.height ); var pixelData = imageData.data; //定义为一块的边长是多少(这个图像宽高的整数倍) var size = 16; var totalnum = size*size; 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; } } contextb.putImageData( imageData , 0 , 0 , 0 , 0 , canvasb.width, canvasb.height ); }
还没有评论,来说两句吧...