---
title: AI x WebXR! フェイストラッキングを用いた擬似3D表現
tags: 
author: [Takashi Yoshinaga](https://www.docswell.com/user/Tks_Yoshinaga)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/9J2G823WJR.jpg?width=480
description: AI x WebXR! フェイストラッキングを用いた擬似3D表現 by Takashi Yoshinaga
published: February 05, 24
canonical: https://www.docswell.com/s/Tks_Yoshinaga/5YWJ6E-2024-02-05-000707
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/9J2G823WJR.jpg)

AI x WebXR!
フェイストラッキングを⽤いた擬似3D表現


# Page. 2

![Page Image](https://bcdn.docswell.com/page/DEYV6Y19EM.jpg)

まずは素材のダウンロード
http://arfukuoka.lolipop.jp
/parallax/sample.zip


# Page. 3

![Page Image](https://bcdn.docswell.com/page/VJNMZP2D78.jpg)

⾃⼰紹介
⽒名︓吉永崇(Takashi Yoshinaga)
所属︓Steampunk Digital株式会社
専⾨︓医療⽀援AR,運動計測,3D Video
コミュニティ︓ARコンテンツ作成勉強会


# Page. 4

![Page Image](https://bcdn.docswell.com/page/YE9NZ318E3.jpg)

Twitterと勉強会ページで情報を発信しています
@AR_Fukuoka
Googleで「AR勉強会」で検索


# Page. 5

![Page Image](https://bcdn.docswell.com/page/GE8K1M4Z7D.jpg)

ハッシュタグ
#AR_Fukuoka


# Page. 6

![Page Image](https://bcdn.docswell.com/page/LELZQ361JR.jpg)

本題に⼊ります


# Page. 7

![Page Image](https://bcdn.docswell.com/page/4JMV1D55JW.jpg)

今⽇のゴール
https://youtu.be/fyzXNG_0IIE
AIを⽤いた顔の認識とカメラコントロールを使った擬似3D表現


# Page. 8

![Page Image](https://bcdn.docswell.com/page/PJR2L43ZE9.jpg)

使⽤ツール︓MediaPipe &amp; TensorFlow
GoogleのMediaPipeとTnsorflow.jsがコラボでパッケージを開発。
顔認識を実現するfacemeshと⼿の認識を実現するhandposeが
提供されている中で今回はfacemeshを使⽤。
これを使う


# Page. 9

![Page Image](https://bcdn.docswell.com/page/PEXDW2417X.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 10

![Page Image](https://bcdn.docswell.com/page/3EKXVMZM7D.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 11

![Page Image](https://bcdn.docswell.com/page/L735MYD2E5.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 12

![Page Image](https://bcdn.docswell.com/page/87DD65P67G.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 13

![Page Image](https://bcdn.docswell.com/page/VJPXYG1Z78.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整
カメラ(=視点)の位置を調整


# Page. 14

![Page Image](https://bcdn.docswell.com/page/2EVLG6YMJQ.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 15

![Page Image](https://bcdn.docswell.com/page/57GX8N9XEL.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 16

![Page Image](https://bcdn.docswell.com/page/4EQ89QW5JP.jpg)

今回の進め⽅
サンプルをコピペしながら
コードの意味を解説


# Page. 17

![Page Image](https://bcdn.docswell.com/page/KJ42XNKVE1.jpg)

テンプレートの取得
https://glitch.com/~parallax-template


# Page. 18

![Page Image](https://bcdn.docswell.com/page/LE1MN5X47G.jpg)

少し下にスクロール
テンプレートの取得


# Page. 19

![Page Image](https://bcdn.docswell.com/page/GEW345NZE2.jpg)

テンプレートの取得
Remix Your Own


# Page. 20

![Page Image](https://bcdn.docswell.com/page/47ZV2N3LE3.jpg)

テンプレートの確認
index.html


# Page. 21

![Page Image](https://bcdn.docswell.com/page/YJ65V8XM7V.jpg)

テンプレートの確認


# Page. 22

![Page Image](https://bcdn.docswell.com/page/GJ5YD9XQJ4.jpg)

テンプレートの確認
① ライブラリ読み込み
② スクリプト記述
③ CGとカメラ映像
の表⽰
Lesson01


# Page. 23

![Page Image](https://bcdn.docswell.com/page/LE35MYXZJ5.jpg)

テンプレートの確認
① ライブラリ読み込み
② スクリプト記述
③ CGとカメラ映像
の表⽰


# Page. 24

![Page Image](https://bcdn.docswell.com/page/8EDD6524EG.jpg)

①ライブラリの読み込み
&lt;head&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;title&gt;AR Fukuoka&lt;/title&gt;
&lt;!̶A-Frame読み込み--&gt;
&lt;script src=&quot;https://aframe.io/releases/1.1.0/aframe.min.js&quot;&gt;&lt;/script&gt;
&lt;!--TensorFlow関連の読み込み--&gt;
&lt;script src=&quot;https://unpkg.com/@tensorflow/tfjs-core@2.1.0/dist/tf-core.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://unpkg.com/@tensorflow/tfjs-converter@2.1.0/dist/tf-converter.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://unpkg.com/@tensorflow/tfjs-backend-webgl@2.1.0/dist/tf-backend-webgl.js&quot;&gt;
&lt;/script&gt;
&lt;!--顔認識の学習モデル読み込み--&gt;
&lt;script src=&quot;https://unpkg.com/@tensorflow-models/facemesh@0.0.4/dist/facemesh.js&quot;&gt;&lt;/script&gt;
&lt;!--⾃前のスクリプトを記述--&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
&lt;/script&gt;
&lt;/head&gt;
各種ライブラリの読み込み
・ A-Frame (3D描画に使⽤)
・ TensorFlow関連 (顔認識に使⽤)


# Page. 25

![Page Image](https://bcdn.docswell.com/page/V7PXYG1VE8.jpg)

②スクリプトの記述
&lt;head&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;title&gt;AR Fukuoka&lt;/title&gt;
&lt;!̶A-Frame読み込み--&gt;
&lt;script src=&quot;https://aframe.io/releases/1.1.0/aframe.min.js&quot;&gt;&lt;/script&gt;
&lt;!--TensorFlow関連の読み込み--&gt;
&lt;script src=&quot;https://unpkg.com/@tensorflow/tfjs-core@2.1.0/dist/tf-core.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://unpkg.com/@tensorflow/tfjs-converter@2.1.0/dist/tf-converter.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://unpkg.com/@tensorflow/tfjs-backend-webgl@2.1.0/dist/tf-backend-webgl.js&quot;&gt;
&lt;/script&gt;
&lt;!--顔認識の学習モデル読み込み--&gt;
&lt;script src=&quot;https://unpkg.com/@tensorflow-models/facemesh@0.0.4/dist/facemesh.js&quot;&gt;&lt;/script&gt;
&lt;!--⾃前のスクリプトを記述--&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
次のページで解説
&lt;/script&gt;
&lt;/head&gt;


# Page. 26

![Page Image](https://bcdn.docswell.com/page/2JVLG6YR7Q.jpg)

②スクリプトの記述
&lt;!--⾃前のスクリプトを記述。今回は事前に3つの関数を⽤意。--&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
}
&lt;/script&gt;
初期化(1)
・ カメラ(PC/スマホ)の起動
・ 映像サイズや描画領域の取得
c
初期化(2)
・ 顔認識に⽤いる学習データ
の読み込み
c
毎フレーム実⾏
・ 顔の認識
・ 顔の位置を⽤いた視点変更


# Page. 27

![Page Image](https://bcdn.docswell.com/page/5EGX8N96JL.jpg)

テンプレートの確認
① ライブラリ読み込み
② スクリプト記述
③ CGとカメラ映像
の表⽰


# Page. 28

![Page Image](https://bcdn.docswell.com/page/4JQ89QW27P.jpg)

テンプレートの確認
① ライブラリ読み込み
② スクリプト記述
③ CGとカメラ映像
の表⽰


# Page. 29

![Page Image](https://bcdn.docswell.com/page/K742XNKPJ1.jpg)

③CGとカメラ映像の表⽰
&lt;!̶A-Frameを⽤いた3次元描画--&gt;
&lt;a-scene id=&quot;scene&quot; background=&quot;color: #FAFAFA&quot; style=&quot;position: absolute;&quot;&gt;
&lt;!--表⽰するオブジェクト--&gt;
&lt;a-entity id=&quot;objects&quot; position = &quot;0 0 -0.5&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-box position=&quot;-0.1 -0.05 0.1&quot; scale=&quot;0.1 0.1 0.1&quot; rotation=&quot;0 45 0&quot; color=&quot;#4CC3D9&quot; shadow&gt;&lt;/a-box&gt;
&lt;a-sphere position=&quot;0 0.015 -0.1&quot; radius=&quot;0.125&quot; color=&quot;#EF2D5E&quot; shadow&gt;&lt;/a-sphere&gt;
&lt;a-cylinder position=&quot;0.1 -0.025 0.1&quot; radius=&quot;0.05&quot; height=&quot;0.15&quot; color=&quot;#FFC65D&quot; shadow&gt;&lt;/a-cylinder&gt;
&lt;a-plane position=&quot;0 -0.11 0&quot; rotation=&quot;-90 0 0&quot; width=&quot;0.4&quot; height=&quot;0.4&quot; color=&quot;#7BC8A4&quot; shadow&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--ウィンドウの向こう側に表⽰する部屋のオブジェクト--&gt;
&lt;a-entity id=&quot;room&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-plane position=&quot;0 0.5 -0.5&quot; rotation=&quot;90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 -0.5 -0.5&quot; rotation=&quot;-90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;-0.5 0 -0.5&quot; rotation=&quot;0 90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0.5 0 -0.5&quot; rotation=&quot;0 -90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 0.0 -1&quot; rotation=&quot;0 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--カメラ(3D視点の設定)--&gt;
&lt;a-entity camera position=&quot;0 0 0&quot; &gt;&lt;/a-entity&gt;
&lt;/a-scene&gt;
&lt;!--カメラ画像表⽰--&gt;
&lt;video id=&quot;video&quot; style=&quot;position: absolute; width:320px; height:240px;&quot;&gt;&lt;/video&gt;
A-Frameで3D描画
ビデオ映像の表⽰


# Page. 30

![Page Image](https://bcdn.docswell.com/page/LJ1MN5XXEG.jpg)

③CGとカメラ映像の表⽰
この後の作業を進めるとこうなる予定(ビデオ映像はまだ表⽰されない)


# Page. 31

![Page Image](https://bcdn.docswell.com/page/GJW345NKJ2.jpg)

A-Frame解説
&lt;!̶A-Frameを⽤いた3次元描画--&gt;
&lt;a-scene id=&quot;scene&quot; background=&quot;color: #FAFAFA&quot; style=&quot;position: absolute;&quot;&gt;
&lt;!--表⽰するオブジェクト--&gt;
&lt;a-entity id=&quot;objects&quot; position = &quot;0 0 -0.5&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-box position=&quot;-0.1 -0.05 0.1&quot; scale=&quot;0.1 0.1 0.1&quot; rotation=&quot;0 45 0&quot; color=&quot;#4CC3D9&quot; shadow&gt;&lt;/a-box&gt;
&lt;a-sphere position=&quot;0 0.015 -0.1&quot; radius=&quot;0.125&quot; color=&quot;#EF2D5E&quot; shadow&gt;&lt;/a-sphere&gt;
&lt;a-cylinder position=&quot;0.1 -0.025 0.1&quot; radius=&quot;0.05&quot; height=&quot;0.15&quot; color=&quot;#FFC65D&quot; shadow&gt;&lt;/a-cylinder&gt;
&lt;a-plane position=&quot;0 -0.11 0&quot; rotation=&quot;-90 0 0&quot; width=&quot;0.4&quot; height=&quot;0.4&quot; color=&quot;#7BC8A4&quot; shadow&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--ウィンドウの向こう側に表⽰する部屋のオブジェクト--&gt;
&lt;a-entity id=&quot;room&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-plane position=&quot;0 0.5 -0.5&quot; rotation=&quot;90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 -0.5 -0.5&quot; rotation=&quot;-90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;-0.5 0 -0.5&quot; rotation=&quot;0 90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0.5 0 -0.5&quot; rotation=&quot;0 -90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 0.0 -1&quot; rotation=&quot;0 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--カメラ(3D視点の設定)--&gt;
&lt;a-entity camera position=&quot;0 0 0&quot; &gt;&lt;/a-entity&gt;
&lt;/a-scene&gt;
3D描画に関する記述
&lt;a-scene&gt;と&lt;/a-scene&gt;の間に表⽰するオブジェクトを記述


# Page. 32

![Page Image](https://bcdn.docswell.com/page/4EZV2N3NJ3.jpg)

A-Frame解説
&lt;!̶A-Frameを⽤いた3次元描画--&gt;
&lt;a-scene id=&quot;scene&quot; background=&quot;color: #FAFAFA&quot; style=&quot;position: absolute;&quot;&gt;
&lt;!--表⽰するオブジェクト--&gt;
&lt;a-entity id=&quot;objects&quot; position = &quot;0 0 -0.5&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-box position=&quot;-0.1 -0.05 0.1&quot; scale=&quot;0.1 0.1 0.1&quot; rotation=&quot;0 45 0&quot; color=&quot;#4CC3D9&quot; shadow&gt;&lt;/a-box&gt;
&lt;a-sphere position=&quot;0 0.015 -0.1&quot; radius=&quot;0.125&quot; color=&quot;#EF2D5E&quot; shadow&gt;&lt;/a-sphere&gt;
&lt;a-cylinder position=&quot;0.1 -0.025 0.1&quot; radius=&quot;0.05&quot; height=&quot;0.15&quot; color=&quot;#FFC65D&quot; shadow&gt;&lt;/a-cylinder&gt;
&lt;a-plane position=&quot;0 -0.11 0&quot; rotation=&quot;-90 0 0&quot; width=&quot;0.4&quot; height=&quot;0.4&quot; color=&quot;#7BC8A4&quot; shadow&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--ウィンドウの向こう側に表⽰する部屋のオブジェクト--&gt;
&lt;a-entity id=&quot;room&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-plane position=&quot;0 0.5 -0.5&quot; rotation=&quot;90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 -0.5 -0.5&quot; rotation=&quot;-90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;-0.5 0 -0.5&quot; rotation=&quot;0 90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0.5 0 -0.5&quot; rotation=&quot;0 -90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 0.0 -1&quot; rotation=&quot;0 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--カメラ(3D視点の設定)--&gt;
&lt;a-entity camera position=&quot;0 0 0&quot; &gt;&lt;/a-entity&gt;
&lt;/a-scene&gt;
3D描画に関する記述
&lt;a-scene&gt;と&lt;/a-scene&gt;の間に表⽰するオブジェクトを記述


# Page. 33

![Page Image](https://bcdn.docswell.com/page/Y765V8X9EV.jpg)

A-Frame解説
&lt;a-scene id=&quot;scene&quot; background=&quot;color: #FAFAFA&quot; style=&quot;position: absolute;&quot;&gt;
&lt;!--表⽰するオブジェクト--&gt;
&lt;a-entity id=&quot;objects&quot; position = &quot;0 0 -0.5&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-box position=&quot;-0.1 -0.05 0.1&quot; scale=&quot;0.1 0.1 0.1&quot; rotation=&quot;0 45 0&quot;
color=&quot;#4CC3D9&quot; shadow&gt;&lt;/a-box&gt;
&lt;a-sphere position=&quot;0 0.015 -0.1&quot; radius=&quot;0.125&quot;
color=&quot;#EF2D5E&quot; shadow&gt;&lt;/a-sphere&gt;
&lt;a-cylinder position=&quot;0.1 -0.025 0.1&quot; radius=&quot;0.05&quot; height=&quot;0.15&quot;
color=&quot;#FFC65D&quot; shadow&gt;&lt;/a-cylinder&gt;
&lt;a-plane position=&quot;0 -0.11 0&quot; rotation=&quot;-90 0 0&quot; width=&quot;0.4&quot; height=&quot;0.4&quot;
color=&quot;#7BC8A4&quot; shadow&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--ウィンドウの向こう側に表⽰する部屋のオブジェクト--&gt;
p 基本図形はa-xxxで提供されている
&lt;a-entity id=&quot;room&quot; scale=&quot;1 1 1&quot;&gt;
https://aframe.io/docs/1.1.0/primitives/
&lt;!--中略--&gt;
a-box.html
&lt;/a-entity&gt;
p position,rotationで位置や⾓度指定
&lt;!--カメラ(3D視点の設定)--&gt;
p a-entityタグで囲むことで⼦要素の
&lt;a-entity camera position=&quot;0 0 0&quot; &gt;&lt;/a-entity&gt;
オブジェクトの⼀括調整も可能


# Page. 34

![Page Image](https://bcdn.docswell.com/page/G75YD9XD74.jpg)

A-Frame解説
&lt;!̶A-Frameを⽤いた3次元描画--&gt;
&lt;a-scene id=&quot;scene&quot; background=&quot;color: #FAFAFA&quot; style=&quot;position: absolute;&quot;&gt;
&lt;!--表⽰するオブジェクト--&gt;
&lt;a-entity id=&quot;objects&quot; position = &quot;0 0 -0.5&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-box position=&quot;-0.1 -0.05 0.1&quot; scale=&quot;0.1 0.1 0.1&quot; rotation=&quot;0 45 0&quot; color=&quot;#4CC3D9&quot; shadow&gt;&lt;/a-box&gt;
&lt;a-sphere position=&quot;0 0.015 -0.1&quot; radius=&quot;0.125&quot; color=&quot;#EF2D5E&quot; shadow&gt;&lt;/a-sphere&gt;
&lt;a-cylinder position=&quot;0.1 -0.025 0.1&quot; radius=&quot;0.05&quot; height=&quot;0.15&quot; color=&quot;#FFC65D&quot; shadow&gt;&lt;/a-cylinder&gt;
&lt;a-plane position=&quot;0 -0.11 0&quot; rotation=&quot;-90 0 0&quot; width=&quot;0.4&quot; height=&quot;0.4&quot; color=&quot;#7BC8A4&quot; shadow&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--ウィンドウの向こう側に表⽰する部屋のオブジェクト--&gt;
&lt;a-entity id=&quot;room&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-plane position=&quot;0 0.5 -0.5&quot; rotation=&quot;90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 -0.5 -0.5&quot; rotation=&quot;-90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;-0.5 0 -0.5&quot; rotation=&quot;0 90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0.5 0 -0.5&quot; rotation=&quot;0 -90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 0.0 -1&quot; rotation=&quot;0 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--カメラ(3D視点の設定)--&gt;
&lt;a-entity camera position=&quot;0 0 0&quot; &gt;&lt;/a-entity&gt;
&lt;/a-scene&gt;
3D描画に関する記述
&lt;a-scene&gt;と&lt;/a-scene&gt;の間に表⽰するオブジェクトを記述


# Page. 35

![Page Image](https://bcdn.docswell.com/page/9J2G82QMJR.jpg)

A-Frame解説
&lt;!̶A-Frameを⽤いた3次元描画--&gt;
&lt;a-scene id=&quot;scene&quot; background=&quot;color: #FAFAFA&quot; style=&quot;position: absolute;&quot;&gt;
&lt;!--表⽰するオブジェクト--&gt;
&lt;a-entity id=&quot;objects&quot; position = &quot;0 0 -0.5&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-box position=&quot;-0.1 -0.05 0.1&quot; scale=&quot;0.1 0.1 0.1&quot; rotation=&quot;0 45 0&quot; color=&quot;#4CC3D9&quot; shadow&gt;&lt;/a-box&gt;
&lt;a-sphere position=&quot;0 0.015 -0.1&quot; radius=&quot;0.125&quot; color=&quot;#EF2D5E&quot; shadow&gt;&lt;/a-sphere&gt;
&lt;a-cylinder position=&quot;0.1 -0.025 0.1&quot; radius=&quot;0.05&quot; height=&quot;0.15&quot; color=&quot;#FFC65D&quot; shadow&gt;&lt;/a-cylinder&gt;
&lt;a-plane position=&quot;0 -0.11 0&quot; rotation=&quot;-90 0 0&quot; width=&quot;0.4&quot; height=&quot;0.4&quot; color=&quot;#7BC8A4&quot; shadow&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--ウィンドウの向こう側に表⽰する部屋のオブジェクト--&gt;
&lt;a-entity id=&quot;room&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-plane position=&quot;0 0.5 -0.5&quot; rotation=&quot;90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 -0.5 -0.5&quot; rotation=&quot;-90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;-0.5 0 -0.5&quot; rotation=&quot;0 90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0.5 0 -0.5&quot; rotation=&quot;0 -90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 0.0 -1&quot; rotation=&quot;0 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!--カメラ(3D視点の設定)--&gt;
&lt;a-entity camera position=&quot;0 0 0&quot; &gt;&lt;/a-entity&gt;
&lt;/a-scene&gt;
3D描画に関する記述
&lt;a-scene&gt;と&lt;/a-scene&gt;の間に表⽰するオブジェクトを記述


# Page. 36

![Page Image](https://bcdn.docswell.com/page/DEYV6YWPEM.jpg)

A-Frame解説
&lt;!--ウィンドウの向こう側に表⽰する部屋のオブジェクト--&gt;
&lt;a-entity id=&quot;room&quot; scale=&quot;1 1 1&quot;&gt;
&lt;a-plane position=&quot;0 0.5 -0.5&quot; rotation=&quot;90 0 0&quot; src=&quot;画像URL &quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 -0.5 -0.5&quot; rotation=&quot;-90 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;-0.5 0 -0.5&quot; rotation=&quot;0 90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0.5 0 -0.5&quot; rotation=&quot;0 -90 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;a-plane position=&quot;0 0.0 -1&quot; rotation=&quot;0 0 0&quot; src=&quot;画像URL&quot;&gt;&lt;/a-plane&gt;
&lt;/a-entity&gt;
&lt;!-- カメラ(3D視点の設定)--&gt;
&lt;a-entity camera position=&quot;0 0 0&quot; &gt;&lt;/a-entity&gt;
p 板(a-plane)を配置して天井・床・壁を作成
p srcの右辺でテクスチャが画像を指定
p サイズは1m3相当。親要素のa-entityの
scaleを編集して縦・横・奥⾏きを調節可能
p &lt;a-entity camera&gt;で視点の位置を設定


# Page. 37

![Page Image](https://bcdn.docswell.com/page/VJNMZP9M78.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 38

![Page Image](https://bcdn.docswell.com/page/YE9NZ32WE3.jpg)

ビデオを描画する
&lt;script type=&quot;text/javascript&quot;&gt;
//ビデオを扱う変数
var video;
//ページを読み込み終わったら実⾏
window.onload = function() {
//カメラ画像のサイズ設定(とりあえず640x480くらい)
let constraints = { video: { width: 640, height: 480 } };
//カメラデバイスの取得
navigator.mediaDevices.getUserMedia(constraints).then(
function(mediaStream) {
//body内の描画領域(id=video)を取得
video = document.getElementById(&quot;video&quot;);
//リアルタイム映像をvideo要素に対応づける
video.srcObject = mediaStream;
//準備が整ったら再⽣
video.onloadedmetadata = function(e) {
video.play();
};
}
);
}
&lt;/script&gt;
Lesson02


# Page. 39

![Page Image](https://bcdn.docswell.com/page/GE8K1M5R7D.jpg)

動作確認
Show


# Page. 40

![Page Image](https://bcdn.docswell.com/page/LELZQ3Y2JR.jpg)

動作確認
In a New Window


# Page. 41

![Page Image](https://bcdn.docswell.com/page/4JMV1DN9JW.jpg)

動作確認
カメラの映像が表⽰されればOK
うまく動かない場合は[完成品]フォルダの中の2.txtをコピペで差し替える


# Page. 42

![Page Image](https://bcdn.docswell.com/page/PJR2L4D9E9.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 43

![Page Image](https://bcdn.docswell.com/page/PEXDW2137X.jpg)

顔認識の学習モデル読み込み
//ビデオを扱う変数
var video;
//ページを読み込み終わったら実⾏
window.onload = function() {
//カメラ画像のサイズ設定
var constraints = { video: { width: 640, height: 480 } };
//カメラデバイスの取得
navigator.mediaDevices.getUserMedia(constraints).then(
function(mediaStream) {
//body内のid=videoの要素を取得
video = document.getElementById(&quot;video&quot;);
//リアルタイム映像をvideo要素に対応づける
video.srcObject = mediaStream;
//準備が整ったら再⽣
video.onloadedmetadata = function(e) {
video.play();
//顔認識の学習モデルを読み込む(このあと記述)
LoadFaceModel();
};
}
);
};
Lesson03


# Page. 44

![Page Image](https://bcdn.docswell.com/page/3EKXVM2N7D.jpg)

顔認識の学習モデル読み込み
//ビデオを扱う変数
var video;
//顔認識の学習モデル
var model;
//ページを読み込み終わったら実⾏
window.onload = function() {
//カメラ画像のサイズ設定
let constraints = { video: { width: 640, height: 480 } };
//カメラデバイスの取得
navigator.mediaDevices.getUserMedia(constraints).then(
//スペースの都合上省略
//カメラの準備が整ったらLoadFaceModelを呼び出す
);
}
//トラッキング開始準備の関数
async function LoadFaceModel(){
//顔認識のための学習モデル読み込み
model = await facemesh.load();
//顔認識のループ(次のステップで使⽤)
FaceTracking ();
}
Lesson04


# Page. 45

![Page Image](https://bcdn.docswell.com/page/L735MY4ZE5.jpg)

顔の認識
//ビデオを扱う変数
var video;
//顔認識の学習モデル
var model;
window.onload = function() {/*スペースの都合上省略*/ };
async function LoadFaceModel(){
model = await facemesh.load();
FaceTracking ();
}
//顔検出と描画のループ
async function FaceTracking () {
//顔の検出
let predictions = await model.estimateFaces(video);
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//検出された顔の情報にアクセスして表⽰
console.log(predictions[0]);
}
requestAnimationFrame(FaceTracking);
}
Lesson05


# Page. 46

![Page Image](https://bcdn.docswell.com/page/87DD65Q47G.jpg)

動作確認
カメラの映像は表⽰されるけど、
学習データの読み込みに時間がかかる


# Page. 47

![Page Image](https://bcdn.docswell.com/page/VJPXYGLV78.jpg)

動作確認(Safari)
①適当な箇所を右クリック
②要素を調査とか
要素の詳細を表⽰


# Page. 48

![Page Image](https://bcdn.docswell.com/page/2EVLG6QRJQ.jpg)

動作確認(Safari)
①コンソール
②検出結果


# Page. 49

![Page Image](https://bcdn.docswell.com/page/57GX8NW6EL.jpg)

認識結果の内訳
faceInViewConfidence: 1, //顔らしさ(信頼度 0~1)
boundingBox: { // 顔を囲む矩形の⾓の座標
topLeft: [232.28, 145.26],
bottomRight: [449.75, 308.36],
},
mesh: [ // 顔の各特徴の座標[x,y,z] (認識⽤に192x192pxに縮⼩した画像上の座標)
[92.07, 119.49, -17.54], [91.97, 102.52, -30.54], ...
],
scaledMesh: [// 顔の各特徴の座標[x,y,z] (ビデオ画像の座標)
[322.32, 297.58, -17.54], [322.18, 263.95, -30.54], ...
],
annotations: { //顔のパーツと座標の組み合わせ
silhouette: [
[326.19, 124.72, -3.82], [351.06, 126.30, -3.00], ...
],
今回はboundingBoxの
...
中⼼を使⽤する︕
}


# Page. 50

![Page Image](https://bcdn.docswell.com/page/4EQ89Q32JP.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整
カメラ(=視点)の位置を調整


# Page. 51

![Page Image](https://bcdn.docswell.com/page/KJ42XN1PE1.jpg)

顔の中⼼位置を算出
&lt;script type=&quot;text/javascript&quot;&gt;
var video; //ビデオを扱う変数
var model; //顔認識の学習モデル
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
&lt;/script&gt;
c
}
次はここを編集


# Page. 52

![Page Image](https://bcdn.docswell.com/page/LE1MN5GX7G.jpg)

顔の中⼼位置を算出
//ビデオを扱う変数
var video;
//顔認識の学習モデル
var model;
window.onload = function() {/*スペースの都合上省略*/ };
async function LoadFaceModel(){{/*スペースの都合上省略*/ }
c
async function FaceTracking () {
//顔の検出
let predictions = await model.estimateFaces(video);
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//バウンディングボックスとその左上・右下の座標を取得
let keypoints = predictions[0].boundingBox;
let topLeft=keypoints.topLeft;
let bottomRight=keypoints.bottomRight;
//中⼼を計算
let cX=((topLeft[0]+bottomRight[0])/2);
let cY=(topLeft[1]+bottomRight[1])/2;
console.log(predictions[0]);
}
requestAnimationFrame(FaceTracking);
}
ここに注⽬︕


# Page. 53

![Page Image](https://bcdn.docswell.com/page/GEW345KKE2.jpg)

顔の中⼼位置を算出
//ビデオを扱う変数
var video;
//顔認識の学習モデル
var model;
window.onload = function() {/*スペースの都合上省略*/ };
async function LoadFaceModel(){{/*スペースの都合上省略*/ }
async function FaceTracking () {
//顔の検出
let predictions = await model.estimateFaces(video);
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//バウンディングボックスとその左上・右下の座標を取得
let keypoints = predictions[0].boundingBox;
let topLeft=keypoints.topLeft;
let bottomRight=keypoints.bottomRight;
//中⼼を計算
let cX=(topLeft[0]+bottomRight[0])/2;
let cY=(topLeft[1]+bottomRight[1])/2;
console.log(cX+&quot;, &quot;+cY);
}
requestAnimationFrame(FaceTracking);
}
Lesson06


# Page. 54

![Page Image](https://bcdn.docswell.com/page/47ZV2NZNE3.jpg)

このあとやりたいこと
x
-1
Y
Y
x
-1
1
1
p
p
p
p
原点は画像の左上
座標はピクセルで表現
画素数はカメラによって違う
xy座標(ピクセル)を顔の位置と
して反映させると値が⼤きすぎる
p
p
p
p
原点は画像の中央
座標は画像中の相対位置
X,Y共に-1~1正規化
カメラの画素数に依存せず
座標を扱うことが可能


# Page. 55

![Page Image](https://bcdn.docswell.com/page/YJ65V8Z97V.jpg)

顔の中⼼位置を正規化
//ビデオを扱う変数
var video;
//顔認識の学習モデル
var model;
window.onload = function() {/*スペースの都合上省略*/ };
async function LoadFaceModel(){{/*スペースの都合上省略*/ }
async function FaceTracking () {
//顔の検出
let predictions = await model.estimateFaces(video);
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//バウンディングボックスとその左上・右下の座標を取得
let keypoints = predictions[0].boundingBox;
let topLeft=keypoints.topLeft;
let bottomRight=keypoints.bottomRight;
//中⼼を計算
let cX=(topLeft[0]+bottomRight[0])/video.videoWidth-1;
let cY=(topLeft[1]+bottomRight[1])/video.videoHeight-1;
console.log(cX+&quot;, &quot;+cY);
}
requestAnimationFrame(FaceTracking);
}
Lesson07


# Page. 56

![Page Image](https://bcdn.docswell.com/page/GJ5YD9WDJ4.jpg)

顔の中⼼位置を正規化
//ビデオを扱う変数
var video;
//顔認識の学習モデル
var model;
window.onload = function() {/*スペースの都合上省略*/ };
async function LoadFaceModel(){{/*スペースの都合上省略*/ }
async function FaceTracking () {
//顔の検出
let predictions = await model.estimateFaces(video);
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//バウンディングボックスとその左上・右下の座標を取得
let keypoints = predictions[0].boundingBox;
let topLeft=keypoints.topLeft;
let bottomRight=keypoints.bottomRight;
//中⼼を計算
let cX=(topLeft[0]+bottomRight[0])/video.videoWidth-1;
let cY=(topLeft[1]+bottomRight[1])/video.videoHeight-1;
console.log(cX+&quot;, &quot;+cY);
//console.log(cX+&quot;,
&quot;+cY);
}
⽂字の表⽰は不要
requestAnimationFrame(FaceTracking);
}


# Page. 57

![Page Image](https://bcdn.docswell.com/page/9E2G822MER.jpg)

カメラの動きへの反映
&lt;script type=&quot;text/javascript&quot;&gt;
var video; //ビデオを扱う変数
var model; //顔認識の学習モデル
var camera; //カメラ(視点)を扱う変数
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
}
&lt;/script&gt;
カメラ(=視点)の位置を調整
Lesson08


# Page. 58

![Page Image](https://bcdn.docswell.com/page/D7YV6YYP7M.jpg)

カメラの動きへの反映
&lt;script type=&quot;text/javascript&quot;&gt;
var video; //ビデオを扱う変数
var model; //顔認識の学習モデル
var camera; //カメラ(視点)を扱う変数
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
}
&lt;/script&gt;
c
};
次はここを編集


# Page. 59

![Page Image](https://bcdn.docswell.com/page/VENMZPPMJ8.jpg)

カメラの動きへの反映
window.onload = function() {
//a-scene(id=scene)を取得
let scene = document.getElementById(&#039;scene&#039;);
//A-Frameのカメラを取得
camera= scene.camera;
//カメラ画像のサイズ設定(とりあえず640x480くらい)
let constraints = { video: { width: 640, height: 480 } };
//カメラデバイスの取得
navigator.mediaDevices.getUserMedia(constraints).then(
function(mediaStream) {
video = document.getElementById(&quot;video&quot;);
video.srcObject = mediaStream;
video.onloadedmetadata = function(e) {
video.play();
LoadFaceModel();
};
}
);
Lesson09
};


# Page. 60

![Page Image](https://bcdn.docswell.com/page/Y79NZ33W73.jpg)

カメラの動きへの反映
&lt;script type=&quot;text/javascript&quot;&gt;
var video; //ビデオを扱う変数
var model; //顔認識の学習モデル
var camera; //カメラ(視点)を扱う変数
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
&lt;/script&gt;
c
}
次はここを編集


# Page. 61

![Page Image](https://bcdn.docswell.com/page/G78K1MMRJD.jpg)

カメラの動きへの反映
async function FaceTracking(){
//顔の検出
let predictions = await model.estimateFaces(video);
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//バウンディングボックスとその左上・右下の座標を取得
let keypoints = predictions[0].boundingBox;
let topLeft=keypoints.topLeft;
let bottomRight=keypoints.bottomRight;
//中⼼を計算(-1~1で正規化)
let cX=(topLeft[0]+bottomRight[0])/video.videoWidth-1;
let cY=(topLeft[1]+bottomRight[1])/video.videoHeight-1;
//カメラの位置を操作
camera.position.x=-cX; //左右反転
camera.position.y=-cY; //上下反転
camera.position.z=2.5; //奥⾏きは分からないので適当に設定
}
window.requestAnimationFrame(FaceTracking);
Lesson10
}


# Page. 62

![Page Image](https://bcdn.docswell.com/page/L7LZQ332ER.jpg)

動作確認
顔の位置に連動


# Page. 63

![Page Image](https://bcdn.docswell.com/page/4EMV1DD9EW.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 64

![Page Image](https://bcdn.docswell.com/page/PER2L44979.jpg)

部屋サイズの設定
&lt;script type=&quot;text/javascript&quot;&gt;
var video; //ビデオを扱う変数
var model; //顔認識の学習モデル
var camera; //カメラ(視点)を扱う変数
var canvas: //描画領域
var screenWidth, screenHeight; //表⽰領域のサイズ
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
}
&lt;/script&gt;
Lesson11


# Page. 65

![Page Image](https://bcdn.docswell.com/page/P7XDW223JX.jpg)

部屋サイズの設定
&lt;script type=&quot;text/javascript&quot;&gt;
var video; //ビデオを扱う変数
var model; //顔認識の学習モデル
var camera; //カメラ(視点)を扱う変数
var canvas; //描画領域
var screenWidth, screenHeight; //表⽰領域のサイズ
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
}
&lt;/script&gt;
c
};
次はここを編集


# Page. 66

![Page Image](https://bcdn.docswell.com/page/37KXVMMNJD.jpg)

部屋サイズの設定
window.onload = function() {
//キャンバス領域を取得
canvas=document.getElementsByClassName(&#039;a-canvas&#039;)[0];
};
//a-scene(id=scene)を取得
let scene = document.getElementById(&#039;scene&#039;);
//A-Frameのカメラを取得
camera= scene.camera;
//カメラ画像のサイズ設定(とりあえず640x480くらい)
let constraints = { video: { width: 640, height: 480 } };
//カメラデバイスの取得
navigator.mediaDevices.getUserMedia(constraints).then(
function(mediaStream) {
//中略
}
);
Lesson12


# Page. 67

![Page Image](https://bcdn.docswell.com/page/LJ35MYYZ75.jpg)

部屋サイズの設定
&lt;script type=&quot;text/javascript&quot;&gt;
var video; //ビデオを扱う変数
var model; //顔認識の学習モデル
var camera; //カメラ(視点)を扱う変数
var canvas; //描画領域
var screenWidth, screenHeight; //表⽰領域のサイズ
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
&lt;/script&gt;
c
}
次はここを編集


# Page. 68

![Page Image](https://bcdn.docswell.com/page/8JDD6554JG.jpg)

部屋サイズの設定
async function FaceTracking(){
//描画領域のサイズが変わった場合
if(screenWidth!=canvas.width || screenHeight!=canvas.height){
screenWidth=canvas.width;
screenHeight=canvas.height;
//部屋の横幅を1に固定した場合の⾼さを計算
let height=screenHeight/screenWidth;
//部屋のオブジェクトを取得してサイズを変更
let room= document.getElementById(&#039;room&#039;);
room.setAttribute(&#039;scale&#039;, { x: 1, y: height, z: 1 });
}
//顔の検出
let predictions = await model.estimateFaces(video);
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//中略
}
window.requestAnimationFrame(FaceTracking);
Lesson13
}


# Page. 69

![Page Image](https://bcdn.docswell.com/page/VEPXYGGVJ8.jpg)

動作確認
頭の位置と視点は連動するが、部屋がモニタに固定されない


# Page. 70

![Page Image](https://bcdn.docswell.com/page/27VLG66REQ.jpg)

原因と解決⽅法
【現状】
p カメラの視野⾓は固定されている
p カメラが部屋のモデルから離れると
視野内に他の領域も⼊ってくる
理想的には・・・
p カメラ(頭)の位置に応じて視野⾓が
部屋の上下左右にフィットするように
変化してくれると良い
【理想】


# Page. 71

![Page Image](https://bcdn.docswell.com/page/5JGX8NN67L.jpg)

ハンズオン⼿順
p 3D表⽰のテンプレート取得
p ビデオ画像の取得と表⽰
p facemeshで顔の認識
p 顔とカメラの位置を連動
p 奥⾏き空間のサイズ調整
p 画⾓の調整


# Page. 72

![Page Image](https://bcdn.docswell.com/page/47Q89QQ2EP.jpg)

CGの世界の視野設定
描画可能エリア
top
left
ar
e
n
r
fa
背後の世界を
スクリーンに投影
right
bottom
【開発者にとっての視野設定】
p 描画可能なエリアをコンピュータに伝える⼿段。
p カメラを起点とした奥⾏(near far), 横⽅向の座標(left right),
縦⽅向の座標(top bottom)の6パラメータで数式化して表現。


# Page. 73

![Page Image](https://bcdn.docswell.com/page/KE42XNNP71.jpg)

描画判定(コンピュータ側の仕事)
1
0
-1
near
x
top
left
1
right
y
z
far
-1
1
-1
bottom
【前後範囲の内外判定】
near~farのzを-1~1とし、CGのz座標を変換したときに範囲内なら描画
【スクリーンの内外判定】
left~rightのxを-1~1、bottom~topのyを-1~1とし、スクリーン(near)
に投影した(座標変換した)ときのxy座標が範囲内なら描画


# Page. 74

![Page Image](https://bcdn.docswell.com/page/L71MN55XJG.jpg)

描画判定(開発者側の仕事)
z c)
y
c,
,
(x c
near
bottom
0
zs
x
1
top
right
near
-1
y
z
1
left
right
left
top
-1
1
(xs,ys)
-1
bottom
p left, right, top, bottom, near, farを使って描画領域を決定する
p カメラを原点にした3次元座標(xc,yc,zc)を、描画領域の座標系での
座標(xs,ys,zs)に変換するためのルール(式)をコンピュータ側に教える


# Page. 75

![Page Image](https://bcdn.docswell.com/page/G7W3455K72.jpg)

変換式
【やりたいこと】
CGの3D座標
xc, yc, zc
変換ルールをUnityがわかる形(数式)で表現
1
いい感じに変換
0
-1
𝑥!
𝑦!
𝑧!
1
= 座標変換
top
left
z
描画判定用の座標系
xs, ys, zs
1
near
right
y
【数式で書くと】
far
-1
1
x
-1
bottom
4×4の⾏列で表現 ←さっきの6パラメータで作れる
𝑥&quot;
𝑦&quot;
𝑧&quot;
1
−
1
𝑧!
2 𝑛𝑒𝑎𝑟
𝑟𝑖𝑔ℎ𝑡 − 𝑙𝑒𝑓𝑡
0
0
2 𝑛𝑒𝑎𝑟
𝑡𝑜𝑝 − 𝑏𝑜𝑡𝑡𝑜𝑚
0
0
0
0
𝑟𝑖𝑔ℎ𝑡 + 𝑙𝑒𝑓𝑡
𝑟𝑖𝑔ℎ𝑡 − 𝑙𝑒𝑓𝑡
𝑡𝑜𝑝 + 𝑏𝑜𝑡𝑡𝑜𝑚
𝑡𝑜𝑝 − 𝑏𝑜𝑡𝑡𝑜𝑚
𝑓𝑎𝑟 + 𝑛𝑒𝑎𝑟
−
𝑓𝑎𝑟 − 𝑛𝑒𝑎𝑟
−1
0
0
−
2𝑓𝑎𝑟 𝑛𝑒𝑎𝑟
𝑓𝑎𝑟 − 𝑛𝑒𝑎𝑟
0


# Page. 76

![Page Image](https://bcdn.docswell.com/page/4JZV2NNN73.jpg)

変換⾏列作成スクリプト
c
2 𝑛𝑒𝑎𝑟
𝑟𝑖𝑔ℎ𝑡 − 𝑙𝑒𝑓𝑡
0
0
0
𝑟𝑖𝑔ℎ𝑡 + 𝑙𝑒𝑓𝑡
0
𝑟𝑖𝑔ℎ𝑡 − 𝑙𝑒𝑓𝑡
2 𝑛𝑒𝑎𝑟
𝑡𝑜𝑝 + 𝑏𝑜𝑡𝑡𝑜𝑚
0
𝑡𝑜𝑝 − 𝑏𝑜𝑡𝑡𝑜𝑚 𝑡𝑜𝑝 − 𝑏𝑜𝑡𝑡𝑜𝑚
𝑓𝑎𝑟 + 𝑛𝑒𝑎𝑟
2𝑓𝑎𝑟 𝑛𝑒𝑎𝑟
0
−
−
𝑓𝑎𝑟 − 𝑛𝑒𝑎𝑟
𝑓𝑎𝑟 − 𝑛𝑒𝑎𝑟
0
−1
0
0


# Page. 77

![Page Image](https://bcdn.docswell.com/page/YE65V889JV.jpg)

画⾓の調整
&lt;script type=&quot;text/javascript&quot;&gt;
var
var
var
var
var
video; //ビデオを扱う変数
model; //顔認識の学習モデル
camera; //カメラ(視点)を扱う変数
canvas; //描画領域
screenWidth, screenHeight; //表⽰領域のサイズ
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
}
c
&lt;/script&gt;
次はここに関数を追加


# Page. 78

![Page Image](https://bcdn.docswell.com/page/GE5YD99DE4.jpg)

画⾓の調整
function PerspectiveOffCenter(left, right, bottom, top, near, far)
{
var x = 2.0 * near / (right - left);
var y = 2.0 * near / (top - bottom);
var a = (right + left) / (right - left);
var b = (top + bottom) / (top - bottom);
var c = -(far + near) / (far - near);
var d = -(2.0 * far * near) / (far - near);
var e = -1.0;
var m = new THREE.Matrix4();
m.set( x,0,a,0, 0,y,b,0, 0,0,c, d,0,0, e,0);
return m;
}
Lesson14


# Page. 79

![Page Image](https://bcdn.docswell.com/page/972G825M7R.jpg)

Left/Right/Top/Bottom
1
(-0.5, height/2, 0)
(0.5, height/2, 0)
Y
X
(-0.5, -height/2, 0)
height
(0.5, -height/2, 0)
(x,y,z)


# Page. 80

![Page Image](https://bcdn.docswell.com/page/DJYV6YKPJM.jpg)

画⾓の調整
&lt;script type=&quot;text/javascript&quot;&gt;
var
var
var
var
var
video; //ビデオを扱う変数
model; //顔認識の学習モデル
camera; //カメラ(視点)を扱う変数
canvas; //描画領域
screenWidth, screenHeight; //表⽰領域のサイズ
var halfWidth, halfHeight; //表⽰領域の半分のサイズ
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
}
&lt;/script&gt;
Lesson15


# Page. 81

![Page Image](https://bcdn.docswell.com/page/V7NMZPRME8.jpg)

画⾓の調整
&lt;script type=&quot;text/javascript&quot;&gt;
var
var
var
var
var
video; //ビデオを扱う変数
model; //顔認識の学習モデル
camera; //カメラ(視点)を扱う変数
canvas; //描画領域
screenWidth, screenHeight; //表⽰領域のサイズ
var halfWidth, halfHeight; //表⽰領域の半分のサイズ
//ページを読みこんだら実⾏。初期化に使⽤。
window.onload = function() {
};
//顔認識の学習モデル読み込み
async function LoadFaceModel(){
}
//顔認識をリアルタイムに⾏う
async function FaceTracking(){
c
}
&lt;/script&gt;
次はここを編集


# Page. 82

![Page Image](https://bcdn.docswell.com/page/YJ9NZ3MWJ3.jpg)

画⾓の調整
//描画領域のサイズが変わった場合
if(screenWidth!=canvas.width || screenHeight!=canvas.height){
screenWidth=canvas.width;
screenHeight=canvas.height;
//部屋の横幅を1に固定した場合の⾼さを計算
let height=screenHeight/screenWidth;
//部屋のオブジェクトを取得してサイズを変更
let room= document.getElementById(&#039;room&#039;);
room.setAttribute(&#039;scale&#039;, { x: 1, y: height, z: 1 });
}
halfwidth = 0.5; //今回は横幅を1に固定しているので0.5でOK
halfHeight = height/2; //部屋オブジェクトの⾼さの半分
//顔の検出
let predictions = await model.estimateFaces(video);
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//中略
}
Lesson16


# Page. 83

![Page Image](https://bcdn.docswell.com/page/GJ8K1MLRED.jpg)

画⾓の調整
//描画領域のサイズが変わった場合
if(screenWidth!=canvas.width || screenHeight!=canvas.height){
screenWidth=canvas.width;
screenHeight=canvas.height;
//部屋の横幅を1に固定した場合の⾼さを計算
let height=screenHeight/screenWidth;
//部屋のオブジェクトを取得してサイズを変更
let room= document.getElementById(&#039;room&#039;);
room.setAttribute(&#039;scale&#039;, { x: 1, y: height, z: 1 });
}
halfwidth = 0.5; //今回は横幅を1に固定しているので0.5でOK
halfHeight = height/2; //部屋オブジェクトの⾼さの半分
//顔の検出
let predictions = await model.estimateFaces(video);
c
//⾒つかった顔が1つ以上あれば
if (predictions.length &gt; 0) {
//中略
}
次はここを編集


# Page. 84

![Page Image](https://bcdn.docswell.com/page/LJLZQ3L27R.jpg)

画⾓の調整
if (predictions.length &gt; 0) {
//バウンディングボックスとその左上・右下の座標を取得
let keypoints = predictions[0].boundingBox;
let topLeft=keypoints.topLeft;
let bottomRight=keypoints.bottomRight;
//中⼼を計算(-1~1で正規化)
let cX=(topLeft[0]+bottomRight[0])/video.videoWidth-1;
let cY=(topLeft[1]+bottomRight[1])/video.videoHeight-1;
//カメラの位置を操作
camera.position.x=-cX; //左右反転
camera.position.y=-cY; //上下反転
camera.position.z=2.5; //奥⾏きは分からないので適当に設定
}
//変換⾏列を計算してカメラに適⽤
camera.projectionMatrix=PerspectiveOffCenter(
(-halfWidth-camera.position.x), (halfWidth-camera.position.x),
(-halfHeight-camera.position.y),(halfHeight-camera.position.y),
camera.position.z,5);
Lesson17


# Page. 85

![Page Image](https://bcdn.docswell.com/page/47MV1DM97W.jpg)

画⾓の調整
if (predictions.length &gt; 0) {
//バウンディングボックスとその左上・右下の座標を取得
let keypoints = predictions[0].boundingBox;
let topLeft=keypoints.topLeft;
let bottomRight=keypoints.bottomRight;
//中⼼を計算(-1~1で正規化)
let cX=(topLeft[0]+bottomRight[0])/video.videoWidth-1;
let cY=(topLeft[1]+bottomRight[1])/video.videoHeight-1;
//カメラの位置を操作
camera.position.x=-cX * halfWidth; //左右反転
camera.position.y=-cY * halfHeight; //上下反転
camera.position.z=2.5; //奥⾏きは分からないので適当に設定
}
//変換⾏列を計算してカメラに適⽤
camera.projectionMatrix=PerspectiveOffCenter(
(-halfWidth-camera.position.x), (halfWidth-camera.position.x),
(-halfHeight-camera.position.y),(halfHeight-camera.position.y),
camera.position.z,5);
Lesson18


# Page. 86

![Page Image](https://bcdn.docswell.com/page/P7R2L4V9J9.jpg)



# Page. 87

![Page Image](https://bcdn.docswell.com/page/PJXDW2Z3EX.jpg)

仕上げ
a-sceneとvideoタグのsytleで指定している
position: absolute;をそれぞれ削除


# Page. 88

![Page Image](https://bcdn.docswell.com/page/3JKXVM8NED.jpg)

完成︕


# Page. 89

![Page Image](https://bcdn.docswell.com/page/LE35MY2ZJ5.jpg)

c
おまけ︓部屋の前⾯より⼿前を表⽰可能にする
&lt;a-entity id=&quot;objects&quot; position = &quot;0 0 0&quot; scale=&quot;1 1 1&quot;&gt;


# Page. 90

![Page Image](https://bcdn.docswell.com/page/8EDD65Z4EG.jpg)

おまけ︓部屋の前⾯より⼿前を表⽰可能にする
//バウンディングボックスとその左上・右下の座標を取得
let keypoints = predictions[0].boundingBox;
let topLeft=keypoints.topLeft;
let bottomRight=keypoints.bottomRight;
//中⼼を計算(-1~1で正規化)
let cX=(topLeft[0]+bottomRight[0])/video.videoWidth-1;
let cY=(topLeft[1]+bottomRight[1])/video.videoHeight-1;
//カメラの位置を操作
camera.position.x=-cX * halfWidth; //左右反転
camera.position.y=-cY * halfHeight; //上下反転
camera.position.z=2.5; //奥⾏きは分からないので適当に設定
次はここを編集
//変換⾏列を計算してカメラに適⽤
camera.projectionMatrix=PerspectiveOffCenter(
(-halfWidth-camera.position.x), (halfWidth-camera.position.x),
(-halfHeight-camera.position.y),(halfHeight-camera.position.y),
camera.position.z,5);


# Page. 91

![Page Image](https://bcdn.docswell.com/page/V7PXYGDVE8.jpg)

おまけ︓部屋の前⾯より⼿前を表⽰可能にする
//中⼼を計算(-1~1で正規化)
let cX=(topLeft[0]+bottomRight[0])/video.videoWidth-1;
let cY=(topLeft[1]+bottomRight[1])/video.videoHeight-1;
//カメラの位置を操作
camera.position.x=-cX * halfWidth; //左右反転
camera.position.y=-cY * halfHeight; //上下反転
camera.position.z=2.5; //奥⾏きは分からないので適当に設定
let near =1; //nearの値をカメラのz(=2.5)ではなくカメラから1m⼿前に変更
let a = near/camera.position.z; //near変更に伴うnear⾯のサイズ変化の割合
//変換⾏列を計算してカメラに適⽤
camera.projectionMatrix=PerspectiveOffCenter(
(-halfWidth-camera.position.x)*a, (halfWidth-camera.position.x)*a,
(-halfHeight-camera.position.y)*a,(halfHeight-camera.position.y)*a,
near,5);
完成品19


# Page. 92

![Page Image](https://bcdn.docswell.com/page/2JVLG61R7Q.jpg)

参考資料
• A-Frameチュートリアル
https://www.slideshare.net/ssuserc0d7fb/osc2020fukuoka-webar
• mediapipeチュートリアル
https://www.slideshare.net/ssuserc0d7fb/ai-xwebar-mediapipe-in
•Kinect x Unity版ヘッドトラッキング
https://speakerdeck.com/takashiyoshinaga/kinectwo
yong-itahetudotoratukingu


