使用canvas實現區域性高斯模糊效果
阿新 • • 發佈:2018-12-20
這個功能目的是為了模糊一些人的臉部,一些文字資訊。主要用於使用者手動操作進行模糊。
實現的功能:本人實現了再pc端上面進行拖拽模糊。
實現思路:
- 首先載入圖片,然後再載入完成的回撥中,建立一個高斯模糊過的圖片畫布。
- 接著,繫結滑鼠的互動事件,在裡面獲取到在畫布上面點選的位置。通過位置獲取當前位置周圍的影象資料,進行生成圓形資料。
- 最後,使用drawImage將資料覆蓋到畫布上面。
是不是感覺思路很簡單,其實實現起來也不那麼難。
接下來,檢視一下案例:地址還沒有
最後付上原始碼
<!doctype html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>canvas畫布的高斯模糊效果</title> </head> <body> <canvas id="canvas" style="margin: 0 auto; display: block;"></canvas> <canvas id="pixelCanvas"></canvas> </body> <script> var canvas = document.getElementById('canvas'); let img = new Image(); //這裡直接修改圖片的路徑 img.src = "meinv.jpg"; img.onload = function () { let bufferCanvas = document.createElement("canvas"); let ctx = bufferCanvas.getContext('2d'); let canvasCtx = canvas.getContext("2d"); //設定canvas的寬高 canvas.height = bufferCanvas.height = img.height; canvas.width = bufferCanvas.width = img.width; //將影象繪製到canvas上面 ctx.drawImage(img, 0, 0, img.width, img.height); canvasCtx.drawImage(img, 0, 0, img.width, img.height); //從畫布獲取一半影象 var emptyData = ctx.getImageData(0, 0, img.width, img.height); //將影象資料進行高斯模糊 data.data是一個數組,每四個值代表一個畫素點的rgba的值,data.width data.height 分別代表影象資料的寬高 emptyData = gaussBlur(emptyData); //將模糊的影象資料再渲染到畫布上面 ctx.putImageData(emptyData, 0, 0); //繫結點選事件,然後通過點選事件獲取當前點選區域進行繪製 canvas.addEventListener("mousedown", function (e) { //獲取到canvas距離視窗左上角的位置 let offsetLeft = canvas.getBoundingClientRect().left; let offsetTop = canvas.getBoundingClientRect().top; //獲取到滑鼠距離視窗左上角的 let downX = e.clientX - offsetLeft; let downY = e.clientY - offsetTop; //console.log(downX, downY); generatePixel(downX, downY); function mouseMove(event) { let moveX = event.clientX - offsetLeft; let moveY = event.clientY - offsetTop; //console.log(moveX, moveY); generatePixel(moveX, moveY); } function mouseUp() { document.removeEventListener("mousemove", mouseMove); document.removeEventListener("mouseup", mouseUp); } document.addEventListener("mousemove", mouseMove); document.addEventListener("mouseup", mouseUp) }); //根據座標位置,生成附近九畫素的貼圖 let num = 50; let r = num / 2; let pixelCanvas = document.createElement("canvas"); pixelCanvas.width = pixelCanvas.height = num; let pixelCtx = pixelCanvas.getContext("2d"); function generatePixel(x, y) { let imageData = ctx.getImageData(x - r, y - r, num, num); pixelCtx.putImageData(imageData, 0, 0); //x右側超出 if (x + r > bufferCanvas.width) { let imageData = ctx.getImageData(0, y - r, x + r - bufferCanvas.width, num); pixelCtx.putImageData(imageData, bufferCanvas.width - x + num / 2, 0); } //x左側超出 if (x - r < 0) { let imageData = ctx.getImageData(bufferCanvas.width + x - r, y - r, -x + r, num); pixelCtx.putImageData(imageData, 0, 0); } //將繪製的正方形裁剪成圓形 pixelCtx.fillStyle = pixelCtx.createPattern(pixelCanvas, 'no-repeat'); pixelCtx.clearRect(0, 0, num, num); pixelCtx.arc(r, r, r, 0, Math.PI * 2); pixelCtx.fill(); canvasCtx.drawImage(pixelCanvas, x - r, y - r, num, num); //如果是在左右邊緣,需要繪製兩次 if(x + r > bufferCanvas.width){ canvasCtx.drawImage(pixelCanvas, x-r-bufferCanvas.width, y-r); } if(x-r < 0){ canvasCtx.drawImage(pixelCanvas, x-r+bufferCanvas.width, y-r); } } }; //將資料進行高斯模糊 function gaussBlur(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 = 10; 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; } } return imgData; } </script> </html>