1. ホーム
  2. Web制作
  3. html5

顔決済機能の実装をベースにしたHTML5+tracking.js

2022-01-14 01:42:16

最近、顔決済が非常にホットなので、もちろん上司もその流れに乗りたいので、顔決済のプロジェクトがあります。この記事では、HTML5環境に顔認証を実装する方法と、その開発過程で発生した問題点について解説しています。

1.カメラ1.1カメラを取得するために入力します。

html5でユーザーカメラを取得するには、inputを使用して、以下の2つの方法があります。

<input type="file" capture="camera" accept="image/*"/>

また、アルバムを開きたい場合は、このようにします。

<input type="file" accept="img/*">

しかし、どちらのアプローチにも互換性の問題があることは、使ったことのある人ならご存じでしょう。

1.2 getUserMediaはカメラ画像を取得する

getUserMediaはhtml5の新しいapiで、公式の定義のビットは

MediaDevices.getUserMedia() はユーザーにメディア入力の使用許可を求めるプロンプトを表示し、メディア入力によって MediaStream は、要求されたメディアタイプのトラックを含む。このストリームには、ビデオトラック(カメラ、ビデオキャプチャデバイス、画面共有サービスなどのハードウェアまたは仮想ビデオソースから)、オーディオトラック(マイク、A/D変換器などのハードウェアまたは仮想オーディオソースから)、または他のトラックタイプが含まれる可能性があります。

簡単に言うと、ユーザーカメラにアクセスできるようになるのです。

上記のinputと同様、この方法には互換性の問題がありますが、以下のように他のアプローチで解決することが可能です。 MediaDevices.getUserMedia() ドキュメントには、"Using the new API in older browsers"の記述があります。また、ここのWebで、getUserMediaの比較的包括的なバージョンをまとめた参考文献があり、以下のようなコードになっています。

// Accessing user media devices
getUserMedia(constraints, success, error) {
    if (navigator.mediaDevices.getUserMedia) {
        // Latest standard API
        navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
    } else if (navigator.webkitGetUserMedia) {
        //webkit kernel browser
        navigator.webkitGetUserMedia(constrains).then(success).catch(error);
    } else if (navigator.mozGetUserMedia) {
        //Firefox browser
        navagator.mozGetUserMedia(constraints).then(success).catch(error);
    } else if (navigator.getUserMedia) {
        //Older version of API
        navigator.getUserMedia(constraints).then(success).catch(error);
    } else {
        this.scanTip = "Your browser does not support access to user media devices"
    }
}

1.3 ビデオ再生画面

get deviceメソッドには、成功時と失敗時の2つのコールバック関数があります。成功した場合は、動画の再生が開始されます。ビデオ画面を再生するには、実際には、ビデオのURLを設定し、playメソッドを呼び出します。URLは、さまざまなブラウザの互換性を考慮して設定されます。

success(stream) {
    this.streamIns = stream
    // Set the URL for playback, for webkit browsers
    this.URL = window.URL || window.webkitURL
    if ("srcObject" in this.$refs.refVideo) {
        this.$refs.refVideo.srcObject = stream
    } else {
        this.$refs.refVideo.src = this.URL.createObjectURL(stream)
    }
    this.$refs.refVideo.onloadedmetadata = e => {
        // Play the video
        this.$refs.refVideo.play()
        this.initTracker()
    }
},
error(e) {
    this.scanTip = "Access to user media failed" + e.name + "," + e.message
}

注意事項

  1. ビデオ画面の再生メソッドは、onloadmetadata コールバック関数内に記述するのが最適です。そうしないと、エラーが報告される可能性があります。
  2. 動画を再生する場合、セキュリティ上の理由から、ローカル環境でテストする必要があります。つまり http://localhost/xxxx または https://xxxxx 環境でないと、クロスドメインで問題が発生する可能性があります。
  3. 以下で使用する initTracker() メソッドも、この onloadedmetadata コールバック関数内に置くことができ、そうでない場合はエラーも報告されます。

2. 顔のキャプチャ

2.1 tracking.jsで顔をキャプチャする

画面が正常に動画で再生されると、こちらのサードパーティーの機能を使って、顔認識を開始します。 tracking.js という、海外の神様が書いたJavaScriptの画像認識プラグインです。肝心のコードは以下の通りです。

// Face capture
initTracker() {
    this.context = this.$refs.refCanvas.getContext("2d") // canvas
    this.tracker = new tracking.ObjectTracker(['face']) // tracker instance
    this.tracker.setStepSize(1.7) // set step size
    this.tracker.on('track', this.handleTracked) // bind the listener method
    try {
        tracking.track('#video', this.tracker) // start tracking
    } catch (e) {
        this.scanTip = "Access to user media failed, please retry"
    }
}

顔を取り込んだら、ページ上に小さなボックスでマークアップすることで、ある程度インタラクティブな表現ができるようになります。

// The tracking event
handleTracked(e) {
    if (e.data.length === 0) {
        this.scanTip = 'No face detected'
    } else {
        if (!this.tipFlag) {
            this.scanTip = 'Detected successfully, taking a picture, please hold still for 2 seconds'
        }
        // take a picture after 1 second, only once
        if (!this.flag) {
            this.scanTip = 'Taking picture...'
            this.flag = true
            this.removePhotoID = setTimeout(() => {
                this.tackPhoto()
                this.tipFlag = true
            }, 2000)
        }
        e.data.forEach(this.plot)
    }
}

ページ上に顔を識別するためのボックスをいくつか描きます。

<div class="rect" v-for="item in profile"
             :style="{ width: item.width + 'px', height: item.height + 'px', left: item.left + 'px', top: item.top + 'px'}"></div>
// Plot the tracking box
plot({x, y, width: w, height: h}) {
    // Create the box object
    this.profile.push({ width: w, height: h, left: x, top: y })
}

2.2 写真撮影

写真を撮るには、ビデオを画像ソースとして使用し、キャンバスに画像をダウンして保存します。なお、ここでtoDataURLメソッドを使用する場合、第2パラメータqualityを0から1の間で設定することができます。

// Take a photo
tackPhoto() {
    this.context.drawImage(this.$refs.refVideo, 0, 0, this.screenSize.width, this.screenSize.height)
    // Save as base64 format
    this.imgUrl = this.saveAsPNG(this.$refs.refCanvas)
    // this.compare(imgUrl)
    this.close()
},
// Base64 to file
getBlobBydataURI(dataURI, type) {
    var binary = window.atob(dataURI.split(',')[1]);
    var array = [];
    for(var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], {
        type: type
    });
},
// Save as a png,base64 image
saveAsPNG(c) {
    return c.toDataURL('image/png', 0.3)
}

写真を撮影したら、バックエンドにファイルを送って比較・検証することができます。このとき、AliCloudのインターフェイスを使用します。

3. 最終結果

3.1 リファレンスコード・デモ

最後に デモ githubに置いてあるので、興味のある方は開いてみてください。

効果は以下の通りです。

3.2 プロジェクトへの着地

最後に、プロジェクトに入れ、最後のステップよりも何もない、比較の成功の結果によると、インターフェイスの比較を呼び出すには、成功または失敗、顔の支払いまたは元のパスワードの支払いを使用して継続するかどうかを決定するために、効果は次のとおりです。

追記:ここで顔比較に失敗したのは、マスクをしているので、歯をむき出しにして顔を見せているわけではないからです。

概要

今回の記事は、HTML5+tracking.jsによる顔認証決済についてです。HTML5の顔決済については、スクリプトハウスの過去記事を検索していただくか、引き続き以下の記事をご覧ください。