フェイスモーションを使用してタイポグラフィと対話する方法

公開: 2022-03-10
簡単なまとめ↬この記事では、機械学習、可変フォント、CSSグリッドを組み合わせて、ユーザーの顔の近さ、傾き、数に対応するレイアウトを作成する方法について説明します。

Webデザイナーは、ページのコンテンツの表示を改善するための新しい方法を常に探しています。 時には、これは独創的な解決策につながるか、しばしば設計分野から遠ざけられている技術と相互作用する可能性があります。 この記事では、テキストの読みやすさを向上させるために、機械学習を使用してユーザーの顔の近さなどを検出し、タイポグラフィを人工知能と接触させます。

画面とユーザーの顔の間の距離やページを読んでいる人の数など、カメラからいくつかの情報を抽出するために、Tensorflowで顔認識を使用する方法を実験します。 次に、タイポグラフィを適応させ、ページレイアウトを調整するために、これらのデータをCSSに渡します。

Tensorflowとは何ですか?

Tensorflowは、Google for MachineLearningのオープンソースプラットフォームです。 機械学習は、画像、オーディオトラック、時系列、自然なテキスト、および一般的なデータから複雑な関係や繰り返しパターンを認識することを学習するアルゴリズムを研究するコンピュータサイエンスの分野です。 これらのアルゴリズムは、入力データに基づいて意思決定を行うために使用できる一種のスキーマである数学モデル(トレーニング済みモデルとも呼ばれます)を生成します。 このトピックにアプローチしたい場合は、CharlieGerardがフロントエンド開発者向けのMLについてここSmashingMagに書いています。

Tensorflowは、AI開発者、データサイエンティスト、数学者に多くのツールを提供しますが、データ分析が日常業務でない場合でも慌てる必要はありません。 良いニュースは、私たちがやろうとしているように、事前に構築されたモデルを使用している限り、それを使用するために専門家である必要はないということです。

Tensorflowモデルは、JavaScriptSDKを使用してWebで使用できます。

設定

顔認識アルゴリズムの使用を開始するには、いくつかの手順に従う必要があります。

  • TensorflowSDKをロードします。
  • 数学モデルを含むFacemeshライブラリをロードします。
  • ユーザーのカメラにアクセスし、それをHTMLビデオ要素にストリーミングします。 Facemeshは、ビデオタグからのフレームを分析して、顔の存在を検出します。

このプロジェクトでは、CDNを介してTensorflowを使用しますが、バンドラー方式を使用する場合は、NPMでも使用できます。

 <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-webgl"></script>

Tensorflow自体はトリックを実行しないため、MLフレームワークの上に構築され、顔認識用のトレーニング済みモデルを提供するライブラリであるFacemeshを追加する必要があります。

 <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/facemesh"></script>

次のステップは、トレーニングされたモデルをロードし、ビデオストリームからの顔データを評価する関数を定義するためにFacemeshライブラリをセットアップすることです。

 // create and place the video const video = document.createElement('video'); document.body.appendChild(video); // setup facemesh const model = await facemesh.load({ backend: 'wasm', maxFaces: 1, }); async function detectFaces() { const faces = await model.estimateFaces(video); console.log(faces); // recursively detect faces requestAnimationFrame(detectFaces); }

これで、ビデオタグを使用してカメラストリームにアクセスする許可をユーザーに求める準備ができました。

 // enable autoplay video.setAttribute('autoplay', ''); video.setAttribute('muted', ''); video.setAttribute('playsinline', ''); // start face detection when ready video.addEventListener('canplaythrough', detectFaces); // stream the camera video.srcObject = await navigator.mediaDevices.getUserMedia({ audio: false, video: { facingMode: 'user', }, }); // let's go! video.play();

navigator.mediaDevices.getUserMediaメソッドは許可を求め、カメラをビデオ要素にストリーミングし始めます。 受け入れられると、カメラはビデオタグへのストリーミングを開始し、ブラウザコンソールはFacemeshによって検出された顔情報をログに記録します。

カメラの権限には安全なhttps接続またはローカルホストが必要であることに注意してください。index.htmlファイルを単純に開くことはできません。 Nodeのローカルサーバーチェックアウトhttp-serverを設定する方法がわからない場合、またはPythonの場合はこのガイド、PHPの場合はこのガイドに従ってください。

ジャンプした後もっと! 以下を読み続けてください↓

ケース1.スマートフォンのカメラを使用してタイポグラフィを調整する

私たちはスマートフォンでどこでもウェブをナビゲートします。 昔は混雑した電車やバスに乗っていて、スペースがないのでスマートフォンを目の近くに置いていた時期がありました。 同じ場所を見ていても、スマートフォンの位置や傾きを変えてしまうことがよくあります。 目とスマートフォンの間の距離は、私たちの読書能力に影響を与えます。 その距離を評価することで、より近いまたはより遠い読み取りのためにグリフを最適化するためにマイクロタイポグラフィーを調整できます。

顔検出とは、もちろん目の位置検出も意味します。 Facemeshから提供されたデータを使用して、カメラでキャプチャされた画像全体に対する顔のサイズを計算できます。 顔が大きくなればなるほど、画面に近づくと考えられます。 0(片方の腕が離れている-顔がカメラの約半分を占める)から1(画面に接着)までのスケールを設定し、セグメントの分割で現在の値を検出できます。

 async function detectFaces() { const faces = await model.estimateFaces(video); if (faces.length === 0) { // is somebody out there? return requestAnimationFrame(detectFaces); } const [face] = faces; // extract face surface corners let { bottomRight, topLeft} = face.boundingBox; // calculate face surface size let width = bottomRight[0] - topLeft[0]; let height = bottomRight[1] - topLeft[1]; let videoWidth = video.videoWidth; let videoHeight = video.videoHeight; let adjustWidth = videoWidth / 2; let adjustHeight = videoHeight / 2; // detect the ratio between face and full camera picture let widthRatio = Math.max(Math.min((width - adjustWidth) / (videoWidth - adjustWidth), 1), 0); let heightRatio = Math.max(Math.min((height - adjustHeight) / (videoHeight - adjustHeight), 1), 0); let ratio = Math.max(widthRatio, heightRatio); // recursively detect faces requestAnimationFrame(detectFaces); }
セグメントによるユーザーの顔の表現は、スマートフォンのフレーム内に配置され、画面のどの領域が顔によって占められているかを示します。
目、鼻、口の位置と傾きなど、Facemeshによって検出された特性の2つの例。 ポイント間の面積を使用して、スマートフォンのカメラへの近さを計算できます。 (大プレビュー)

ratioを計算したので、次は魔法を起こして、値をスタイルシートに渡します。

 document.documentElement.style.setProperty('--user-distance', ratio);

この値と少しの計算で、フォントの太さ、サイズ、そしておそらくスタイルにも簡単にわずかな変更を加えることができますが、さらに良いことをすることができます。 可変フォント、つまりグリフの形状とスペースをパラメーター化したフォントを使用して、光学サイズの変化を更新することにより、すべてのグリフの知覚を調整できます。

すべての可変フォントは光学サイズ値に独自のスケールを使用するため、比率値をそのスケールに関連付ける必要があります。 さらに、ほんの少しの拡張を提供するために、利用可能な光学サイズのサブセット間を移動したい場合があります。

 .main-text { --min-opsz: 10; --max-opsz: 15; --opsz: calc(var(--min-opsz) + (var(--user-distance) * (var(--max-opsz) - var(--min-opsz)))); ... font-family: 'Amstelvar', serif; font-variation-settings: 'opsz' var(--opsz); }

ここでライブで見ることができます。 この例は、テクノロジーがどのように機能するかを示すためのものにすぎないことに注意してください。 より良い読者体験を実際に提供するために、活字の変更はユーザーの目にはほとんど知覚できないはずです。 ここではグリフの形状を活用しましたが、色を使用してコントラストを増減することは、もう1つの良い解決策です。 別の実験は、読みの遠近法を計算するために顔の角度を検出し、アセンダー、ディセンダー、文字の高さを変更することでした。

EdoardoCavazzaによるペン[Facemeshand ascenders / descenders](https://codepen.io/smashingmag/pen/oNxrYop)を参照してください。

EdoardoCavazzaによるPenFacemeshとアセンダー/ディセンダーを参照してください。

ケース2:見ている人の数が変わったときにレイアウトを調整する

この2番目のケースでは、画面を見ている人の数に基づいてレイアウトを変更します。 高校の教室のコンテキストでインタラクティブホワイトボードに表示されるエッセイを想像することができます。 このシナリオは、非推奨のプロジェクションメディアクエリで検出されたシナリオとはまったく異なります。これは、視聴している生徒の数が10人より少ないか多い場合にページのレイアウトを調整するためです。教室にいる生徒が数人しかない場合、安全にボードに近づくことができますが、教室全体が存在する場合は、おそらくスペースが十分ではなく、より少ない(そしてより大きな)ものを表示するようにレイアウトを変更する必要があります。

ホワイトボードで見ている顔の数を正しく検出するには、前のスクリプトにいくつかの変更を加える必要があります。 まず、複数の顔を検出するようにFacemeshに指示する必要があります。

 const model = await facemesh.load({ backend: 'wasm', maxFaces: 30, });

次に、その番号をスタイルシートに渡す必要があります。

 async function detectFaces() { const faces = await model.estimateFaces(video); document.documentElement.style.setProperty('--watching', faces.length); // recursively detect faces requestAnimationFrame(detectFace); }

繰り返しになりますが、その値を使用してフォントサイズを単純に大きくすることもできますが、目的は完全に異なるレイアウトを提供することです。 CSSグリッドレイアウトは、このミッションで役立つ場合があります。 この投影されたドキュメントは、関連する画像を含む脇白のある長い形式です。

 <section> <article> <h1>...</h1> <h2>...</h2> <p>...</p> </article> <aside> <img src="..." alt="..." /> </aside> </section>

そして、これがデフォルトのレイアウトです。

 section { display: grid; grid-template-columns: repeat(12, 1fr); grid-column-gap: 1em; width: 120ch; max-width: 100%; padding: 1em; } section article { grid-column: 1 / -5; } section aside { grid-column: 7 / -1; }
左:10人以上が視聴している場合は、使用可能なすべての列を使用してメインテキストを優先し、テキストの後に画像を移動します。右:アクティブなFirefoxグリッドインスペクターガイドを備えた12列を使用したページレイアウト。 12列すべてが本文に使用され、4列はその後の画像に使用されます。
:ページのデフォルトのレイアウトでは、12列のうち8列が長い形式のテキストに使用され、残りの4列が画像に使用されます。 :10人以上が視聴している場合は、使用可能なすべての列を使用してメインテキストを優先し、テキストの後に画像を移動します。 (大プレビュー)

多数の人が見ているときは、長い形式の読書コンテキストに特権を与え、メイン列により多くのスペースを与え、フォントサイズを大きくし、邪魔な要素を削除する必要があります。 そのために、スパン列の数を増やし、本文の下に脇を移動します。

 :root { --watching: 10; } section { /** The maximum number of people watching for the default layout */ --switch: 10; /** The default number of columns for the text */ --text: 8; /** The default number of columns for the aside */ --aside: 4; grid-template-columns: repeat(calc(var(--text) + var(--aside)), 1fr); } section article { /** * Kinda magic calculation. * When the number of people watching is lower than --switch, it returns -2 * When the number of people watching is greater than --switch, it returns -1 * We are going to use this number for negative span calculation */ --layout: calc(min(2, (max(var(--switch), var(--watching)) - var(--switch) + 1)) - 3); /** * Calculate the position of the end column. * When --layout is -1, the calculation just returns -1 * When --layout is -2, the calculation is lower than -1 */ --layout-span: calc((var(--aside) * var(--layout)) + var(--aside) - 1); /** * Calculate the maximum index of the last column (the one "before" the aside) */ --max-span: calc(-1 * var(--aside) - 1); /** * get the max between --layout-span and the latest column index. * -1 means full width * --max-span means default layout */ --span: max(var(--max-span), var(--span)); grid-column-start: 1; grid-column-end: var(--span); }
  • ここでライブで見ることができます→

逆に、少人数の学生グループがボードの近くでテキストを体験している場合は、メディアファイルやインタラクティブなアクショントリガーなどの詳細を提供できます。

顔認識を超えて

私たちが直面した事例()は、レイアウトまたは活版印刷のスコープに顔認識テクノロジーを使用する方法の2つの例にすぎません。 Tensorflowは、カメラストリームをページの変数に変換できる他のモデルとライブラリを提供します。 さらに、スマートフォンには、センサーAPIを使用して利用できるセンサーが他にもたくさんあることを忘れてはなりません。GPS、加速度計、周囲光などです。

気分は情報の読み方、学習方法、検索方法に影響を与えるため、機械学習を使用すると、ユーザーの表現を分析して、ユーザーの精神に応じて最小限のレイアウトから詳細なレイアウトに切り替えることもできます。

長年にわたり、レスポンシブWebデザインにCSSメディアクエリを使用することに慣れています。 ただし、ビューポートのサイズは、ユーザーエクスペリエンスの変数の1つにすぎません。 最近、 prefers-color-schemeprefers-reduced-motionなど、ユーザーの好みを尊重するように設計された新しい種類のメディアクエリがブラウザに登場しました。 これにより、設計者と開発者はWebデザインの実践を一歩前進させることができ、Webページをユーザーのデバイスだけでなく環境全体に適応させることができます。 ビッグデータの時代には、レスポンシブでアダプティブなデザインを超える機会があります。 私たちのWebページは、最終的に「画面を離れる」ことができ、ユーザーのグローバルエクスペリエンスの一部になることができます。 インタラクションデザインにはこれらすべての可能性が含まれるため、テクノロジーとWebデザインの可能な組み合わせを実験し続けることは、今後数年間で非常に重要になります。