space ocr
ガイド記事料金ドキュメント
developer

検証できるバウンディングボックスを返すOCR API

OCR API の多くはバウンディングボックスを返しますが、座標系はまちまちで、ボックスが示すのは値の出どころだけです。data.cells[path] に入る 0〜1000 正規化の box と傾きに沿う quad、そして確認すべき値を名指しする verified / review の契約を、開発者向けに解説します。

8 分で読了· 2026-08-31

バウンディングボックスは、OCRを検証するための手がかりです。素の文字列は、モデルが何を読んだつもりかを示すだけ。一方ボックスは、それをページ上のどこで読んだのかまで示してくれるので、あなた(あるいはレビュー担当者やコード)は、その値を鵜呑みにせず原本と突き合わせて確認できます。請求書、経費、KYC、記録管理といった監査の対象になる場面にOCRを組み込むなら、「モデルが total: 2,045 を返した」だけでは足りません。その 2,045 がどのピクセルから来たのかを指し示せる必要があります。

幸い、主要なOCR APIのほとんどはバウンディングボックスを返してくれます。やっかいなのは、いざ実装を始めると効いてくる3つの点で各社が違うことです。すなわち座標系、(生テキストだけでなく)構造化フィールドまで得られるか、そしてボックスの隣に付く値ごとの信号が実際には何なのか、の3つです。本ガイドではこの3点を順に解説し、座標が明示的な確認契約——値ごとの判定と、確認すべきパスの一覧——とともに返るOCR APIが、実際にどんなものかをお見せします。

ほとんどのOCR APIはボックスを返す——違いはここにある

Google Cloud Vision、Tesseract、Amazon Textract、Azure AI Document Intelligence は、いずれもテキストと一緒にジオメトリ(形状情報)を返します。違いが出るのは、座標系、構造化フィールドまで得られるのか生テキスト+レイアウトだけなのか、そして値ごとの数値が何を報告しているのか、という点です。下表は2026年8月時点の各社の公開ドキュメントをまとめたものです。仕様は動きますので、統合工数を見積もる前に最新のドキュメントで再確認してください。

API座標系構造化フィールド値ごとの信号
Google Cloud Visionソース画像のピクセル単位の boundingPoly 頂点(機能によっては normalizedVertices が返ります)テキスト+ジオメトリ(構造化されたキー・バリューは別製品の Document AI単語/シンボルごとの認識信頼度(0〜1)
Tesseractピクセル単位の hOCR / TSV ボックス(ローカルのライブラリで、ホスト型APIではありません)なし——生テキスト+レイアウト単語ごとの認識信頼度(0〜100)
Amazon Textractページの幅・高さに対して0〜1で正規化された BoundingBox(+同じく0〜1の PolygonAnalyzeDocument によるフォーム/テーブル、AnalyzeExpense による領収書ブロックごとの認識信頼度(%)
Azure Document Intelligenceピクセル(画像)またはインチ(PDF)単位のバウンディングポリゴン事前構築/カスタムモデル単語ごとの認識信頼度
space-ocr宣言したフィールドのパスをキーに、0〜1000で正規化された box +傾きに沿う quadfields で宣言(明細行は children)、または autoFieldsverified 判定+review.flagged の確認リスト(根拠は evidence

注目したい点が2つあります。1つめは、座標の単位は使い回せないこと。ピクセルのボックスは実際に読み取られた画像そのものに紐づきますが、正規化されたボックスはリサイズしても有効なままです。2つめは、値ごとの列が同じものを測っているとは限らないこと。認識信頼度が答えるのは「エンジンが自分の読み取りにどれだけ自信があるか」で、「返ってきた値がそもそもページ上で見つかったのか」とは別の問いです。

✓ Verified

ボックスがどう導き出されるかは、その形式と同じくらい大切です。 space-ocr では、言語モデルが返すのは各フィールドのテキストと、どの単語トークンを使ったかのヒントだけで、ボックスそのものは一切返しません。エンジンはそのテキストを、ビジョンOCRがページ上で実際に検出したシンボルと文字単位で突き合わせます。だからこそボックスは、それらの文字が見つかった実際のピクセルに収まります。照合が走った値については、そのセルの evidence に、どれだけ見つかったかを示す match_ratio が入ります。突き合わせる相手が無かった場合、このキーはそもそも付きません。トークンのヒントはノイズを含むことがあり(繰り返し行どうしで取り違えることもあります)、そのため鵜呑みにはせず、列・行の整合性チェックで裏を取ります。これこそ、モデルが主張するだけの座標と、ページに照らして検証し直した座標との違いです。

space-ocr が値ごとに返すもの

業務データは data.values に、リクエストしたスキーマそのままの形で入ります。その値がどこから来て、検査を通ったのかは、同じパスをキーにした別のマップ data.cells にまとまります——total、明細行なら items[0].price といったパスです。各セルが持つのは次のものです。

  • box0〜1000で正規化されたグリッド上の、整数からなる軸並行矩形 { xmin, ymin, xmax, ymax }(0,0 = 左上、1000,1000 = 右下)。画像のピクセルサイズに依存しません。
  • quad — 書類の傾きに沿った回転対応ボックスを形作る、順序付きの4点(左上、右上、右下、左下)。傾いたスマホ写真でもきれいに枠が付きます。box と必ず一緒に返ります。
  • verified — 判定であり、review の鏡です。何かが立てば false、何も立たず照合が実際に走ったなら true、何も立たないが照合する相手が無かったとき(行のユニオンなど)は null です。
  • reviewnull、または { reasons }。理由はランキング順で、先頭が代表です。コードには text_mismatchlow_rationoboxmissing などがあります。
  • evidence — 判定の生データです。text_match(文字照合そのもの)、sourcevision_symbol_matchtoken_id)、match_ratio、そしてその座標でOCRが読んだ文字である printed_text が入ります。

同じパスは data.review.flagged にも並びます。これが確認リストで、目を通すべき値ごとに1件、理由付きで載ります。data.image は実際に読み取られたページの幅と高さで、すべての座標はこれを基準に表されます。(スカラー型の type、あるいは string フィールドへの patternenum を宣言すると data.normalized の層も付きますが、下の string だけの例では現れません。)

1つの値:values と cells
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "data": {
    "values": { "total": "2,045" },
    "cells": {
      "total": {
        "box": { "xmin": 381, "ymin": 803, "xmax": 500, "ymax": 825 },
        "quad": [
          { "x": 380, "y": 804 }, { "x": 500, "y": 801 },
          { "x": 500, "y": 823 }, { "x": 381, "y": 826 }
        ],
        "verified": true,
        "review": null,
        "evidence": {
          "text_match": true,
          "source": "vision_symbol_match",
          "match_ratio": 1.0,
          "printed_text": "2,045"
        }
      }
    },
    "image": { "width": 1654, "height": 2339 }
  }
}

ピクセルか、正規化か?一度変換しておけば、リサイズで崩れなくなる

OCR統合でよく起きるバグの1つが、ピクセル座標がアップロードした画像そのものに紐づいてしまうことです。保存のためにリサイズや再圧縮をしたり、EXIFの回転フラグを見落としたりすると、重ねたボックスがずれたり、切れたり、別のテキストに乗ったりします。正規化座標なら、この手のバグをまるごと避けられます。0〜1000のボックスは、同じページをどう描画しても、その上にそのまま当てはまるからです。

先に押さえておきたいのは、基準となる面が data.image であって、送ったファイルそのものではない、という点です。これは実際に読み取られたページで、EXIFの向きはすでにピクセルに焼き込まれ、大きな写真は読み取り前に縮小されています。そのため widthheight はアップロードした画像と入れ替わって返ることがあります(4000×3000で送って3000×4000が返る、など)。data.image を基準に変換すれば計算は合います。

表示中の画像にボックスを描くときは、一度だけ変換します。

  • SVGオーバーレイ — SVGに viewBox="0 0 1000 1000" を与え、boxquad をそのまま描きます。
  • 絶対配置のdivleftPct = xmin / 1000 * 100topPct = ymin / 1000 * 100widthPct = (xmax - xmin) / 1000 * 100heightPct = (ymax - ymin) / 1000 * 100
  • ピクセルへ戻すpixel_x = box.xmin / 1000 * data.image.widthpixel_y = box.ymin / 1000 * data.image.height

EXIFの向きはそのページに適用済みなので、回転したスマホ写真(向き 6/8)でも、あなたの側で補正処理をかける必要はありません。ただし傾きの補正(デスキュー)は行いません。傾いた写真は傾いたままなので、quad が傾きに沿い、box はその周りで軸に並行なままになります。

フィールドをリクエストして座標を受け取る
1
2
3
4
5
6
7
8
9
10
11
curl -s https://api.space-ocr.com/ocr/fields \
  -H "Authorization: Bearer $SPACE_OCR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "https://example.com/receipt.jpg",
    "imageType": "url",
    "fields": [
      { "name": "vendor", "type": "string" },
      { "name": "total",  "type": "string" }
    ]
  }'

信頼度スコア、マッチ率、そして判定

ここは押さえておく価値のある区別です。ほとんどのOCR APIが用意しているのは認識信頼度で、これはフォントの鮮明さや画質などをもとに、エンジンが自分の読み取りにどれだけ自信があるかを表す数値です。役には立ちますが、いわばモデルが自分の答案を自分で採点しているようなもの。これに対してマッチ率は、外側の事実を測ります。モデルが返した値の文字のうち、ページ全体のOCRが検出したシンボルの中で実際に見つかったのは何文字か、です。値は十分な認識信頼度を付けて返ってきても、ページ上の何にも一致しないことがあり得ます。

とはいえ、この比率を渡されて「しきい値は自分で決めてください」と言われるわけではありません。match_ratio は判定の根拠として evidence に入っています。しきい値はエンジン側が当てており——0.85以上で確実な文字一致として扱われます——カバレッジが足りなければ、そのセルは review の理由に low_ratio を付けて返ります。したがってコード側のゲートは review != null、より良いのは data.review.flagged をそのまま回すことです。そうすれば、比率では見えないクラスにも届きます。required なのに一度も返らなかった値(missing)、座標が付かなかった値(nobox)、宣言したパターンや範囲を破った値、などです。

意外に思われがちですが、驚く必要のない組み合わせが1つあります。verified: falseevidence.text_match: true の同居です。これは文字としてはページと一致していて、あなたが宣言したルールの方が引っ掛けた値です。どちらも理由は違えど確認に値します。そして、どちらも逆側を保証するものではありません——2つのエンジンが同じ誤読で一致してしまうこともあるからです。

検証したら、OCRを再実行せずにクエリする

座標は、データが残り続けてこそいちばん役立ちます。POST /upload で画像をシートに投入し、あとは GET /view でサーバー側からクエリするだけです。wheresortselectlimitoffset を使って、たとえば total >= 40000 の行をまとめて取り出す、といった操作が、OCRの再実行も追加課金もなしに行えます。絞り込みの対象になるのはそのシートの列(ほかに nameocrStatuscreatedAt)で、各行は cells マップを保ったまま返るので boxquad もそのままです。boxes=0 を付ければ外して軽いペイロードにもできます。検証ワークフローの詳しい解説は、バウンディングボックスによるOCRの検証OCR監査証跡をご覧ください。

どの値をクリックしても、その出どころの領域が原本上で光ります。APIが返すのと同じ座標を、そのままインタラクティブにしたものです。

APIから検証可能なバウンディングボックスを得る手順

  1. フィールドをリクエストする
    imageType を 'url' または 'base64' にして画像を /ocr/fields へPOSTし、独自の fields 配列を渡すか autoFields を true にします。エンジンが読むのはラスター画像です。
  2. 座標を読む
    data.cells をフィールドのパスで引きます。各セルには、0〜1000グリッド上の box { xmin, ymin, xmax, ymax }、4点の quad、判定の verified、review、evidence が入っています。
  3. 重ねる、または変換する
    SVG の viewBox '0 0 1000 1000' でボックスを描くか、pixel_x = box.xmin / 1000 * data.image.width でピクセルに変換します。data.image は実際に読み取られたページで、EXIF回転はすでに適用済みです。
  4. 確認リストを処理する
    スコアを自分でしきい値判定するのではなく、data.review.flagged を回します。各エントリはパスと理由の組で、根拠は cells[path].evidence に、match_ratio も含めて入っています。
  5. 保存してクエリする
    /upload で画像をシートに投入し、GET /view(where、sort、select)でクエリします——各行は box と quad を含む cells マップを保持し、OCRの再実行も追加料金もありません。
どのOCR APIがバウンディングボックスを返しますか?
Google Cloud Vision、Tesseract、Amazon Textract、Azure AI Document Intelligence は、いずれもテキストとともにジオメトリを返し、space-ocr も同様です。2026年8月時点の各社の公開ドキュメントによれば、違いは座標系(Vision と Tesseract はピクセル、Azure は画像がピクセルでPDFがインチ、Textract は0〜1で正規化、space-ocr は0〜1000で正規化)、構造化フィールドが返るのか生テキスト+レイアウトだけなのか、そして値ごとの数値が何を報告するのか、にあります。
バウンディングボックスの座標はピクセルですか、それとも正規化されていますか?
space-ocr は、画像のピクセルサイズに依存しない0〜1000グリッドに正規化された box と、ページの傾きに沿う4点の quad を返します。ピクセルへの変換は pixel_x = box.xmin / 1000 * data.image.width(yも同様)で行えますし、SVG の viewBox を '0 0 1000 1000' にすればそのまま重ねられます。基準となる面は data.image、つまりEXIFの向きと必要な縮小を経て実際に読み取られたページなので、その width と height は送ったファイルと異なることがあります。
OCRの信頼度スコアとマッチ率の違いは何ですか?
認識信頼度は、エンジンが自分の読み取りにどれだけ自信があるかを表します。一方 match_ratio は、返された値のテキストが、ページ全体のOCRが検出したシンボルの中で実際にどれだけ見つかったかを測ります。自己申告ではなく、外側からのチェックです。これは根拠として cells[path].evidence に入ります。0.85以上で確実な文字一致として扱われ、カバレッジが足りなければエンジンがそのセルの review 理由に low_ratio を立てるので、コード側は数値ではなく review でゲートします。
傾いた写真や回転した写真でも、回転対応のバウンディングボックスを得られますか?
得られます。すべてのセルが、軸並行の box と一緒に、順序付きの4点(左上、右上、右下、左下)からなる quad を返し、quad は書類の傾きに沿います。傾きの補正(デスキュー)は行いません。また座標の基準となるページ(data.image)にはEXIFの向きが適用済みなので、向き6または8のスマホ写真でも、あなたの側で補正処理をかける必要はありません。
このバウンディングボックス対応OCRは、日本語・韓国語・中国語でも動きますか?
動きます。ひとつのエンジンが、自動言語検出でCJKとラテン文字の両方を扱います。設定すべき言語パラメータはありません。文字体系を問わず、全角文字も含めて、すべての値が同じ契約で返ります——宣言したフィールドのパスをキーに、data.cells の box、quad、verified、review、evidence です。
関連記事