ロード中

トップへ(mam-mam.net/)

WEBサイトでカメラ(WebCam)画像から顔認識して目、口、鼻等の座標を取得する

検索:

WEBサイトでJavascriptを使ってカメラ(WebCam)の映像からリアルタイムに顔認識して目、口、鼻等の座標を取得して線を引く

カメラ使用を許可してください。しばらくすると、カメラ映像が表示されます

カメラに顔を映してください。顔を認識して目、口、鼻、眉、顎の輪郭に線を描画します。マスクは外してください。
(カメラ映像が正しく映らない場合は、リロードしてみてください)


使用したライブラリ

face-api.js(https://github.com/justadudewhohacks/face-api.js)を使用させていただきました。
face-api.jsのライセンス情報
MIT License
Copyright (c) 2018 Vincent Mühler

ソースコード



<script src="face-api.min.js"></script>


<div><canvas id="preview"></canvas></div>
<style>
 #preview{
   max-width:100%;
   width:640px;
   height:auto;
 }
</style>


<script>
var video,prev,prev_ctx,prevW,prevH;

async function loadImage(src){
  return new Promise(function(resolve,reject){
    let img=new Image();
    img.onload=function(){resolve(img);}
    img.onerror=function(e){reject(e);}
    img.src=src;
  });
}

window.addEventListener('DOMContentLoaded',async function(event){
  prev=document.querySelector("#preview");
  prev_ctx=prev.getContext("2d" ,{willReadFrequently:false});
  await Promise.all([
    //TinyFaceDetectorModelを使用する
    faceapi.nets.tinyFaceDetector.loadFromUri('./models'),
    //faceLandmark68TinyNetを使用する
    faceapi.nets.faceLandmark68TinyNet.loadFromUri("./models"),
  ]);

  //<video>エレメントの生成
  video=document.createElement('video');
  video.setAttribute("autoplay","");
  video.setAttribute("muted","");
  video.setAttribute("playsinline","");
  video.onloadedmetadata = function(e){video.play();};
  prev=document.getElementById("preview");
  prev_ctx=prev.getContext("2d", {willReadFrequently:true,alpha:false});

  //左右反転表示させる
  prev.style.transform="scaleX(-1)";


  //カメラ使用の許可ダイアログが表示される
  navigator.mediaDevices.getUserMedia(
    //マイクはオフ, カメラの設定   前面カメラを希望する 640×480を希望する
    //参考:背面は"environment"、全面は"user"
    {"audio":false,"video":{"facingMode":"user","width":{"ideal":640},"height":{"ideal":480}}}
  ).then( //許可された場合
    function(stream){
      video.srcObject = stream;
      //0.5秒後にスキャンする
      setTimeout(Scan,500,true);
    }
  ).catch(
    //許可されなかった場合
    function(){
      //エラー
    }
  );
});

async function Scan(first){
  if(first){
    //初回のみ設定を行う(最終的に選択されたカメラ映像のサイズが不明の為)
    //選択された幅高さ
    prevW=video.videoWidth;
    prevH=video.videoHeight;
    //内部のサイズ
    prev.setAttribute("width",prevW);
    prev.setAttribute("height",prevH);
  }

  //  webカメラの映像から顔認識を行う
  const useTinyModel = true;
  const detection = await faceapi.detectAllFaces(
      video , 
      new faceapi.TinyFaceDetectorOptions({
        inputSize:416,      //検出する最大ピクセル数、32だと最大で32x32ピクセルの顔まで検出する
        scoreThreshold:0.5, //閾値、値を大きくすると検出精度は上がるが小さくすると検出精度が下がる
      })
  ).withFaceLandmarks(true);//trueでtinyモデルを使用する
  //prev_ctx.clearRect(0, 0, prevW, prevH);
  prev_ctx.drawImage(video,0,0,prevW,prevH);
  for(let i=0;i<detection.length;i++){
    //あごのアウトライン
    const jawOutline = detection[i].landmarks.getJawOutline();
    drawPath(jawOutline,prev_ctx,2,"#00F");
    //鼻
    const nose = detection[i].landmarks.getNose();
    drawPath(nose,prev_ctx,1,"#0FF");
    //口
    const mouth = detection[i].landmarks.getMouth();
    drawPath(mouth,prev_ctx,1,"#0F0");
    //左目
    const leftEye = detection[i].landmarks.getLeftEye();
    drawPath(leftEye,prev_ctx,1,"#F00");
    //右目
    const rightEye = detection[i].landmarks.getRightEye();
    drawPath(rightEye,prev_ctx,1,"#F00");
    //左眉
    const leftEyeBrow = detection[i].landmarks.getLeftEyeBrow();
    drawPath(leftEyeBrow,prev_ctx,1,"#FF0");
    //右眉
    const rightEyeBrow = detection[i].landmarks.getRightEyeBrow();
    drawPath(rightEyeBrow,prev_ctx,1,"#FF0");
    //左目、右目、口の中心座標の配列(3個)
    const ref=detection[i].landmarks.getRefPointsForAlignment();
    for(let i=0;i<ref.length;i++){
      prev_ctx.fillStyle="#000";
      prev_ctx.beginPath();
      prev_ctx.arc(ref[i].x,ref[i].y,8,0,Math.PI*2,true);
      prev_ctx.fill();
    }
  }
  setTimeout(Scan,50,false);
}

function drawPath(arr,ctx,lineWidth,color){
  ctx.lineWidth=lineWidth;
  ctx.strokeStyle=color;
  ctx.beginPath();
  ctx.moveTo(arr[0].x,arr[0].y);
  for(let i=1;i<arr.length;i++){
    ctx.lineTo(arr[i].x,arr[i].y);
  }
  ctx.stroke();
}
</script>