首页  >  文章  >  web前端  >  html5利用canvas实现图片转素描效果

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

青灯夜游
青灯夜游原创
2018-09-25 17:41:373633浏览

本章给大家介绍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实现图片转素描效果的全部代码,大家可以自己动手编译调试。

以上是html5利用canvas实现图片转素描效果的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn