1. 程式人生 > >canvas圖像處理

canvas圖像處理

RR -o 演示 如果 算子 HA 參考 核心 邊緣檢測

最近在慕課網看到一個canvas圖像處理的教程,現在總結一下。 不多說其它了,開始說代碼吧。 以下canvasA是原圖的畫布,canvasB是處理後的圖像的畫布 RGB通道過濾

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演示

canvas圖像處理