ロード中

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

WEBサイトでカメラ(WebCam)画像から目立つ人間をセグメント化して表示する ~Google MediaPipe/selfie_segmentation

WEBサイトでカメラ(WebCam)画像から「Google MediaPipe/selfie_segmentation.js」を使用して目立つ人間をセグメント化して表示します

人物を青色で塗りつぶして表示する

カメラ使用を許可してしばらくするとカメラ映像が表示されます。 カメラに人を映してください。
人物のみを青色で塗りつぶして表示し、背景はそのまま表示します。

ソースコード



<!DOCTYPE html>
<html lang="ja">
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0,user-scalable=yes">
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation@0.1/selfie_segmentation.js" crossorigin="anonymous"></script>

  <script type="module">
    let video,can,ctx;
    window.addEventListener('load', async function(event){
      video = document.querySelector('.video');
      can = document.querySelector('.can');
      ctx = can.getContext('2d');

      const selfieSegmentation = new SelfieSegmentation({locateFile: function(file){
        return `https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation@0.1/${file}`;
      }});
      selfieSegmentation.setOptions({
        //0:一般的なモデルを使用、1:ランドスケープモデルを使用
        modelSelection: 1,
      });
      selfieSegmentation.onResults(onResults);
      const camera = new Camera(video, {
        onFrame: async function(){
          await selfieSegmentation.send({image: video});
        },
        width: 640,
        height: 480
      });
      camera.start();
    });

  function onResults(results) {
    ctx.save();
    //既存のキャンバスのコンテンツの上に新しい図形を描画(既定)
    ctx.globalCompositeOperation = 'source-over';
    //透明な黒で塗りつぶす
    ctx.clearRect(0, 0, can.width, can.height);
    //人物のセグメンテーションを描画
    ctx.drawImage(results.segmentationMask, 0, 0, can.width, can.height);
    //新しい図形と出力先キャンバスが重なる部分のみ描画しそれ以外は透明
    //つまり、透明ではない部分を塗りつぶせる
    ctx.globalCompositeOperation = 'source-in';
    ctx.fillStyle = '#00F';
    ctx.fillRect(0, 0, can.width, can.height);

    //現在イメージの領域のみが描画され重なった部分は新規イメージとなる。
    //つまり、透明部分のみに描画される
    ctx.globalCompositeOperation = 'destination-atop';
    ctx.drawImage(results.image, 0, 0, can.width, can.height);
    ctx.restore();
  }

  </script>
</head>
<body>
  <div class="container">
    <video class="video" style="display:none;"></video>
    <canvas class="can" width="640" height="480" style="transform:scale(-1,1);width:90%;max-width:640px;height:auto;"></canvas>
  </div>
</body>
</html>



人物は表示して、背景のみを黒色で塗りつぶして表示する

上記とは逆に人物のみを表示して背景を黒色で塗りつぶすには、onResult関数を以下のように書き換えます。

function onResults(results) {
  ctx.save();
  //既存のキャンバスのコンテンツの上に新しい図形を描画(既定)
  ctx.globalCompositeOperation = 'source-over';
  //透明な黒で塗りつぶす
  ctx.clearRect(0, 0, can.width, can.height);
  //人物のセグメンテーションを描画
  ctx.drawImage(results.segmentationMask, 0, 0, can.width, can.height);

  //透明でない部分だけ描画
  ctx.globalCompositeOperation = 'source-atop';
  ctx.drawImage(results.image, 0, 0, can.width, can.height);

  //現在イメージの領域のみが描画され重なった部分は新規イメージとなる。
  //つまり、透明部分のみに描画される
  ctx.globalCompositeOperation = 'destination-atop';
  ctx.fillStyle = '#000';
  ctx.fillRect(0, 0, can.width, can.height);

  ctx.restore();
}