ユーザー(手書き入力)を認識する

手書き入力認識 API を使用すると、手書き入力のテキストを処理して認識できます。

手書き入力認識 API とは何ですか。

Handwriting Recognition API を使用すると、ユーザーの手書き文字(インク)をテキストに変換できます。 一部のオペレーティング システムには以前からこのような API が搭載されています。この新機能により、ウェブアプリで この機能を使用しますコンバージョンはユーザーのデバイスで直接行われ、 オフライン モードで起動できます。サードパーティのライブラリやサービスを追加する必要はありません。

この API は、いわゆる「オンライン」ほぼリアルタイムの認識ですつまり、 手書き入力をキャプチャして分析することで、ユーザーが手書き入力を できます。「オフライン」とは対照的に、光学式文字認識(OCR)などの手順を用います。 最終製品のみがわかっているため オンラインアルゴリズムは 個々のインク ストロークの時間的シーケンスや圧力などの追加のシグナルを推定することもできます。

手書き入力認識 API に推奨されるユースケース

使用例:

  • ユーザーが手書きのメモをキャプチャして翻訳できるようにするメモ作成アプリケーション 生成します。
  • 時間的な制約からペン入力や指入力が可能なフォーム アプリケーション。
  • クロスワード、ハングマン、数独など、文字や数字を入力する必要があるゲーム。

現在のステータス

手書き入力認識 API は Chromium 99 から利用できます。

手書き入力認識 API の使用方法

機能検出

createHandwritingRecognizer() メソッドが存在するかどうかを確認することで、ブラウザ サポートを検出します navigator オブジェクトで設定:

if ('createHandwritingRecognizer' in navigator) {
  // 🎉 The Handwriting Recognition API is supported!
}

基本コンセプト

手書き入力認識 API は、入力方法に関係なく手書き入力をテキストに変換します。 (マウス、タップ、ペン)。API には、次の 4 つの主要エンティティがあります。

  1. point は、特定の時点でポインタがあった場所を表します。
  2. ストロークは 1 つ以上のポイントで構成されます。ユーザーがストロークを打つと、ストロークの記録が開始されます。 ポインタを下に動かす(マウスのメインボタンをクリックするか、ペンまたは 指で操作し、ポインタを上に上げると終了します。
  3. 図形描画は 1 つ以上のストロークで構成されます。実際の認定はこのレベルで行われます。
  4. 認識ツールが、想定される入力言語で構成されている。インスタンスを作成するために使用します。 認識ツールの構成が適用された図。

こうした概念は、後ほど説明する特定のインターフェースと辞書として実装されます。

Handwriting Recognition API の中核的なエンティティ: 1 つ以上のポイントが 1 つのストロークを構成し、1 つ以上のストロークが描画を構成し、認識ツールによって作成されます。実際の認識は描画レベルで行われます。

認識ツールを作成する

手書き入力からテキストを認識するには、 navigator.createHandwritingRecognizer() を呼び出して制約を渡すことで HandwritingRecognizer 追加できます。制約により、使用する手書き入力認識モデルが決まります。現在、 優先度の高い順に言語のリストを指定できます。

const recognizer = await navigator.createHandwritingRecognizer({
  languages: ['en'],
});

このメソッドは、次の場合に HandwritingRecognizer のインスタンスで解決される Promise を返します。 ブラウザがリクエストに対応できるかどうかがわかります。それ以外の場合は、エラーで Promise が拒否され、 手書き入力認識が使用できなくなります。このため、1 つのテーブルに 特定の認識機能のサポートを先に進めます。

認識ツールのサポートのクエリ

navigator.queryHandwritingRecognizerSupport() を呼び出すと、ターゲット プラットフォームが 使用する手書き入力認識機能をサポートしている必要があります。次の例では、 開発者:

  • 英語のテキストを検出したいと考えています。
  • 可能であれば、代替の確率の低い予測を取得する
  • セグメンテーションの結果、すなわちポイントおよび それを構成するストローク
const { languages, alternatives, segmentationResults } =
  await navigator.queryHandwritingRecognizerSupport({
    languages: ['en'],
    alternatives: true,
    segmentationResult: true,
  });

console.log(languages); // true or false
console.log(alternatives); // true or false
console.log(segmentationResult); // true or false

このメソッドは、結果オブジェクトで解決される Promise を返します。ブラウザがこの機能をサポートしているか デベロッパーが指定した場合、その値は true に設定されます。それ以外の場合は false に設定されます。 この情報を使用して、アプリ内の特定の機能を有効または無効にできます。 クエリを調整して新しいクエリを送信します。

図形描画を開始する

アプリケーション内には、ユーザーが手書き入力を行う入力領域を用意する必要があります。 あります。パフォーマンス上の理由から、 キャンバス オブジェクトを使用します。正確な この部分の実装はこの記事の対象外ですが、デモを参照してください。 その方法を確認しましょう。

新しい描画を開始するには、認識ツールで startDrawing() メソッドを呼び出します。このメソッドは、 認識アルゴリズムを微調整するためのさまざまなヒントを含むオブジェクトです。すべてのヒントは省略可能です。

  • 入力するテキストの種類: テキスト、メールアドレス、数字、個々の文字 (recognitionType)
  • 入力デバイスの種類: マウス、タップ、ペンによる入力(inputType
  • 直前のテキスト(textContext
  • 返される可能性が低い代替予測の数(alternatives
  • ユーザーが入力する可能性の高いユーザー識別可能な文字(「書記体」)のリスト (graphemeSet)

手書き入力認識 API は、 ポインタ イベント: 任意のポインティング デバイスからの入力を消費する抽象インターフェースです。ポインタ イベントの引数には、 使用されるポインタの型。つまり、ポインタ イベントを使用して入力の型を判別できる 自動的に適用されます。次の例では、手書き入力認識用の図形描画が自動的に 手書き入力領域で最初に pointerdown イベントが発生したときに作成されます。 pointerType は空にするか、独自の値に設定することができるため、以下を行うための整合性チェックを導入しました。 図形描画の入力タイプには、サポートされている値のみが設定されていることを確認します。

let drawing;
let activeStroke;

canvas.addEventListener('pointerdown', (event) => {
  if (!drawing) {
    drawing = recognizer.startDrawing({
      recognitionType: 'text', // email, number, per-character
      inputType: ['mouse', 'touch', 'pen'].find((type) => type === event.pointerType),
      textContext: 'Hello, ',
      alternatives: 2,
      graphemeSet: ['f', 'i', 'z', 'b', 'u'], // for a fizz buzz entry form
    });
  }
  startStroke(event);
});

ストロークを追加する

また、pointerdown イベントは新しいストロークを開始するのにも適しています。これを行うには、 HandwritingStroke のインスタンス。また、現在の時刻を基準点として保存し、 次のポイントが追加されます。

function startStroke(event) {
  activeStroke = {
    stroke: new HandwritingStroke(),
    startTime: Date.now(),
  };
  addPoint(event);
}

Wifi 拡張ポイントを追加する

ストロークを作成したら、最初のポイントを直接追加する必要があります。指標を追加する際は ポイント作成ロジックを別のメソッドに実装するのが合理的です。 次の例では、addPoint() メソッドが参照タイムスタンプから経過時間を計算します。 時間情報は省略可能ですが、認識品質を向上させることができます。次に、X を読み取って、 ポインタ イベントの Y 座標で、現在のストロークにポイントを追加します。

function addPoint(event) {
  const timeElapsed = Date.now() - activeStroke.startTime;
  activeStroke.stroke.addPoint({
    x: event.offsetX,
    y: event.offsetY,
    t: timeElapsed,
  });
}

pointermove イベント ハンドラは、ポインタが画面上で移動すると呼び出されます。この点は ストロークにも追加する必要がありますポインタが API 呼び出しにない場合にも、 「下」(マウスを押さずに画面上でカーソルを動かした場合など) ] ボタンを離します。次の例のイベント ハンドラは、アクティブなストロークが存在するかどうかを確認し、 示されます。

canvas.addEventListener('pointermove', (event) => {
  if (activeStroke) {
    addPoint(event);
  }
});

テキストを認識する

ユーザーがもう一度ポインタを離すと、 addStroke() メソッドを使用します。次の例では activeStroke もリセットされるため、pointermove 完了したストロークにはポイントを追加しません。

次に、getPrediction() メソッドを呼び出してユーザーの入力を認識します。 描画します。通常、認識にかかる時間は数百ミリ秒未満なので、 実行できます。次の例では、ストロークが完成するたびに新しい予測を実行します。

canvas.addEventListener('pointerup', async (event) => {
  drawing.addStroke(activeStroke.stroke);
  activeStroke = null;

  const [mostLikelyPrediction, ...lessLikelyAlternatives] = await drawing.getPrediction();
  if (mostLikelyPrediction) {
    console.log(mostLikelyPrediction.text);
  }
  lessLikelyAlternatives?.forEach((alternative) => console.log(alternative.text));
});

このメソッドは Promise を返します。この Promise は、名前順に並んだ予測の配列で解決されます。 できます。要素の数は、alternatives ヒントに渡された値によって異なります。マイページ この配列を使用して、可能性のある一致の選択肢をユーザーに提示し、ユーザーが 選択します。または、最も確率の高い予測を行うこともできます。ここでは、 例です。

予測オブジェクトには、認識されたテキストとオプションのセグメンテーション結果が含まれます。 次のセクションで説明します

セグメンテーションの結果を含む詳細な分析情報

ターゲット プラットフォームでサポートされている場合、予測オブジェクトにセグメンテーション結果を含めることもできます。 これは、認識されたすべての手書き入力セグメントを含む配列です。認識された ユーザー識別可能な文字(grapheme)と、認識されたテキスト内での位置 (beginIndexendIndex)と、それを作成したストロークと点が含まれます。

if (mostLikelyPrediction.segmentationResult) {
  mostLikelyPrediction.segmentationResult.forEach(
    ({ grapheme, beginIndex, endIndex, drawingSegments }) => {
      console.log(grapheme, beginIndex, endIndex);
      drawingSegments.forEach(({ strokeIndex, beginPointIndex, endPointIndex }) => {
        console.log(strokeIndex, beginPointIndex, endPointIndex);
      });
    },
  );
}

この情報を使用して、認識された書記をキャンバス上で再度追跡できます。

認識された各書記素の周りにボックスが描画される

認定を完了

認識が完了したら、クラスで clear() メソッドを呼び出してリソースを解放できます。 HandwritingDrawingHandwritingRecognizerfinish() メソッド:

drawing.clear();
recognizer.finish();

デモ

ウェブ コンポーネント <handwriting-textarea> は、 段階的に強化、手書き入力が可能な編集コントロール あります。編集コントロールの右下にあるボタンをクリックすると、 描画モードを使用します描画が完了すると、ウェブ コンポーネントが自動的に 認識したテキストを編集コントロールに戻します。手書き入力の認識で API がまったくサポートされていない、またはリクエストされた機能がプラットフォームでサポートされていない場合、[編集] ボタン 非表示になります。ただし、基本的な編集コントロールは <textarea> として引き続き使用できます。

ウェブ コンポーネントには、ウェブコンポーネントの認識動作を定義するプロパティと属性が 外部(languagesrecognitiontype を含む)。コントロールのコンテンツは、 value 属性:

<handwriting-textarea languages="en" recognitiontype="text" value="Hello"></handwriting-textarea>

値が変更されたときに通知を受け取るには、input イベントをリッスンします。

Glitch のデモを使ってコンポーネントを試すことができます。 また、 ソースコード。このコントロールを npm から取得します。

セキュリティと権限

Chromium チームは、基本原則に基づいて手書き認識 API を設計、実装しました。 強力なウェブ プラットフォーム機能へのアクセスの制御で定義されている 制御、透明性、エルゴノミクスの点で優れています。

ユーザー コントロール

ユーザーが手書き認識 API をオフにすることはできません。ウェブサイトでのみ使用できます。 HTTPS 経由で配信され、最上位のブラウジング コンテキストからのみ呼び出すことができます。

透明性

手書き入力認識が有効かどうかは表示されません。フィンガープリントを回避するため、ブラウザでは 検出時に権限プロンプトをユーザーに表示するなど、対策を実装しています 特定します。

権限の永続性

現在、手書き認識 API では権限プロンプトが表示されません。したがって、権限は 永続化する必要はありません。

フィードバック

Chromium チームでは、手書き入力認識 API について、感想をお聞かせください。

API 設計について教えてください

API で想定どおりに機能していないものはありますか?あるいは不足しているメソッドがあるか アイデアを実現するために必要なものやプロパティは?セキュリティに関する質問またはコメント どうすればよいでしょうか。対応する GitHub リポジトリで仕様に関する問題を報告するか、 解決します

実装に関する問題を報告する

Chromium の実装にバグは見つかりましたか?または、実装が仕様と異なっていますか? new.crbug.com でバグを報告します。できるだけ詳細に説明してください [Components] ボックスに「Blink>Handwriting」と入力します。 Glitch は、すばやく簡単に再現を共有するのに最適です。

API のサポートを表示する

手書き入力認識 API を使用する予定はありますか?皆様の公開サポートが Chromium チームの力になります 他のブラウザ ベンダーがそれらの機能をサポートすることの重要性を説明します。

どのように使用する予定なのかを WICG の談話スレッドで共有してください。ツイートの送信先 @ChromiumDev(ハッシュタグを使用) #HandwritingRecognition どこで、どのように使用されているかをお知らせください。

謝辞

この記事は、Joe Medley、Hongin Yu、Jiewei Qian によってレビューされました。ヒーロー画像: Samir Bouakedスプラッシュを解除