(농담 앱) laughingman

Google 크롬의 Face Detection



이전 어딘가에서 Google 크롬의 Shape Detection API가 화제가 된 것을 보았습니다. 이 안에 Face Detection이 있는 것 같기 때문에, 이것을 사용하면의 유명한 웃음 남자가 생길지도? 라고 생각해, 시험해 보았습니다. PC 1대, chrome(+설정 변경)만으로 움직일 수 있는 것이 편리하네요.

완성



h tps : // d re my t-rin g-428c. 네 tぃfy. 코m/

( github )

열면 "카메라를 사용할 수 있습니까?"라는 경고가 표시됩니다. 그것을 OK하고, 조금 기다리시면 자동으로 시작할 것.

확인한 것은 macbook+chrome(최신). windows+chrome에서도 괜찮을 것 같습니다. 2019/8 현재라면, chrome의 플래그인 「Experimental Web Platform features」를 유효하게 하지 않으면 안되는 것 같습니다. chrome://flags에서 설정할 수 있습니다.
소문에 따르면 Android의 Chrome에서도 움직이는 것 같습니다만, 가지고 있지 않습니다.

웃는 남자의 이미지를 사용하는 것은 아무리 좋지 않으므로 자신의 계정 이미지를 사용합니다. 둥근 모습이라고 생각하지만, 계정 이미지의 모티브입니다, 웃는 남자.



스마트 폰으로 youtube를 재생하고 PC 웹캠으로 촬영했습니다.
(자신의 얼굴을 사용하는 것은 동작 확인 시에 매우 힘들다…)
과연 이미지가 거칠기도 있어 백발 백중까지는 되지 않습니다만, 상당한 정밀도와 속도입니다.

기본 동영상은 Youtube-8M에서 찾았습니다. 여기 입니다.

해설



1. Face Detection·카메라 주위



이번에는 웹캠에서 실시간으로 영상을 얻어야합니다. 그래서 Face Detection 이외에 카메라의 기동도 필요하게 됩니다.
거친 흐름은 로드 완료로 카메라를 기동, 이후, 영상 로드시의 훅으로 「얼굴 검출」 「카메라 영상을 Canvas에 표시」 「아이콘을 Canvas에 표시」입니다.
카메라는 video 태그(숨기기)의 src에 카메라 영상을 설정하여 canvas에 표시하는 형태로 만들었습니다.

1. 카메라 시작



window onload에서 다음을 수행했습니다.
영상 읽어들일 때의 훅(코드중에서는 tick 함수)입니다만, 첫회만 호출해, 나머지는 스스로 재설정하는 것 같은 형태입니다. setTimeout에서 주기 처리를 할 때의 방법입니까?
canvas가 2개 있는 이유는 후술.
// カメラを取得
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
// videoタグにカメラを関連付け
const myvideo = document.querySelector("#myvideo");
myvideo.srcObject = stream;

// カメラ周りの初期設定
myvideo.onloadedmetadata = async (e) => {
    // カメラ起動
    myvideo.play();
    // canvasのサイズをカメラサイズに合わせる。vwidth, vheightはキャンバスクリア用の変数です。
    mycanvasicon.width = mycanvasvideo.width = vwidth = myvideo.videoWidth;
    mycanvasicon.height = mycanvasvideo.height = vheight = myvideo.videoHeight;

    // 初回の映像読み込み
    await tick();
};

2. 영상을 읽을 때의 후크



「얼굴 검출」 「아이콘을 Canvas에 표시」 「카메라 영상을 Canvas에 표시」입니다. 본 기사의 키모가 되는 얼굴 검출은 무려 일행.
// 顔認識のインスタンス
const detector = new FaceDetector();

// 映像読み込み時のフック
const tick = async () => {
    try {
        // アイコン画像が読み込めていたら映像表示開始。
        if (loadedmyicon) {
            // 顔検出。まさかの一行。これだけで写真中の顔全ての情報が配列で取得できます。
            const detects = await detector.detect(myvideo);

            // 以前のアイコンをクリア。これをしないとアイコンが増えていきます。
            myctxicon.clearRect(0, 0, vwidth, vheight);

            // 検出した顔すべてにアイコンを表示。
            for (const detect of detects) {
                const box = detect.boundingBox;
                // boxの大きさが顔より随分小さいので、サイズ拡大する自作関数。
                const pos = fixPosWH(box);
                // アイコン表示
                myctxicon.drawImage(myicon, pos.x, pos.y, pos.wh, pos.wh);
            }
            // カメラの画像を表示。画面いっぱいに上書きするので、前回の表示クリアは不要。
            myctxvideo.drawImage(myvideo, 0, 0, vwidth, vheight);
        }
        // 次回のカメラ映像読み込み準備。
        window.requestAnimationFrame(tick);
    } catch (e) {
        console.error(e);
    }
};

2. 기타



Face Detection 이외로 곤란한 일입니다.

1. 아이콘이 표시되지 않음



카메라의 이미지 쪽이 큰 탓인지, 아무래도 아이콘을 먼저 그려 버려, 카메라의 이미지로 덧쓰기되어 버리는 것 같습니다.

그래서 캔버스를 2개 준비해 position: fixed 로 겹쳐서 카메라를 표시하는 캔버스를 아래에, 아이콘을 표시하는 캔버스를 위로 하는 것으로 해결했습니다. 위에 쓴 캔버스가 먼저 그려집니다.

index.html
<body>
  <video id="myvideo" autoplay style="visibility: hidden"></video>
    <div id="canvases" style="position: relative">
      <canvas id="mycanvasvideo" class="mycanvas" style="position: fixed; top: 0; left: 0;"></canvas>
      <canvas id="mycanvasicon" class="mycanvas" style="position: fixed; top: 0; left: 0;"></canvas>
    </div>
</body>

덧붙여서, 아이콘 이미지의 로딩도 기다려야했습니다.

main.js
// 顔に表示するアイコンと読み込み待ちフラグ
const myicon = new Image();
myicon.src = "./icon.png";
let loadedmyicon = false;
myicon.onload = () => {
  loadedmyicon = true; // カメラの画像を反映するときにこのフラグを参照
}

이 외에, 감지되는 크기와 얼굴의 크기가 없기 때문에, 아이콘의 크기를 조정하거나와 미묘한 곤란도 있었습니다.

결론



의외로 흠뻑 작동하기에 놀랐습니다. 얼굴 숨기고 동영상 촬영할 때라든지 좋을지도 모르겠네요.

좋은 웹페이지 즐겨찾기