るぴブロ

備忘録とかです(*'ω'*)

Ink Recognizerを使ってみよう ( Cognitive Services 復習 )

こんばんは!
コロナウイルスの影響で各地のイベントは自粛ムード…
我が家は出来るだけ人が多い所を避けて、前々から嫁に頼まれてたやつをDIYしています。

さて、勉強会も中々開催できないので、時間がある時に Microosoft Azure のサービスで一番好きな Cognitive Services について不定期でのんびりブログに書いていこうと思います。

Cognitive Services

Microsoft の提供するサービスである、 Cognitive Services は人間の認知する機能の一部(見たり、聞いたり、話したり、意思決定したり、検索したり)を機械で擬似的に再現したサービスで Web API として利用できる AI パーツ。

2020.02.26 現在のサービス一覧 (27 Services ※5 preview)

  • 決定:よりスマートな意思決定をすばやく行う
  • 言語:非構造化テキストから意味を取り出す
    • Immersive Reader(preview):音声や視覚的な合図を使用して、あらゆる能力の読み手がテキストを理解できるようにする
    • Language Understanding自然言語を解釈する機能を提供
    • QnA Maker:ナレッジベースから質疑応答を、会話形式で行うことができる
    • Text Analytics:センチメント、キー フレーズ、名前付きエンティティを検出
    • Translator Text:60 を超えるサポート言語を検出し、リアルタイムで翻訳
  • 音声:音声処理をアプリやサービスに統合する
  • 視覚:画像、ビデオ、デジタル インク内のコンテンツを識別し、分析する
    • Computer Vision:画像内のコンテンツを分析
    • Custom Vision:ビジネス上のニーズに合うよう画像認識をカスタマイズ
    • Face:イメージ内の人物とその感情を検出して識別
    • Form Recognizer(preview):ドキュメントからテキスト、キーと値のペア、テーブルを抽出
    • Ink Recognizer(preview):デジタル インクや手書き入力を認識し、一般的なシェイプの位置特定
    • Video Indexer:ビデオのビジュアルとオーディオ チャネルを分析し、そのコンテンツにインデックスを設定
  • 検索:World Wide Web から探しているものを見つける
    • Bing Autosuggest:インテリジェントな先行入力機能が追加され、ユーザーはよりすばやくクエリを入力する
    • Bing Custom Search:検索結果に広告が表示されないカスタムの検索エンジンを作成
    • Bing Entity Search:名前付きエンティティを識別して分類し、それに基づいて検索結果を探す
    • Bing Image Search:さまざまな画像検索オプションをアプリに追加
    • Bing News Search:アプリをニュースの検索リソースに変更
    • Bing Spell Check:ユーザーが単語の切れ目、スラング、名前、同音異義語、ブランドを識別して修正
    • Bing Video Search:高度なビデオ検索機能をアプリに追加
    • Bing Visual Search:ユーザーが画像を使用して検索
    • Bing Web Search:安全で広告なしの、位置認識機能を備えた検索をユーザーが利用できるようにし、Web の検索結果、画像、ニュース、ビデオ、ビジュアルから関連情報を表示

Ink Recognizer

初回となる今回は、タイトル通り Ink Recognizer API についてです。

手書きの文字、図形、インク ドキュメントのレイアウトなどのデジタル インク コンテンツを認識できる AI サービス

ちょっと何言ってるかわかりませんね。

要は Ink Recognizer API を使用すると、アプリケーション内の手書きコンテンツを簡単に認識する事ができるんです。
あぁ、OCRかw と思われる方もいらっしゃるかと思いますが(僕もそう思いました)、タブレットPCなどにペンや手書きで書いた文字の軌跡を時間軸で並べ渡してあげる事で、図形や文字を認識してくれるというものらしいです。

f:id:rupic:20200224220125p:plain

できる事

手書き認識

63 の主要な言語とロケールの手書きコンテンツを認識

docs.microsoft.com

レイアウト認識

コンテンツを手書き領域、段落、行、単語、箇条書きに分割します。 これにより、お使いのアプリケーションでそのレイアウト情報を使用して、リストの自動書式設定や図形の配置などの追加機能を構築

図形認識

一般的な幾何学図形を認識

docs.microsoft.com

図形とテキストの認識

どのインク ストロークが図形または手書きコンテンツに属しているかを認識し、それらを個別に分類

価格

現在 Preview 中なので価格設定は変わる事があるかもしれませんが以下となっています。

こちら、200 ストロークの要求で 1 トランザクションでして、例えば『石橋裕太』という文字の場合、合計 37 ストロークという感じだと思います。
なので Free プランでも十分に楽しめるかと!!

実際に使ってみる

Azure Portal で Ink Recoognizer のリソースを作成

f:id:rupic:20200226173943p:plain
全てのサービス>AI+Machine Learning>Cognitive Services (検索する方が早いw)

f:id:rupic:20200226174200p:plain
Ink Recognizer のリソースを作成

f:id:rupic:20200226174234p:plain
必要事項を良い感じに入力してください

f:id:rupic:20200226174320p:plain
キーとエンドポイント>キー1をコピーしとく

サンプルコード

github.com

こちらのコードをローカルに git clone して VS Code で開きます。

git clone https://github.com/Azure-Samples/cognitive-services-REST-api-samples
cd SampleCode\cognitive-services-REST-api-samples\javascript\InkRecognition\javascript-app\src
code .

f:id:rupic:20200226174833p:plain
coonfig.js の SUBSCRIPTION_KEY にキー1を貼付け

あとは sample.html を開けば良いのですが、ここまで来て気づいた事としてペンで入力出来る端末がない事でしたww (Macbookなのでタッチついてない…)
とりあえず、App Service に GitHub からデプロイして iPad で動作を確認してみましょう。

動作を確認

f:id:rupic:20200226194847p:plain
左側:ペンで書いた文字、右側:Response JSON

Request
ストローク毎にポイントが時系列順で渡されてますね

{
  "version": 1,
  "language": "ja-JP",
  "strokes": [
    {
      "id": 63,
      "points": "48.6895,163.1115,47.3666,163.1115,46.0437,162.1193,46.0437,161.8015,45.3822,161.4630,45.3822,161.1452,46.7052,160.4682,50.0125,159.8145,55.9656,158.8198,63.2416,157.4891,73.1635,156.4943,83.0854,155.1843,91.6843,153.8511,100.2833,152.8589,105.5750,152.2026,108.2208,152.2026,109.5437,152.2026,109.5437,152.2026,108.2208,152.8589,106.8979,154.1896"
    },
    {
      "id": 64,
      "points": "78.4552,159.1582,78.4552,158.8198,77.7937,159.1582,77.1322,160.1504,76.4708,162.4552,75.8093,166.0932,74.4864,171.3797,71.8406,177.0021,67.2104,184.2937,61.9187,191.5671,55.9656,200.1687,48.6895,206.7677,44.0593,211.7338,40.0906,215.0515,37.4447,216.3641,36.1218,216.7025,36.1218,216.0256"
    },
    {
      "id": 65,
      "points": "65.8875,197.1895,65.8875,196.1973,65.8875,195.8588,65.8875,196.8510,65.8875,198.8406,67.2104,203.1323,68.5333,207.7625,70.5177,212.3901,73.1635,216.0256,74.4864,218.6895,75.8093,220.6765,77.1322,221.9865,77.7937,222.6427,78.4552,222.9812"
    },
    {
      "id": 66,
      "points": "74.4864,199.8328,73.1635,198.8406,73.1635,198.8406,74.4864,198.8406,77.1322,198.1843,83.0854,197.5073,88.3770,196.5151,94.3302,195.5410,99.6218,195.2026,102.9291,196.1973,104.2520,197.1895,105.5750,198.1843,105.5750,199.8328,104.9135,201.8171,103.5906,204.1245,101.6062,206.7677,100.2833,209.4291,99.6218,211.0776,98.2989,213.7208,96.9760,215.7078,96.3145,217.0203"
    },
    {
      "id": 67,
      "points": "85.7312,219.0073,83.0854,219.0073,82.4239,219.0073,83.0854,219.3458,85.0697,219.3458,89.7000,217.6947,96.9760,216.3641,102.9291,215.7078,104.2520,215.7078"
    },
    {
      "id": 68,
      "points": "115.4968,171.3797,115.4968,171.0619,114.1739,170.4030,114.1739,170.0671,115.4968,169.7287,118.1427,168.7365,124.0958,168.0802,131.3718,167.4239,136.6635,166.0932,140.6322,165.0984,141.2937,164.7806,140.6322,164.7806,137.3250,164.4447,134.0177,163.4500,131.3718,161.8015,130.0489,160.1504,129.3875,158.1635,129.3875,156.8328,129.3875,156.4943,129.3875,157.1713,129.3875,159.8145,129.3875,167.0854,128.7260,174.6948,128.0645,182.9604,128.0645,191.2286,128.0645,199.1739,128.0645,205.1193,128.0645,210.0854,128.7260,213.0645,129.3875,214.3771,129.3875,214.3771,129.3875,214.0593"
    },
    {
      "id": 69,
      "points": "131.3718,176.3458,131.3718,176.3458,130.7104,176.0254,130.0489,176.0254,129.3875,176.3458,129.3875,177.3380,128.0645,179.3250,128.0645,181.6323,125.4187,186.5984,122.1114,190.5723,118.8041,193.8719,116.1583,196.8510,114.1739,198.5021,112.8510,198.8406,112.1895,197.5073"
    },
    {
      "id": 70,
      "points": "129.3875,175.6895,128.0645,175.0332,127.4031,174.6948,126.7416,174.6948,128.0645,174.6948,129.3875,175.6895,132.6947,177.9969,135.3406,179.9813,138.6479,181.9682,141.2937,183.6167,142.6166,184.2937"
    },  ...長いので省略
  ]
}

Response
こちらは alternates の recognizedString に候補となる文字列が帰ってきてたり、一致率が一番高い文字列がわかったり、文字のある場所が座標として帰ってきてますね

{
  "recognitionUnits": [
    {
      "alternates": [
        {
          "category": "inkWord",
          "recognizedString": "右"
        },
        {
          "category": "inkWord",
          "recognizedString": "后"
        },
        {
          "category": "inkWord",
          "recognizedString": "谷"
        },
        {
          "category": "inkWord",
          "recognizedString": "厄"
        },
        {
          "category": "inkWord",
          "recognizedString": "名"
        },
        {
          "category": "inkWord",
          "recognizedString": "古"
        },
        {
          "category": "inkWord",
          "recognizedString": "百"
        },
        {
          "category": "inkWord",
          "recognizedString": "召"
        },
        {
          "category": "inkWord",
          "recognizedString": "不"
        }
      ],
      "boundingRectangle": {
        "height": 70.79000091552734,
        "topX": 36.119998931884766,
        "topY": 152.1999969482422,
        "width": 73.43000030517578
      },
      "category": "inkWord",
      "class": "leaf",
      "id": 4,
      "parentId": 3,
      "recognizedText": "石",
      "rotatedBoundingRectangle": [
        {
          "x": 38.619998931884766,
          "y": 149.52999877929688
        },
        {
          "x": 109.52999877929688,
          "y": 152.1999969482422
        },
        {
          "x": 106.83000183105469,
          "y": 224.0399932861328
        },
        {
          "x": 35.90999984741211,
          "y": 221.3699951171875
        }
      ],
      "strokeIds": [
        63,
        64,
        65,
        66,
        67
      ]
    },
    {
      "alternates": [
        {
          "category": "inkWord",
          "recognizedString": "槗"
        },
        {
          "category": "inkWord",
          "recognizedString": "楿"
        },
        {
          "category": "inkWord",
          "recognizedString": "橎"
        }, ...長いので省略
  ]
}

f:id:rupic:20200226200825p:plain
認識した文字列と場所をCanvas上に反映させるとこんな感じになります

f:id:rupic:20200226200936p:plain
ちなみにこんな図形を書いてみると…
f:id:rupic:20200226201007p:plain
良い感じに図形の形や場所などを認識してくれます

まとめ

  • Ink Recognizer API を使用すると、アプリケーション内の手書き文字を良い感じに認識してくれる!
  • 認識精度はかなり高めだと思う ※ヘナヘナな文字でもしっかり認識してくれて嬉しいw
  • 会員登録とか紙に文字で書いた後に PC に入力するっていう感じの業務は置き換え可能かも?
  • Macboook + iPad ある時は AppService にデプロイしなくても SideCar 使えば良かったんだと後から気付きましたw(泣
  • あ、Surface Pro 買えば良いのか(白目

f:id:rupic:20200226201646p:plain
SideCar で iPad を液タブとして使えるの忘れてたw