zoukankan      html  css  js  c++  java
  • canvas图像处理

    最近在慕课网看到一个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演示

  • 相关阅读:
    CCF NOI1032 菱形
    CCF NOI1031 等腰三角形
    CCF NOI1030 角谷猜想
    CCF NOI1029 信息加密
    CCF NOI1028 判断互质
    CCF NOI1027 数字之和
    CCF NOI1026 表演打分
    CCF NOI1025 统计奖牌
    CCF NOI1024 因子个数
    CCF NOI1023 最大跨度
  • 原文地址:https://www.cnblogs.com/githubMYL/p/9094738.html
Copyright © 2011-2022 走看看