<!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>
    <script src="js/data.js"></script>
    <style>
        .color-preview {
            display: inline-block;
            font-family: monospace;
            font-size: 12px;
            width: 48px;
            padding: 4px 8px;
            border-radius: 3px;
            border: 2px solid #000;
            margin: 2px;
            text-shadow: #fff 0 0 6px;
        }
        .cp {
            width:16px;
            height: 16px;
            border: 2px solid #fff;
            transition: all 0.3s ease;
            position: relative;

        }
        .row {
            height: 32px;
        }
        .cp2 {
            width: 10px;
            height: 100%;
            display: inline-block;
        }
        .cp1 {
            width: 16px;
            height: 100%;
            padding: 0 2px;
            display: inline-block;
            margin-right: 2px;
        }
        .preview-img {
            height: 32px;
            margin: 0 8px;
        }
        .name {
            display: inline-block;
            font-family: Verdana;
            font-size: 14px;
            vertical-align: super;
        }
        .action {
            padding: 1px 2px;
            border-bottom: 1px dashed #006ed1;
            color: #006ed1;
            cursor: pointer;
        }
        .collapsed {
            display: none;
        }
        .collapsed {
            margin: 8px 0;
        }
        .matched.opened .collapsed {
            display: block;
        }
        .matched {
            padding: 8px 0;
        }
        .accuracy {
            display: inline-block;
            font-size: 12px;
            color: #999;
            font-family: monospace;
            vertical-align: super;
            margin: 0 16px;
        }
    </style>
    <script src="js/DOM.js"></script>

</head>
<body>

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

<canvas id="playback" style="position: absolute;left:0"></canvas>
<canvas id="overlay" style="position: absolute;left:0"></canvas>
<canvas id="ccolors" style="position: absolute;left:700px" width="100" height="480"></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);
      f();
    };
    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);
        }

      }

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




        //const resizedResults = faceapi.resizeResults(result, videoEl)


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

        var top = toPoint(nose[6]).lerp(nose[0], 2).y;
        if(top<0){
          var dtop = -top/dims.height;

          ctx2.drawImage(playback, dtop*dims.width/2, -top, dims.width-dtop*dims.width, dims.height+top);
          ctx2.fillStyle = GetPixel(ctx2,4,4);
          ctx2.fillRect(0,0,dims.width, -top);
          result = await faceapi.detectSingleFace( playback, options ).withFaceLandmarks();//.withFaceDescriptor();
          if(!result){
            return setTimeout( f, 300 );
          }
            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.clearRect(0,0,dims.width, dims.height);
        faceapi.draw.drawFaceLandmarks( canvas, faceapi.resizeResults( result, dims ) );

        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('ccolors').getContext('2d').clearRect(0,0,120,480);


        extracting = -1;
        updateColors([
          block(
            'Lips',
            extractor('lips',ctx2, lips, 5)
          ),
          block(
            'Blush',
            extractor('blush', ctx2, cheek, 3)
          ),
          block(
            'Brows',
            extractor('brows', ctx2, browsSearchArea, 2)
          ),
          block(
            'Eyes',
            extractor('eyes', ctx2, eyes, 6, 1)
          )
        ]);




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

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

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

      }else{
        return setTimeout(f, 300)
      }

      if(cb.checked)
      setTimeout(f, 300)
    };
  var extracting = 0;

  var block = function(title, extracted) {

    return D.div({cls: 'block'},
      D.h('h2', {}, title),
      D.h('p', {}, extracted)
    );
  };

  var updateColors;
  D.div({renderTo: document.getElementById('colors')}, function(_){updateColors = _});
    var f0 = async function() {

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

</body>
</html>