<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="face-api.js"></script>
    <script src="js/Point.js"></script>
    <script src="js/triangle.js"></script>
    <script src="js/kmean.js"></script>
    <script src="js/facemarks.js"></script>
    <script src="js/extract-colors.js"></script>

</head>
<body>

<video onloadedmetadata="" id="inputVideo" style="opacity: 0" autoplay muted playsinline></video>

<canvas id="playback" style="position: absolute;left:0"></canvas>
<canvas id="overlay" style="position: absolute;left:0"></canvas>

<div id="colors"></div>
<div>


    <label><input type="checkbox" id="cb"><span id="upload">Upload an image</span></label>

    <input type="file" id="input"/>
</div>
<script>





  var TINY_FACE_DETECTOR = 1;var SSD_MOBILENETV1 = 2
  function getCurrentFaceDetectionNet() {

    selectedFaceDetector = TINY_FACE_DETECTOR
    if (selectedFaceDetector === SSD_MOBILENETV1) {
      return faceapi.nets.ssdMobilenetv1
    }
    if (selectedFaceDetector === TINY_FACE_DETECTOR) {
      return faceapi.nets.tinyFaceDetector
    }
  }
  function isFaceDetectionModelLoaded() {
    return !!getCurrentFaceDetectionNet().params
  }
window.s0 = 224;

  window.bonusAreaCalc = function(cheek) {
    var vx = cheek[0][0].subClone(cheek[0][1]),
      vy = cheek[0][1].subClone(cheek[0][2]);

    var bonusArea = [
      cheek[0][1].subClone(vx.mulClone(1/3)),
      cheek[0][1].subClone(vx.normalize().mul(3))
    ];
    bonusArea.push(bonusArea[1].subClone(vy.mul(1.5)));

    bonusArea[0].add(vy.mulClone(1/4));
    bonusArea[1].add(vy.mulClone(1/5));
    return bonusArea;
  };


  var img = new Image();

  function handleFiles(e) {
    var url = URL.createObjectURL(e.target.files[0]);

    img.onload = function() {
      //ctx.drawImage(img, 0, 0);
    };
    img.src = url;
  }



  var input = document.getElementById('input');
  var cb = document.getElementById('cb');
  var upload = document.getElementById('upload');
  cb.addEventListener('change', function() {
    if(cb.checked){
      upload.innerText = 'Upload an image'
    }else{
      upload.innerText = 'Use camera'

    }
  });
  input.addEventListener('change', handleFiles, false);

  var ctx = overlay.getContext('2d');
  var ctx2 = playback.getContext('2d');
  var canvas = overlay;
  var dims = {width:640, height: 480};

  canvas.width = playback.width = dims.width;
canvas.height = playback.height = dims.height;
    var f = async function(){
      let inputSize = s0;
      let scoreThreshold = 0.5;

var videoEl = inputVideo;
      if (!isFaceDetectionModelLoaded()){
        await getCurrentFaceDetectionNet().load( '/' );
        await faceapi.loadFaceLandmarkModel('/');
      }

      var options = new faceapi.TinyFaceDetectorOptions( { inputSize, scoreThreshold } );

      //const result = await faceapi.detectAllFaces( videoEl, options).withFaceLandmarks()


      //const dims = faceapi.matchDimensions( canvas, videoEl, true );
      //faceapi.matchDimensions( playback, videoEl, true );

      if(cb.checked){
        ctx2.drawImage( videoEl, 0, 0, dims.width, dims.height );
      }else{
        ctx2.clearRect(0,0,dims.width, dims.height);
        if(img.width/dims.width*dims.height>img.height){
          var h = img.height/(img.width/dims.width);
          ctx2.drawImage(img, 0, (dims.height-h)/2, dims.width, h);
        }else{
          var w = img.width/(img.height/dims.height);
          ctx2.drawImage(img,  (dims.width-w)/2, 0, w, dims.height);
        }

      }

      const result = await faceapi.detectSingleFace( playback, options ).withFaceLandmarks();//.withFaceDescriptor();
      if(result){




        //const resizedResults = faceapi.resizeResults(result, videoEl)
        ctx.clearRect(0,0,dims.width, dims.height)
        faceapi.draw.drawFaceLandmarks( canvas, faceapi.resizeResults( result, dims ) );

        var toPoint = function(p) {
          return new Point(p.x, p.y)
        };

        var jaw = result.landmarks.getJawOutline(),
          nose = result.landmarks.getNose(),
          mouth = result.landmarks.getMouth(),
          leftBrow = result.landmarks.getLeftEyeBrow(),
          rightBrow = result.landmarks.getRightEyeBrow(),

          leftEye = result.landmarks.getLeftEye(),
          rightEye = result.landmarks.getRightEye();

        ctx.fillStyle='blue'; mouth.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
        ctx.fillStyle='red'; jaw.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });

        ctx.fillStyle='yellow'; leftEye.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
        ctx.fillStyle='yellow'; rightEye.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });

        ctx.fillStyle='red'; leftBrow.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
        ctx.fillStyle='red'; rightBrow.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });

        ctx.fillStyle='blue'; nose.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });


        var faceMarks = new FaceMarks(result.landmarks);

        var cheek = faceMarks.marks.cheek;

        var ratio = (cheek.left.base[0].distance(cheek.left.base[1])/cheek.right.base[0].distance(cheek.right.base[1]));
        var bad = 2;



        var lips = [];


        lips = lips.concat(faceMarks.marks.lips.top);
        lips = lips.concat(faceMarks.marks.lips.bottom);

        var browsSearchArea = [];

        browsSearchArea.push([
          toPoint(leftBrow[4]),
          toPoint(leftEye[2]).middle(toPoint(leftBrow[4])),
          toPoint(leftBrow[1])
        ]);

        browsSearchArea.push([
          toPoint(rightBrow[0]),
          toPoint(rightEye[1]).middle(toPoint(rightBrow[0])),
          toPoint(rightBrow[3])
        ]);


        var eyes = [];
        if(ratio > bad){
          cheek = [cheek.left.base, cheek.left.bonus1, cheek.left.bonus2];
          browsSearchArea.pop();
          eyes = [
            faceMarks.marks.eyes.left.t1,
            faceMarks.marks.eyes.left.t2,
            faceMarks.marks.eyes.left.t3,
            faceMarks.marks.eyes.left.t4
          ];
        }else if(ratio < 1/bad){
          cheek = [cheek.right.base, cheek.right.bonus1, cheek.right.bonus2];
          browsSearchArea.shift();

          eyes = [
            faceMarks.marks.eyes.right.t1,
            faceMarks.marks.eyes.right.t2,
            faceMarks.marks.eyes.right.t3,
            faceMarks.marks.eyes.right.t4
          ];

        }else{
          cheek = [
            cheek.left.base,
            cheek.left.bonus1,
            cheek.left.bonus2,

            cheek.right.base,
            cheek.right.bonus1,
            cheek.right.bonus2
          ];

          eyes = [
            faceMarks.marks.eyes.left.t1,
            faceMarks.marks.eyes.left.t2,
            faceMarks.marks.eyes.left.t3,
            faceMarks.marks.eyes.left.t4,

            faceMarks.marks.eyes.right.t1,
            faceMarks.marks.eyes.right.t2,
            faceMarks.marks.eyes.right.t3,
            faceMarks.marks.eyes.right.t4
          ];
        }




        var drawPoly = function(poly) {

          ctx.beginPath();
          for(var i = 0,_i = poly.length; i <= _i; i++ ){
            if(i === 0){
              ctx.moveTo( poly[ i ].x, poly[ i ].y );
            }else{
              ctx.lineTo( poly[ i % _i ].x, poly[ i % _i ].y );
            }
          }
          ctx.stroke();
        };
        cheek.forEach(drawPoly);
        lips.forEach(drawPoly);
        browsSearchArea.forEach(drawPoly);
        eyes.forEach(drawPoly);








        document.getElementById('colors').innerHTML = [
          block(
            'Lips',
            extractor(ctx2, lips, 5).map(a=>a.html).join('\n')
          ),
          block(
            'Blush',
            extractor(ctx2, cheek, 5).map(a=>a.html).join('\n')
          ),
          block(
            'Brows',
            extractor(ctx2, browsSearchArea, 5).map(a=>a.html).join('\n')
          ),
          block(
            'Eyes',
            extractor(ctx2, eyes, 5, 1).map(a=>a.html).join('\n')
          )
        ].join('\n');



        //ctx2.putImageData(imageData, minX, minY);

       // debugger;
        //var means = new KMeans()

        //colors.innerHTML = block('Mouth',colors());

      }

      requestAnimationFrame(f);
      //setTimeout(f, 300)
    };


  var block = function(title, children) {
    return '<div class="block"><h2>'+ title +'</h2><p>'+children+'</p></div>'
  };
    var f0 = async function() {

      try{
        const stream = await navigator.mediaDevices.getUserMedia( { video: {} } )
        const videoEl = inputVideo
        videoEl.srcObject = stream
      }catch(e){
        console.error('no media device')
      }
        f()
    }
    f0();
</script>

</body>
</html>