最近在慕课网看到一个canvas图像处理的教程,现在总结一下。
不多说其它了,开始说代码吧。
以下canvasA是原图的画布,canvasB是处理后的图像的画布
RGB通道过滤
function filter(){
var imageData = contextA.getImageData(0,0,canvasA.width,canvasA.height);
//Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
//跨域认为是被污染的
var pixelData = imageData.data;
for(var i=0; i<canvasB.width*canvasB.height; i++){
pixelData[4*i+0] = 0; //r
// pixelData[4*i+1] = 0; //g
pixelData[4*i+2] = 0; //b
}
contextB.putImageData(imageData,0,0,0,0,canvasA.width,canvasA.height);
}
可以看到其实就是获取了像素点时候,把需要过滤掉的颜色置零就可以了
灰度化
function greyEffect(){
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[4*i+0];
var g = pixelData[4*i+1];
var b = pixelData[4*i+2];
var grey = r*0.3 + g*0.59 + b*0.11;
pixelData[4*i+0] = grey;
pixelData[4*i+1] = grey;
pixelData[4*i+2] = grey;
}
contextB.putImageData(imageData,0,0,0,0,canvasA.width,canvasA.height);
}
就是通过一条算灰度的公式算出灰度值,然后把它赋给像素的rgb。
黑白二值化
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[4*i+0];
var g = pixelData[4*i+1];
var b = pixelData[4*i+2];
var grey = r*0.3 + g*0.59 + b*0.11;
if( grey > 255 / 2){
v = 255;
}else{
v = 0;
}
pixelData[4*i+0] = v;
pixelData[4*i+1] = v;
pixelData[4*i+2] = v;
}
contextB.putImageData(imageData,0,0,0,0,canvasA.width,canvasA.height);
}
就是算出灰度后,判断一下灰度是否大于255/2。如果是就认为该点是亮色,置为白色,否则,置为黑色。
反色
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[4*i+0];
var g = pixelData[4*i+1];
var b = pixelData[4*i+2];
pixelData[4*i+0] = 255 - r;
pixelData[4*i+1] = 255 - g;
pixelData[4*i+2] = 255 - b;
}
contextB.putImageData(imageData,0,0,0,0,canvasA.width,canvasA.height);
}
就是把像素的rgb变成255-rgb,就得到了相反的颜色
模糊算法
function blurEffect(){
//临时保存样板
var tmpData = contextA.getImageData(0,0,canvasA.width,canvasA.height);
var tmpPixelData = tmpData.data;
var imageData = contextA.getImageData(0,0,canvasA.width,canvasA.height);
var pixelData = imageData.data;
var blurR = 4; //模糊半径
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;
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];
}
}
pixelData[4*i+0] = totalr / totalnum;
pixelData[4*i+1] = totalg / totalnum;
pixelData[4*i+2] = totalb / totalnum;
}
}
contextB.putImageData(imageData,0,0,0,0,canvasA.width,canvasA.height);
}
这个算法比之前的复杂许多,原理就是获取当前像素点周围的像素的rgb的平均值赋给当前像素点。
边缘检测
1.roberts算子
function roberts(){
//获取像素点阵
var imageData = contextA.getImageData(0,0,canvasB.width,canvasB.height);
var pixelData = imageData.data;
//算法核心
for(var i = 0; i < canvasB.height-1; i++){
for(var j = 0; j < canvasB.width-1; j++){
//获取需要像素下标
var target = 4*(i*canvasB.width+j); //左上
var member1 = 4*(i*canvasB.width+j+1); //右上
var member2 = 4*((i+1)*canvasB.width+j); //左下
var member3 = 4*((i+1)*canvasB.width+j+1); //右下
for(var k = 0; k < 3; k++){
var gx = pixelData[target+k] - pixelData[member3+k];
var gy = pixelData[member1+k] - pixelData[member2+k];
var vc = Math.abs(gx) + Math.abs(gy);
pixelData[target+k] = vc;
}
}
}
contextB.putImageData(imageData,0,0,0,0,canvasB.width,canvasB.height);
}
这个算法更复杂了,什么阈值的我没看懂,没有用,发现效果还可以。
2.sobel算子
//sobel算子
function sobel(){
//获取像素点阵
var imageData = contextA.getImageData(0,0,canvasB.width,canvasB.height);
var pixelData = imageData.data;
var fImageData = contextA.getImageData(0,0,canvasB.width,canvasB.height);
var fData = fImageData.data; //拷贝pixelData
//旋转后的卷积核
var gxData = [
[1,0,-1],
[2,0,-2],
[1,0,-1]
];
var gyData = [
[1,2,1],
[0,0,0],
[-1,-2,-1]
];
//算法核心
for(var i = 1; i < canvasB.height-1; i++){
for(var j = 1; j < canvasB.width-1; j++){
//获取需要像素下标
var target = 4*(i*canvasB.width+j);
var gx = [0,0,0]; //r,g,b
var gy = [0,0,0];
for(var dx = -1; dx <= 1; dx++){
for(var dy = -1; dy <= 1; dy++){
var x = i + dx;
var y = j + dy;
var p = 4*(x*canvasB.width + y);
//rgb分别计算
for(var k = 0; k < 3; k++){
gx[k] += (fData[p+k] * gxData[dx+1][dy+1]);
gy[k] += (fData[p+k] * gyData[dx+1][dy+1]);
}
}
}
for(var k = 0; k < 3; k++){
var vc = Math.abs(gx[k]) + Math.abs(gy[k]);
pixelData[target+k] = vc;
}
}
}
contextB.putImageData(imageData,0,0,0,0,canvasB.width,canvasB.height);
}
效果:
demo演示
网友评论