JavaでAzure Computer Visionを使い、OCR(光学式文字認識)を行う
みすてむずはMisskeyのサーバの一つです。多様な人々が集まりジャンルフリーな雑談を日々繰り広げています。 ITに関わる方が多いのでITに関わるお話が多いです。
1.はじめに
一般的な生活をしていると、30分に1回はJavaでOCRしたいなと思うことがあります。今回はそんな時にAzure Computer Visionを利用してサクッとOCRしちゃう方法を書いていきたいと思います。
利用する環境は以下の通り
OSはUbuntu-22.04 (on WSL2)
Javaのバージョンは21、利用しているJDKはOpenJDK
IDEはIntellij IDEA CE 2023.2.3
ここに記載した手順は公式を元にしています
2.事前準備
事前準備として、Azureのアカウント登録と、ComputerVision APIの利用設定を行っておきます
2-1.Azureアカウント登録
無料試用版がおすすめ($200のクレジット付き、ただし30日の期限あり)
Basicアカウントにアップグレード可能(基本無料、従量課金制、テクサポ等なし)
2-2.ComputerVision APIの利用設定
Azureアカウントを作成した後、AzureポータルのホームからComputerVisionリソースの作成を行う
「リソースの作成」を選択
https://gyazo.com/039bcb9cf32844f4f99d3104d7ed58da
「カテゴリ」から「AI+Machine Learning」を選択→「Computer Vision」を選択
https://gyazo.com/35695a499c3c9bd2adc98194197ac769
「リソースグループ」、「リージョン」、「名前」、「価格レベル」を入力 or 選択する
「リソースグループ」は新規作成も出来る
「価格レベル」はFreeでOK
https://gyazo.com/df07f18ad9011282f2a23e027406ec1d
条項への同意ボックスをONにして「次へ」
https://gyazo.com/9b6a902584c41efb75740c9ed1f17f1c
リソースにアクセスできるネットワーク種類を選択して「確認と作成」を押下
特に問題なければデフォルトの「インターネットを含むすべてのネットワークがこのリソースにアクセスできます。」を選択しておくのがベター
https://gyazo.com/a83b38a590e0a00685010d337732dfc0
リソースの内容を確認して、問題なければ「作成」を押下
https://gyazo.com/1100262e1d8146de38c38cc5ae8fda0e
作成したComputer Visionのリソース情報を表示して、APIキーとエンドポイントをコピーしておく
APIキーはキー1でOK
https://gyazo.com/38a2457925a24ed5096a7def92848214
3.Computer Vision APIの使い方
事前準備でコピーしたAPIキー、エンドポイントを利用してREST APIを叩く
Computer Visionでは、画像の解析と解析結果取得に分けて処理を行うため、Java側でもそれぞれに用意されたURLにHTTPアクセスする必要がある。
Java標準のHttpClientでアクセス可能、詳細はサンプルコードを参照してください。
その他サードパーティ(apacheなど)でも問題ない……はず。
サンプルコードではローカルの画像をapplication/octet-streamで送っている
アクセス可能な場所(クラウド上のストレージやインターネット上に公開してるNASなど)があれば、アクセス用のURLをapplication/jsonで送信できる。
APIキー、エンドポイントの直書きは非推奨であることに注意
GithubやGitlabなど、パブリックな場所にアップロードする場合は予めソースコードから削除しておくこと。
code:OcrWithAzureSampleApp.java
package sample;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class OcrWithAzureSampleApp {
public static void main(String[] args) throws IOException {
var endpoint = "<エンドポイント>";
var apiKey = "<APIキー>";
// 画像解析用のURL組み立て、language=jaで読み取り画像の言語を指定可能
var url = endpount + "vision/v3.2/read/analyze?overload=stream&language=ja";
try(var client = HttpClient.newHttpClient()) {
// 画像解析処理に対してPOSTするためのHTTPリクエスト作成
var analyzeRequest = HttpRequest.newBuilder()
// 画像を直接送信する場合はapplication/octet-stream指定
// 画像を別の場所に置いて、アクセスできるURLを発行すれば、application/jsonでもOK
.header("Content-Type", "application/octet-stream")
// ヘッダーにOcp-Apim-Subscription-Key:APIキーを指定
// APIを叩く際の認証に必須な為、必ず指定すること。
.header("Ocp-Apim-Subscription-Key", apiKey)
// JSONで画像の場所を送信する場合は、ここでJSONを指定する
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("<文字認識用の画像パス>")))
.uri(URI.create(url))
.build();
var analyzeResponse = client.send(analyzeRequest,
HttpResponse.BodyHandlers.ofString());
// 画像の送信が成功した場合は、ステータスコード:202が返る
if (analyzeResponse.statusCode() != 202)
throw new IllegalStateException("failed");
// 解析結果については、レスポンスのヘッダー:Operation-Locationに結果取得用URLが記載されてくる
// 結果取得用URLは48時間有効
var analyzeResultUrl = analyzeResponse.headers().firstValue("Operation-Location");
if(analyzeResultUrl.isEmpty())
throw new IllegalStateException("failed");
// 画像分析に時間がかかるので待つ
Thread.sleep(5000L);
// 分析結果を取得するためのHTTPリクエスト作成
var analyzeResultRequest = HttpRequest.newBuilder()
// 分析結果の取得にもAPIキーの指定が必要
.header("Ocp-Apim-Subscription-Key", apiKey)
.GET()
.uri(URI.create(analyzeResultUrl.get()))
.build();
var analyzeResultResponse = client.send(analyzeResultRequest,
HttpResponse.BodyHandlers.ofString());
// 解析結果取得が成功した場合、ステータスコード:200が返る
if(analyzeResultResponse.statusCode() != 200)
throw new IllegalStateException("failed");
// 解析結果の取得、解析結果はJSON形式で返ってくる
System.out.println(analyzeResultResponse.body());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
解析結果は以下の形式になります。
"lines"に認識した文字列のリストが入ってきます。
linesリスト内のオブジェクトの属性:textに認識した文字列、属性:wordsに認識した文字列の各文字が入ります
code: analyzeResult.json
{
"status": "succeeded",
"createdDateTime": "2023-12-03T05:06:07Z",
"lastUpdatedDateTime": "2023-12-03T05:06:07Z",
"analyzeResult": {
"version": "3.2.0",
"modelVersion": "2022-04-30",
"readResults": [
{
"page": 1,
"angle": 2.0009,
"width": 2304,
"height": 586,
"unit": "pixel",
"language": "ja",
"lines": [
{
"boundingBox": [
475,
254,
1041,
277,
1011,
548,
498,
533
],
"text": "こう土",
"appearance": {
"style": {
"name": "handwriting",
"confidence": 0.982
}
},
"words": [
{
"boundingBox": [
475,
254,
531,
255,
521,
533,
475,
531
],
"text": "こ",
"confidence": 0.13
},
{
"boundingBox": [
535,
255,
753,
263,
743,
541,
526,
533
],
"text": "う",
"confidence": 0.743
},
{
"boundingBox": [
757,
263,
947,
270,
938,
548,
748,
541
],
"text": "土",
"confidence": 0.872
}
]
},
{
"boundingBox": [
1704,
220,
2097,
241,
2086,
532,
1685,
527
],
"text": "30",
"appearance": {
"style": {
"name": "handwriting",
"confidence": 1
}
},
"words": [
{
"boundingBox": [
1721,
220,
2064,
231,
2054,
533,
1711,
527
],
"text": "30",
"confidence": 0.996
}
]
},
{
"boundingBox": [
1162,
574,
1162,
215,
1338,
215,
1335,
574
],
"text": "1",
"appearance": {
"style": {
"name": "handwriting",
"confidence": 1
}
},
"words": [
{
"boundingBox": [
1162,
574,
1162,
215,
1306,
215,
1306,
574
],
"text": "1",
"confidence": 0.995
}
]
}
]
}
]
}
}
4.おわりに
JavaでAzure ComputerVision を利用したOCRを行う手順はいかがでしたか?この記事があなたの良きOCRライフの一助になることを祈っています。