canvas之人脸美白

8次阅读

共计 4807 个字符,预计需要花费 13 分钟才能阅读完成。

下面就讲解一下,移动端上传照片,旋转,抠图, 以及图片美白效果原理。

一、上传照片

下面是两种上传照片的方法

1、此方法被废弃,希望能给大家一点提示,和思考的空间

a、通过改变 file 的值获取图片路径,并把路径添加到 img 元素中,在页面中展示

b、图片上传,可以用 form 表单上传,但是获取不到返回值,可以用 ajaxfileupload.js 上传
    <img id="pic" src="image/index3_photo.png" class="index3_photo" width="167" height="218">
    <input id="upload" name="upload" accept="image/*" type="file" style="display: none"/>
    <script>
        $("#pic").click(function () {$("#upload").click(); // 隐藏了 input:file 样式后,点击头像就可以本地上传
            $("#upload").on("change",function(){var objUrl = getObjectURL(this.files[0]) ; // 获取图片的路径,该路径不是图片在本地的路径
                if (objUrl) {var img=new Image()
                    img.src=objUrl
                    img.onload= function () {$("#pic").attr({"src":objUrl,}) ; // 将图片路径存入 src 中,显示出图片
                    }
                }
            });
        });
        // 建立一個可存取到該 file 的 url
        function getObjectURL(file) {
            var url = null ;
            if (window.createObjectURL!=undefined) { // basic
                url = window.createObjectURL(file) ;
            } else if (window.URL!=undefined) {// mozilla(firefox)
                url = window.URL.createObjectURL(file) ;
            } else if (window.webkitURL!=undefined) { // webkit or chrome
                url = window.webkitURL.createObjectURL(file) ;
            }
            return url ;
        }
        $.ajaxFileUpload({
            url: '/file.php', // 用于文件上传的服务器端请求地址
            secureuri: false, // 是否需要安全协议,一般设置为 false
            fileElementId: 'upload', // 文件上传域的 ID
            dataType : 'content', // 返回值类型 一般设置为 json
            success: function (data)  // 服务器成功响应处理函数
        
            {var data = eval('('+data+')')
            },
            error: function (data, status, e)// 服务器响应失败处理函数
            {alert(e);
            }
        })
    </script>

2、通过 canvas 画布上传照片,此方法被推荐

 a、照片展示,通过 file 获取图片路径,画到 canvas 上,在用 base64 转化一下

 b、上传图片,通过 ajax post 上传
    <input type="file" id="upload">
    <canvas id="canvas"></canvas>
    <script src="jquery-2.2.1.min.js"></script>
    <script>
        $("#upload").bind("change", function () {var file=document.getElementById("upload").files[0]
            var URL=window.URL||window.webkitURL;
            var blob=URL.createObjectURL(file)
            var img=new Image()
            img.src=blob
            img.onload= function () {drawCanvas(img)
            }
        })
        var base64
        function drawCanvas(img,i){var canvas=document.createElement("canvas")
            var ctx=canvas.getContext("2d"),imgW=img.width,imgH=img.height,resultW,resultH
            resultW=imgW>640?640:imgW;
            resultH=imgH/imgW*resultW
            canvas.width=resultW
            canvas.height=resultH
            $("body").append(canvas)
            ctx.drawImage(img,0,0,resultW,resultH)
            base64 = canvas.toDataURL("image/jpeg")
        }
        $.post("url",{base64:base64}, function (data) {},"json")
    </script>
总结:之所以先第二种方案,因为第一种方法,直接上传最原始图片,图片尺寸大小都会影响服务器的速度,而且图片太大会导致上传失败,而用 canvas 先缩放图片尺寸大小,可以很好的完成上传

二、旋转图片

在上传过程中,如果不对图片进行处理,会因为拍摄角度,图片展示效果不会达到预期效果, 而且不会进行五官识别
此方法主要借助 exif.js 获取照片拍摄角度进行旋转

checkImgAngel=function(n,m,h){EXIF.getData(n, function () {EXIF.getAllTags(n);
        var  imgOrient= EXIF.getTag(n, 'Orientation');
        switch(imgOrient){
            case 6:// 需要顺时针(向左)90 度旋转
                rotateImg(n,'left');
                break;
            case 8:// 需要逆时针(向右)90 度旋转
                rotateImg(n,'right');
                break;
            case 3:// 需要 180 度旋转
                rotateImg(n,'right');// 转两次
                rotateImg(n,'right');
                break;
        }
    })
}
function rotateImg(img, direction) {var canvas = document.createElement("canvas")
    var ctx = canvas.getContext("2d")
    $(document.body).append(canvas)

    var min_step = 0;
    var max_step = 3;
    if (img == null)return;
    var height = img.height;
    var width = img.width;
    var step = 2;
    if (step == null) {step = min_step;}
    if (direction == 'right') {
        step++;
        step > max_step && (step = min_step);
    } else {
        step--;
        step < min_step && (step = max_step);
    }

    // 旋转角度以弧度值为参数
    var degree = step * 90 * Math.PI / 180;
    var ctx = canvas.getContext('2d');
    switch (step) {
        case 0:
            canvas.width = width;
            canvas.height = height;
            ctx.drawImage(img, 0, 0);
            break;
        case 1:
            canvas.width = height;
            canvas.height = width;
            ctx.rotate(degree);
            ctx.drawImage(img, 0, -height);
            break;
        case 2:
            canvas.width = width;
            canvas.height = height;
            ctx.rotate(degree);
            ctx.drawImage(img, -width, -height);

            break;
        case 3:
            canvas.width = height;
            canvas.height = width;
            ctx.rotate(degree);
            ctx.drawImage(img, -width, 0);

            break;
    }
}

三、人脸抠图

此效果需要借助腾讯优图 API 完成,腾讯优图会提供人脸五官坐标,通过 canvas 的 clip()方法,对人脸进行抠图

function drawLine(data,status){var data = setData1(data,status)// 接口返回数据并处理
    ctx.save();
    var len=data.length
    ctx.beginPath();
    ctx.moveTo(data[0].x,data[0].y)
    for(var i=1;i<len;i++){ctx.lineTo(data[i].x,data[i].y)
    }
    ctx.closePath();
    ctx.clip();
    ctx.drawImage(img, 0, 0);
    ctx.restore()}

注意:因为返回的坐标并不全是五官的轮廓坐标,所以需要开发人员先对数据进行处理,剔除不需要的坐标

四、人脸美白

主要原理是 canvas 的 getImageData 方法,获取到每一个像素点的 rgba 值,进行运算,在通过 putImageData 方法,重新渲染图片,先通过 isPointInPath 方法,把需要美白的部分点 push 到一个数组中

对脸部点进行处理,push 到 imgDataArr 数组中

var imgDataArr=[]
function drawLine(data,status){var data = setData1(data,status)// 接口返回数据并处理
    var len=data.length
    ctx.beginPath();
    ctx.moveTo(data[0].x,data[0].y)
    for(var i=1;i<len;i++){ctx.lineTo(data[i].x,data[i].y)
    }
    ctx.closePath();
    ctx.restore()
    getData()}
function getData(){
    var w = canvas.width
    var h = canvas.height;
    var resultw;
    var resulth
    for(var i=0;i<w;i++){for(var j=0;j<h;j++){
            resultw=j
            resulth=i
            if(ctx.isPointInPath(resultw,resulth)){imgDataArr.push(i*w+j)
            }
        }
    }
}

通过接口返回的脸部五官数据获取像素点,通过 drawLine()在 canvas 上画出脸部模型,在通过 isPointInPath 方法,收集脸部数据

美白效果

function setImagedata(){var imgData = ctx.getImageData(0,0,canvas.width,canvas.height)
    for(var i= 0 ;i<imgDataArr.length;i++){imgData.data[imgDataArr[i]*4+0]=imgData.data[imgDataArr[i]*4+0]+50
        imgData.data[imgDataArr[i]*4+1]=imgData.data[imgDataArr[i]*4+1]+50
        imgData.data[imgDataArr[i]*4+2]=imgData.data[imgDataArr[i]*4+2]+50
        imgData.data[imgDataArr[i]*4+3]=255
    }
    ctx.putImageData(imgData,0,0);
}

正文完
 0