html5利用canvas实现图片转素描效果

2020-07-26 11:10:14
本章给大家介绍html5如何利用canvas实现图片转素描效果。有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助。

素描滤镜原理:
最基础的算法就是:
1、去色;(去色公式:gray = 0.3 red + 0.59 green + 0.11 * blue)
2、复制去色图层,并且反色;
3、对反色图像进行高斯模糊;
4、模糊后的图像叠加模式选择颜色减淡效果。
减淡公式:C =MIN( A +(A×B)/(255-B),255),其中C为混合结果,A为去色后的像素点,B为高斯模糊后的像素点。

先看看效果对比图:

1.png

sigma可以调节效果。

代码实例:

<!DOCTYPE html><html>    <head>        <meta charset="UTF-8">        <title></title>    </head>    <body>        <div id="controls">            <input type="file" name="" id="imgs" value=""/>            <br />            <!--<input type="range" name="" id="range_radius" value="10"  oninput="changeRadius()"/>            radius:<span id="value_radius">1</span>            <br />-->            <input type="range" name="" id="range_sigma" value="40"  oninput="changeSigma()"/>            sigma:<span id="value_sigma">0.8</span>            <br />            <a href="" download="canvas_love.png" id="save_href">下载</a>        </div>        <canvas id="canvas1" width="" height=""></canvas>        <br>        <canvas id="canvas2" width="" height=""></canvas>        <script type="text/javascript">            var eleImg = document.getElementById("imgs");            var eleRadius = document.getElementById("range_radius");            var eleSigma = document.getElementById("range_sigma");            var valueRadius = document.getElementById("value_radius");            var valueSigma = document.getElementById("value_sigma");            var svaeHref = document.getElementById("save_href");            var imgSrc = "img/2.jpg";            var radius = 1;            var sigma = 0.8;            eleImg.addEventListener("input",function (e) {                var fileObj = e.currentTarget.files[0]                 if (window.FileReader) {                        var reader = new FileReader();                        reader.readAsDataURL(fileObj);                        //监听文件读取结束后事件                        reader.onloadend = function (e) {                        imgSrc = e.target.result;    //e.target.result就是最后的路径地址                        sketch()                    };                    }             });            var butSave = document.getElementById("save");            function changeRadius() {                valueRadius.innerText = eleRadius.value/10;                radius = eleRadius.value/10;                sketch()            }            function changeSigma() {                valueSigma.innerText = eleSigma.value/50;                sigma = eleSigma.value/50;                sketch()            }            var canvas1 = document.querySelector("#canvas1");            var cxt1 = canvas1.getContext("2d");            var canvas = document.querySelector("#canvas2");            var cxt = canvas.getContext("2d");            function sketch() {                cxt1.clearRect(0,0,canvas1.width,canvas1.height);                 cxt.clearRect(0,0,canvas.width,canvas.height);                 var img = new Image();                img.src = imgSrc;                img.onload = function () {                    canvas1.width = 600;                    canvas1.height = (img.height/img.width)*600;                    cxt1.drawImage(img, 0, 0, canvas1.width, canvas1.height);                    canvas.width = 600;                    canvas.height = (img.height/img.width)*600;                    cxt.drawImage(img, 0, 0, canvas.width, canvas.height);                    var imageData = cxt.getImageData(0, 0, canvas.width, canvas.height);  //对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值                    var imageData_length = imageData.data.length/4;//                  var originData = JSON.parse(JSON.stringify(imageData))                    // 解析之后进行算法运算                    var originData = [];                    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;//去色                        originData.push(gray)                        originData.push(gray)                        originData.push(gray)                        originData.push(imageData.data[i * 4 + 3])                        var anti_data = 255 - gray;//取反                        imageData.data[i * 4] = anti_data;                        imageData.data[i * 4 + 1] = anti_data;                        imageData.data[i * 4 + 2] = anti_data;                    }                    imageData = gaussBlur(imageData, radius, sigma)//高斯模糊                    for (var i = 0; i < imageData_length; i++) {                        var dodge_data = Math.min((originData[i*4] + (originData[i*4]*imageData.data[i * 4])/(255-imageData.data[i * 4])), 255)//减淡                        imageData.data[i * 4] = dodge_data;                        imageData.data[i * 4 + 1] = dodge_data;                        imageData.data[i * 4 + 2] = dodge_data;                    }                    console.log(imageData)                    cxt.putImageData(imageData, 0, 0);                    var tempSrc = canvas.toDataURL("image/png");                    svaeHref.href=tempSrc;                }            }            sketch()            function gaussBlur(imgData, radius, sigma) {                var pixes = imgData.data,                    width = imgData.width,                    height = imgData.height;                radius = radius || 5;                sigma = sigma || radius / 3;                var gaussEdge = radius * 2 + 1;    // 高斯矩阵的边长                var gaussMatrix = [],                    gaussSum = 0,                    a = 1 / (2 * sigma * sigma * Math.PI),                    b = -a * Math.PI;                for (var i=-radius; i<=radius; i++) {                    for (var j=-radius; j<=radius; j++) {                        var gxy = a * Math.exp((i * i + j * j) * b);                        gaussMatrix.push(gxy);                        gaussSum += gxy;    // 得到高斯矩阵的和,用来归一化                    }                }                var gaussNum = (radius + 1) * (radius + 1);                for (var i=0; i<gaussNum; i++) {                    gaussMatrix[i] = gaussMatrix[i] / gaussSum;    // 除gaussSum是归一化                }                //console.log(gaussMatrix);                // 循环计算整个图像每个像素高斯处理之后的值                for (var x=0; x<width;x++) {                    for (var y=0; y<height; y++) {                        var r = 0,                            g = 0,                            b = 0;                        //console.log(1);                        // 计算每个点的高斯处理之后的值                        for (var i=-radius; i<=radius; i++) {                            // 处理边缘                            var m = handleEdge(i, x, width);                            for (var j=-radius; j<=radius; j++) {                                // 处理边缘                                var mm = handleEdge(j, y, height);                                var currentPixId = (mm * width + m) * 4;                                var jj = j + radius;                                var ii = i + radius;                                r += pixes[currentPixId] * gaussMatrix[jj * gaussEdge + ii];                                g += pixes[currentPixId + 1] * gaussMatrix[jj * gaussEdge + ii];                                b += pixes[currentPixId + 2] * gaussMatrix[jj * gaussEdge + ii];                            }                        }                        var pixId = (y * width + x) * 4;                        pixes[pixId] = ~~r;                        pixes[pixId + 1] = ~~g;                        pixes[pixId + 2] = ~~b;                    }                }                imgData.data = pixes;                return imgData;            }            function handleEdge(i, x, w) {                var  m = x + i;                if (m < 0) {                    m = -m;                } else if (m >= w) {                    m = w + i - x;                }                return m;            }        </script>    </body></html>

上面就是canvas实现图片转素描效果的全部代码,大家可以自己动手编译调试。