Azure Cognitive ServicesでBlob Storage内画像の文字認識

# はじめに
[Azure Cognitive Services](https://azure.microsoft.com/ja-jp/services/cognitive-services/)の機能を使った画像ファイルのOCR処理について、試した結果をメモとして公開します。

# Azure Cognitive Servicesのリソース作成
Azureポータル上部の検索ボックスから「Cognitive Services」を検索してクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/8f5825b7-c471-66d5-2c01-ce9cc65f9e9f.png)
左ペインから「Computer Vision」を選び、中央ペイン上部の「＋作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/9a4f1671-7336-c1a8-96a5-d7d418dd0388.png)
パラメータを指定してリソースを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/9844f369-0ee4-642a-bdf2-1642dfed3a19.png)
サブスクリプション・リソースグループ・リージョンを指定し、リソースの名前を付けます。今回は「ocr-for-blob」としました。
価格レベルは「Free F0」を選択、また「責任ある AI 通知」の文面をよく読んで、同意欄にチェックを付けましょう。
その他パラメータはとりあえずデフォルトのまま作成します。

# インターネット上の画像ファイルに対するOCR処理を試してみる
リソースが準備できたのでOCR処理を試してみましょう。
[APIを利用するサンプル](https://docs.microsoft.com/ja-jp/azure/cognitive-services/computer-vision/quickstarts-sdk/client-library?tabs=visual-studio&pivots=programming-language-rest-api#call-the-read-api)を見ると、画像ファイルのURLをパラメーターとして渡してあげれば実現できそうです。

インターネットに公開されている画像に対しては以下のようにAPIを叩けばよいです。
以下の画像（URL: https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Atomist_quote_from_Democritus.png/338px-Atomist_quote_from_Democritus.png ）を例にすると、

![https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Atomist_quote_from_Democritus.png/338px-Atomist_quote_from_Democritus.png](https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Atomist_quote_from_Democritus.png/338px-Atomist_quote_from_Democritus.png)

```bash
$ curl -v -X POST "https://<Computer Visionのエンドポイント>/vision/v3.2/read/analyze" -H "Content-Type: application/json" \
> -H "Ocp-Apim-Subscription-Key: <Computer Visionのキー>" --data-ascii "{\"url\":\"https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Atomist_quote_from_Democritus.png/338px-Atomist_quote_from_Democritus.png\"}"
～中略～
< operation-location: https://ocr-for-blob.cognitiveservices.azure.com/vision/v3.2/read/analyzeResults/32699971-1f0e-4bd6-9ee9-95ca77b5eb5a
< x-envoy-upstream-service-time: 451
< csp-billing-usage: CognitiveServices.ComputerVision.Transaction=1
< apim-request-id: 32699971-1f0e-4bd6-9ee9-95ca77b5eb5a
< strict-transport-security: max-age=31536000; includeSubDomains; preload
< x-content-type-options: nosniff
< date: Wed, 09 Mar 2022 14:57:59 GMT
<
* Connection #0 to host ocr-for-blob.cognitiveservices.azure.com left intact

# レスポンスヘッダの「operation-location」のURLに対しGETリクエストでOCR結果を取得する。
$ curl -X GET https://xxxxx.cognitiveservices.azure.com/vision/v3.2/read/analyzeResults/87e107e9-5766-4ad2-96c8-e01784abc158 -H "Ocp-Apim-Subscription-Key: <Computer Visionのキー>" \
> | jq '.analyzeResult.readResults[].lines[].text'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2253  100  2247  100     6  15390     41 --:--:-- --:--:-- --:--:-- 15431
"NOTHING"
"EXISTS"
"EXCEPT"
"ATOMS"
"AND EMPTY"
"SPACE."
"Everything else"
"is opinion."
```
上記のようにOCR結果のテキストを取得可能です。

実行に必要な各パラメータはポータルの「キーとエンドポイント」から確認可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/be0814e6-37e1-eb37-0091-1a95ca17934a.png)

# Blobを対象にしてみる
インターネット上に公開されている画像ファイルについてはOCR処理可能ということが確認できました。
では、公開状態にしていないストレージアカウント上のBlobを対象にするとどうでしょうか。
サンプルで利用した画像ファイルをBlobとして配置してAPIを叩いてみます。

```bash
$ curl -X POST "https://ocr-for-blob.cognitiveservices.azure.com/vision/v3.2/read/analyze" -H "Content-Type: application/json" \
> -H "Ocp-Apim-Subscription-Key: <Computer Visionのキー>" --data-ascii "{\"url\":\"https://teststorageforocr.blob.core.windows.net/upload/338px-Atomist_quote_from_Democritus.png\"}"
{"error":{"code":"FailedToDownloadImage","message":"Failed to download image from input URL."}}
```
Cognitive ServiceからBlobが参照できないため、当然エラーになります。

## 解決策1. SASトークン
ストレージアカウント側でSASトークンを発行すれば解決できます。
Blobコンテナーの「共有アクセストークン」から「SAS トークンおよび URL を生成」ボタンをクリックし、SASトークンを生成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/84344b20-2aa1-6fa5-e44a-fcec49aa6709.png)
生成されたSASトークンをBlobのURLの後ろに付与してリクエストを投げれば、問題なくOCR処理が可能です。

```bash
$ curl -v -X POST "https://ocr-for-blob.cognitiveservices.azure.com/vision/v3.2/read/analyze" -H "Content-Type: application/json" \
> -H "Ocp-Apim-Subscription-Key: <Computer Visionのキー>" --data-ascii "{\"url\":\"https://teststorageforocr.blob.core.windows.net/upload/338px-Atomist_quote_from_Democritus.png?<SASトークン>\"}"
～中略～
< operation-location: https://ocr-for-blob.cognitiveservices.azure.com/vision/v3.2/read/analyzeResults/cee220ce-37e6-4f40-b9d0-d938b000cd85
< x-envoy-upstream-service-time: 256
< csp-billing-usage: CognitiveServices.ComputerVision.Transaction=1
< apim-request-id: cee220ce-37e6-4f40-b9d0-d938b000cd85
< strict-transport-security: max-age=31536000; includeSubDomains; preload
< x-content-type-options: nosniff
< date: Wed, 09 Mar 2022 15:23:01 GMT
<
* Connection #0 to host ocr-for-blob.cognitiveservices.azure.com left intact

$ curl -X GET https://ocr-for-blob.cognitiveservices.azure.com/vision/v3.2/read/analyzeResults/cee220ce-37e6-4f40-b9d0-d938b000cd85 -H "Ocp-Apim-Subscription-Key: <Computer Visionのキー>" \
> | jq '.analyzeResult.readResults[].lines[].text'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2247  100  2247    0     0  15182      0 --:--:-- --:--:-- --:--:-- 15182
"NOTHING"
"EXISTS"
"EXCEPT"
"ATOMS"
"AND EMPTY"
"SPACE."
"Everything else"
"is opinion."
```

## 解決策2. マネージドID
もう一つの解決策はマネージドIDを利用するものです。
Computer Visionリソースの左ペイン「ID」からマネージドIDの状態を「オン」に変更し保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/c5f8a835-f5ee-546b-58ff-9adacf113145.png)
次にストレージアカウント側でIAMの設定をします。
Blobコンテナーの「アクセス制御(IAM)」から「＋追加」→「ロールの割り当ての追加」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/6e78bb72-9ff0-754f-0318-7a852d52b8af.png)
Computer Visionリソースに割り当てるロールを選択します。画像の読み出しができればよいので、「ストレージ Blob データ閲覧者」を付与すればよいでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/7ed2f37f-f787-7d10-0994-6ffe1c249363.png)
次のメンバーの画面で「マネージドID」を選択、Computer VisionリソースのIDを選択しロールの割り当てを行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274613/9c6e347a-1b48-2ac8-e312-134e16641ea1.png)

ロールの割り当てを終えて少し待ってからリクエストを投げると、OCR処理ができることが確認できます。

```bash
$ curl -v -X POST "https://ocr-for-blob.cognitiveservices.azure.com/vision/v3.2/read/analyze" -H "Content-Type: application/json" \
> -H "Ocp-Apim-Subscription-Key: <Computer Visionのキー>" --data-ascii "{\"url\":\"https://teststorageforocr.blob.core.windows.net/upload/338px-Atomist_quote_from_Democritus.png\"}"
～中略～
< operation-location: https://ocr-for-blob.cognitiveservices.azure.com/vision/v3.2/read/analyzeResults/b257e82d-1956-49b9-b065-232d387bad2a
< x-envoy-upstream-service-time: 91
< csp-billing-usage: CognitiveServices.ComputerVision.Transaction=1
< apim-request-id: b257e82d-1956-49b9-b065-232d387bad2a
< strict-transport-security: max-age=31536000; includeSubDomains; preload
< x-content-type-options: nosniff
< date: Wed, 09 Mar 2022 15:50:14 GMT
<
* Connection #0 to host ocr-for-blob.cognitiveservices.azure.com left intact

$ curl https://ocr-for-blob.cognitiveservices.azure.com/vision/v3.2/read/analyzeResults/b257e82d-1956-49b9-b065-232d387bad2a -H "Ocp-Apim-Subscription-Key: <Computer Visionのキー>" \
> | jq '.analyzeResult.readResults[].lines[].text'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2247  100  2247    0     0  15713      0 --:--:-- --:--:-- --:--:-- 15713
"NOTHING"
"EXISTS"
"EXCEPT"
"ATOMS"
"AND EMPTY"
"SPACE."
"Everything else"
"is opinion."
```

トークンの有効期限などの管理をしなくてよい分、マネージドIDを利用するのがお手軽そうですね。

# おわりに
Blobの画像にOCR処理を実行するのはよくある利用シーンだと思うのですが、公式ドキュメント探してもコレっていう記載が見当たらなかったのでメモとして残しておきます。
特に「Cognitive ServiceリソースがマネージドIDを利用して他サービスにアクセスする」ってあたり、全く記述がないような…。（書いてあるページがあったらどなたか教えてください…）

上記に紹介したように権限を与えてあげればBlob内のデータにサクッと処理を行えるのでとっても便利です。
REST API以外にも各言語向けにライブラリも公開されているので、簡単に処理を実装できると思います。
Azure Cognitive ServicesではOCR以外にも物体認識や顔認識、画像全体の概要説明などの機能がいろいろ公開されているので、ぜひ利用してみてください。