canvas Face Whitening

Posted by mchaggis on Tue, 23 Jul 2019 11:15:10 +0200

Here's how to upload photos, rotate them, cut them, and whiten them.

I. Uploading Photos

Here are two ways to upload photos

1. This method has been abandoned. I hope to give you some hints and space to think.

a. Get the image path by changing the value of the file, and add the path to the img element, which is displayed on the page.

b. Picture upload, can be uploaded with form form, but can not get the return value, can be uploaded with 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(); // Hide input:file style, click on the avatar to upload locally
            $("#upload").on("change",function(){
                var objUrl = getObjectURL(this.files[0]) ; //The path to get the picture, which is not the local path of the picture
                if (objUrl) {
                    var img=new Image()
                    img.src=objUrl
                    img.onload= function () {
                        $("#pic").attr({
                            "src":objUrl,
                        }) ; //Store the picture path in src and display the picture
                    }
                }
            });
        });
        //Create a url that can be accessed to the file
        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', //Server-side request address for file upload
            secureuri: false, //Whether a security protocol is required is usually set to false
            fileElementId: 'upload', //ID of file upload domain
            dataType : 'content', //The return value type is generally set to json
            success: function (data)  //Server Success Response Processing Function
        
            {
                var data = eval('('+data+')')
            },
            error: function (data, status, e)//Server response failure handler
            {
                alert(e);
            }
        })
    </script>

2. Uploading photos through canvas canvas canvas, this method is recommended.

 a. Photo display. Get the path of the picture through file, draw it on canvas, and convert it with base64.

 b. Upload pictures and upload them through 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>
Summary: The reason for the second scheme is that the first method is to upload the original image directly, and the size of the image will affect the speed of the server, and the image will be too large to upload failures, while using canvas to zoom the size of the image first can complete the upload well.

2. Rotating pictures

In the process of uploading, if the picture is not processed, it will not achieve the desired effect because of the shooting angle, and will not be able to recognize the five senses.
This method mainly uses exif.js to obtain the photographic angle and rotate it.

checkImgAngel=function(n,m,h){
    EXIF.getData(n, function () {
        EXIF.getAllTags(n);
        var  imgOrient= EXIF.getTag(n, 'Orientation');
        switch(imgOrient){
            case 6://Need to rotate 90 degrees clockwise (left)
                rotateImg(n,'left');
                break;
            case 8://Need to rotate 90 degrees counterclockwise (right)
                rotateImg(n,'right');
                break;
            case 3://It needs 180 degrees of rotation.
                rotateImg(n,'right');//Turn twice
                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);
    }

    //Rotation angle is parameterized by radian
    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;
    }
}

3. Face Matching

This effect needs to be accomplished with the help of Tencent Youtu API. Tencent Youtu will provide the coordinates of five facial features. Through the clip() method of canvas, the face will be matted.

function drawLine(data,status){
    var data = setData1(data,status)//Interface returns data and processes it
    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()
}

Note: Because the coordinates returned are not all the contour coordinates of the five senses, developers need to process the data first and eliminate unnecessary coordinates.

4. Face Whitening

The main principle is the getImageData method of canvas, which obtains rgba value of each pixel and carries on the operation. In putImageData method, the image is re-rendered. First, the part of the points needing to be whitened is push ed into an array by isPointInPath method.

Processing facial points, push into the imgDataArr array

var imgDataArr=[]
function drawLine(data,status){
    var data = setData1(data,status)//Interface returns data and processes it
    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)
            }
        }
    }
}

Pixel points are acquired from facial features data returned by interface, facial models are drawn on canvas by drawLine(), and facial data are collected by isPoint InPath method.

Whitening effect

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);
}

Topics: Javascript JSON Firefox PHP JQuery