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

canvas圖像處理匯總

判斷 ext 黑白 return 矩陣 inf 遍歷 不足 alpha

一、canvas的情況

canvas自從出來了之後,在前端的圖像處理上面提供了各種各樣的遍歷,雖然很多的操作其實都是要應用到算法的,但是這個也給前端提供了很多的可能性,其中最終要的一個canvas函數(至少我認為)就是getImageData,這個函數可以提取圖像每個像素的RGBA值。因為有這個函數所有才有豐富多彩的canvas圖像處理。

二、預備知識

2.1 獲取一個canvas對象

<canvas id="test"></canvas>
<script>
    var test = document.querySelector("#test
");// 方法一 var test_1=document.getElementById("test");// 方法二 console.log(test); console.log(test_1); </script>

2.2 創建一個畫布的空間類型(2D,3D)

創建一個2D的畫布

var ctx = test.getContext("2d");

2.3 getImageData對象

getImageData對象可以獲取畫布中的圖片對應的所有像素的RGBA值,這個有利於我們對圖片進行重新的計算。在使用這個屬性的時候,需要配置好HTTP的訪問環境。

2.4 Uint8ClampedArray

這個代表的是一個無類型8位的字符串,也就是說明最多存儲到255

2.5 Uint8ClampedArray與getImageData對象

Uint8ClampedArray包含在getImageData對象中,getImageData除了有Uint8ClampedArray之外,還有獲取圖片數據的長度和寬度。

三、多種圖片效果canvas實現

1. 原圖

2. 反色(負片)效果

3. 去色效果

4. 單色效果

5. 中國版畫效果

6. 高斯模糊效果

7. 浮雕效果與刻雕效果

3.1 原圖

通過canvas來渲染原圖,首選我們在網上隨意找一張圖片。

技術分享圖片

  ·

window.onload = function () {
        var img = new Image();
        img.src = "rx.jpg";
        // 加載完成圖片之後才能夠執行canvas的操作
        img.onload = function () {
            var canvas = document.querySelector("#canvas");
            var cxt = canvas.getContext("2d");
            canvas.width=293;
            canvas.height=220;
            cxt.drawImage(img, 0, 0, 293, 220);
        }
    }

其中canvas的width,height屬性都是必須要設置的,不設置的話,canvas會采用默認的width=300,height=150來設置圖片。

技術分享圖片

3.2 反色(負片)效果

圖片反色的原理其實很簡單不多做解釋:將圖片中的每一個元素進行如下的公式運算就可以得到最終的結果

技術分享圖片

 window.onload = function () {
        var img = new Image();
        img.src = "rx.jpg";
        img.onload = function () {
            var canvas = document.querySelector("#canvas");
            var cxt = canvas.getContext("2d");
            canvas.width = 293;
            canvas.height = 220;
            cxt.drawImage(img, 0, 0, canvas.width, canvas.height);
            var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height);
            var imageData_length = imageData.data.length / 4;
            // 解析之後進行算法運算
            for (var i = 0; i < imageData_length; i++) {
                imageData.data[i * 4] = 255 - imageData.data[i * 4];
                imageData.data[i * 4 + 1] = 255 - imageData.data[i * 4 + 1];
                imageData.data[i * 4 + 2] = 255 - imageData.data[i * 4 + 2];
            }
            cxt.putImageData(imageData, 0, 0);

        }
    }

運行之後的效果如下:

技術分享圖片

3.3 去色效果

這裏說的去色效果與第二種效果不同的是,去色效果相當於就是老舊相機拍出來的黑白照片。

要得到去色效果的照片有很多種方法,但是鹵煮比較推崇的做法是采用基於人眼感覺的加權平均數來實現,這個算法的原理是采用人眼對RGB不同顏色的敏感程度不同,然後通過得出的加權平均數來運算出最後的結果

Gray = (Red * 0.3 + Green * 0.59 + Blue * 0.11)

代碼如下實現:

 window.onload = function () {
        var img = new Image();
        img.src = "rx.jpg";
        img.onload = function () {
            var canvas = document.querySelector("#canvas");
            var cxt = canvas.getContext("2d");
            canvas.width = 293;
            canvas.height = 220;
            cxt.drawImage(img, 0, 0, canvas.width, canvas.height);
            var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height);
            var imageData_length = imageData.data.length / 4;
            // 解析之後進行算法運算
            for (var i = 0; i < imageData_length; i++) {
                var red = imageData.data[i * 4];
                var green = imageData.data[i * 4 + 1];
                var blue = imageData.data[i * 4 + 2];
                var gray = 0.3 * red + 0.59 * green + 0.11 * blue;
                imageData.data[i * 4] = gray;
                imageData.data[i * 4 + 1] = gray;
                imageData.data[i * 4 + 2] = gray;
            }
            cxt.putImageData(imageData, 0, 0);

        }
    }

運行效果如下:

技術分享圖片

3.4 單色效果

單顏色效果原理就是將當前像素的其他色值去除。

假設我們要實現的單顏色效果是紅色,那麽實現的代碼如下:

 window.onload = function () {
        var img = new Image();
        img.src = "rx.jpg";
        img.onload = function () {
            var canvas = document.querySelector("#canvas");
            var cxt = canvas.getContext("2d");
            canvas.width = 293;
            canvas.height = 220;
            cxt.drawImage(img, 0, 0, canvas.width, canvas.height);
            var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height);
            var imageData_length = imageData.data.length / 4;
            // 解析之後進行算法運算
            for (var i = 0; i < imageData_length; i++) {
                imageData.data[i * 4 + 1] = 0;
                imageData.data[i * 4 + 2] = 0;
            }
            cxt.putImageData(imageData, 0, 0);

        }
    }

效果圖:

技術分享圖片

3.5 中國版畫效果

中國版畫不同於去色和反色的效果,在中國版畫的效果中除了黑就是白色,不存在其他的顏色,下面就是一張傳統的中國版畫的效果。

技術分享圖片

這個的實現算法比較的靈活一般是根據你要得到的效果來進行參數配置的,原理就是通過判斷當前元素的色值是否高於這個給定值,高於我們就顯示為黑色,小於我們就顯示為白色這樣的一種方法來實現的。

按照鹵煮一般的設置值來說會設置為126.因為126是2的8次方的中間數。相對來說比較的對稱

實現的代碼如下:

window.onload = function () {
        var img = new Image();
        img.src = "rx.jpg";
        img.onload = function () {
            var canvas = document.querySelector("#canvas");
            var cxt = canvas.getContext("2d");
            canvas.width = 293;
            canvas.height = 220;
            cxt.drawImage(img, 0, 0, canvas.width, canvas.height);
            var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height);
            var imageData_length = imageData.data.length / 4;
            // 解析之後進行算法運算
            for (var i = 0; i < imageData_length; i++) {
                var red = imageData.data[i * 4];
                var green = imageData.data[i * 4 + 1];
                var blue = imageData.data[i * 4 + 2];
                var gray = 0.3 * red + 0.59 * green + 0.11 * blue;
                var new_black;
                if (gray > 126) {
                    new_black = 255;
                } else {
                    new_black = 0;
                }
                imageData.data[i * 4] = new_black;
                imageData.data[i * 4 + 1] = new_black;
                imageData.data[i * 4 + 2] = new_black;
            }
            cxt.putImageData(imageData, 0, 0);

        }
    }

運行的效果如下:

技術分享圖片

如果是我們要渲染更多的黑顏色的話,我們應該要將值調高,反之將其調低,下面我們把值調到150運行一下:

技術分享圖片

3.6 高斯模糊效果

高斯模糊是一種兩維的卷積模糊操作,簡單的介紹就是通過讓圖片的每個像素與四周的像素按照某種權重進行分布求值,要了解具體的同學可以戳戳這裏。

這裏我們就展示結論,推導不做介紹(二維高斯分布函數):

技術分享圖片

我們直接貼出實現的代碼:

function gaussBlur(imgData) {
    console.log(imgData);
    var pixes = imgData.data;
    var width = imgData.width;
    var height = imgData.height;
    var gaussMatrix = [],
        gaussSum = 0,
        x, y,
        r, g, b, a,
        i, j, k, len;

    var radius = 30;
    var sigma = 5;

    a = 1 / (Math.sqrt(2 * Math.PI) * sigma);
    b = -1 / (2 * sigma * sigma);
    //生成高斯矩陣
    for (i = 0, x = -radius; x <= radius; x++, i++){
        g = a * Math.exp(b * x * x);
        gaussMatrix[i] = g;
        gaussSum += g;

    }
    //歸一化, 保證高斯矩陣的值在[0,1]之間
    for (i = 0, len = gaussMatrix.length; i < len; i++) {
        gaussMatrix[i] /= gaussSum;
    }
    //x 方向一維高斯運算
    for (y = 0; y < height; y++) {
        for (x = 0; x < width; x++) {
            r = g = b = a = 0;
            gaussSum = 0;
            for(j = -radius; j <= radius; j++){
                k = x + j;
                if(k >= 0 && k < width){//確保 k 沒超出 x 的範圍
                    //r,g,b,a 四個一組
                    i = (y * width + k) * 4;
                    r += pixes[i] * gaussMatrix[j + radius];
                    g += pixes[i + 1] * gaussMatrix[j + radius];
                    b += pixes[i + 2] * gaussMatrix[j + radius];
                    // a += pixes[i + 3] * gaussMatrix[j];
                    gaussSum += gaussMatrix[j + radius];
                }
            }
            i = (y * width + x) * 4;
            // 除以 gaussSum 是為了消除處於邊緣的像素, 高斯運算不足的問題
            // console.log(gaussSum)
            pixes[i] = r / gaussSum;
            pixes[i + 1] = g / gaussSum;
            pixes[i + 2] = b / gaussSum;
            // pixes[i + 3] = a ;
        }
    }
    //y 方向一維高斯運算
    for (x = 0; x < width; x++) {
        for (y = 0; y < height; y++) {
            r = g = b = a = 0;
            gaussSum = 0;
            for(j = -radius; j <= radius; j++){
                k = y + j;
                if(k >= 0 && k < height){//確保 k 沒超出 y 的範圍
                    i = (k * width + x) * 4;
                    r += pixes[i] * gaussMatrix[j + radius];
                    g += pixes[i + 1] * gaussMatrix[j + radius];
                    b += pixes[i + 2] * gaussMatrix[j + radius];
                    // a += pixes[i + 3] * gaussMatrix[j];
                    gaussSum += gaussMatrix[j + radius];
                }
            }
            i = (y * width + x) * 4;
            pixes[i] = r / gaussSum;
            pixes[i + 1] = g / gaussSum;
            pixes[i + 2] = b / gaussSum;
        }
    }
    console.log(imgData);
    return imgData;
}

運行之後的效果如下:

技術分享圖片

3.7 浮雕效果與刻雕效果

這裏要感謝CSDN的算法專家gloomyfish,他的博文給我提供了一個好的思路,同時根據他的一個代碼邏輯我們可以得出如下的公式:

技術分享圖片 (C常量,Xa後一個像素的RGB,Xb前一個像素的RGB)

其中color代表的是最後的色值,Xa和Xb代表的是當前像素前後兩點的RGB(中的某一個值),C代表的是一個常量【根據你的具體需要來定】

原理就是將某個像素與周邊的差值較大的檢測出來,然後替換成為255,一般我們將這個常量C設置成為128【255的一半】

/**
     * after pixel value - before pixel value + 128
     * 代碼引用自 gloomyfish
     * 浮雕效果
     */
    reliefProcess: function(context, canvasData) {
        //caontext 畫布對象  document.querySelector().getContext("2d");
        // conavas document.querySelector().getContext("2d").getImageData();
        console.log("Canvas Filter - relief process");
        var tempCanvasData = this.copyImageData(context, canvasData);
        for ( var x = 0; x < tempCanvasData.width-1; x++)
        {
            for ( var y = 0; y < tempCanvasData.height-1; y++)
            {

                // Index of the pixel in the array    
                var idx = (x + y * tempCanvasData.width) * 4;
                var bidx = ((x-1) + y * tempCanvasData.width) * 4;
                var aidx = ((x+1) + y * tempCanvasData.width) * 4;

                // calculate new RGB value
                var nr = tempCanvasData.data[aidx + 0] - tempCanvasData.data[bidx + 0] + 128;
                var ng = tempCanvasData.data[aidx + 1] - tempCanvasData.data[bidx + 1] + 128;
                var nb = tempCanvasData.data[aidx + 2] - tempCanvasData.data[bidx + 2] + 128;
                nr = (nr < 0) ? 0 : ((nr >255) ? 255 : nr);
                ng = (ng < 0) ? 0 : ((ng >255) ? 255 : ng);
                nb = (nb < 0) ? 0 : ((nb >255) ? 255 : nb);

                // assign new pixel value    
                canvasData.data[idx + 0] = nr; // Red channel    
                canvasData.data[idx + 1] = ng; // Green channel    
                canvasData.data[idx + 2] = nb; // Blue channel    
                canvasData.data[idx + 3] = 255; // Alpha channel    
            }
        }
    },

運行的圖像如下:

技術分享圖片

其中常量的數值越大,浮雕的顏色越淺,反之加深。我們把它設置到50看下效果:

技術分享圖片

刻雕效果與浮雕效果基本一樣,就是要調整公式裏面的Xa和Xb的位置,調整如下:

技術分享圖片

四、小結

由於canvas涉及到的知識點比較的深奧,所以裏面有很多的內容沒法再這裏一一的進行說明,這一篇文章也就是對於canvas實際應用的一個簡單的說明,在圖形學方面,磨皮處理和高通濾波,低通濾波等等方面的處理還沒有實現,在一些粒子化,動畫,碰撞方面也不能一一道來,深表遺憾

canvas圖像處理匯總