一個會回傳可驗證定界框的 OCR API
多數 OCR API 都會回傳定界框——但座標系統各不相同,而一個框只告訴你位置,不告訴你有多確定。這是一份開發者導向的指南,談帶來源座標的 OCR,外加一個比對命中率,告訴你每個值有多少真的在頁面上被找到。
定界框是你驗證 OCR 的方式。一個光禿禿的字串只告訴你模型認為它讀到了什麼;一個框則告訴你它是在頁面上的哪個位置讀到的,這樣你(或你的審核者,或你的程式碼)就能拿這個值去對照原件,而不必盲目相信。如果你要把 OCR 整合進任何會被稽核的東西——發票、費用、KYC、紀錄管理——「模型回傳了 total: 2,045」是不夠的;你得能指出 2,045 是從哪些像素來的。
好消息是:多數主流 OCR API 確實會回傳定界框。陷阱在於,一旦你開始動手做,它們有三個會帶來影響的差別——座標系統、你是不是也拿得到結構化欄位(而不只是純文字),以及那個逐值信心到底量的是什麼。本指南會把這三點都走一遍,並示範一個帶來源座標、外加一個字元覆蓋比對命中率的 OCR API 在實務上長什麼樣子。
先看證據:你可以滑過去驗證的框
這裡有一個真實的擷取結果,每一個值都指回它被讀出來的確切區域。把滑鼠移到任一欄位上——收據上的框就是那個值的來源,而且每個框都帶著一個比對命中率,告訴你這個值有多少文字真的在頁面上被定位到。

Every value carries a verified on-page location — bbox + 4-point vertices + match_ratio — on a 0–1000 normalized grid (0,0 top-left → 1000,1000 bottom-right), the same shape the live API returns. Hover a field to trace it back to the pixels it came from.
多數 OCR API 都會回傳框——以下是它們的差別
Google Cloud Vision、Tesseract、Amazon Textract 和 Azure AI Document Intelligence 都會在回傳文字時一併附上幾何資訊。它們的分歧在於座標系統、你拿到的是結構化欄位還是只有純文字加版面,以及那個信心數字代表什麼意思。這些是查證過的事實,不是行銷話術——拿它們來估算你那套技術堆疊的整合工作量。
| API | 座標系統 | 結構化欄位 | 逐值信心 |
|---|---|---|---|
| Google Cloud Vision | boundingPoly 頂點,以來源影像的像素為單位 | 只有文字+幾何(結構化的鍵值對屬於 Google Document AI,是另一個獨立產品) | 每個字/符號的辨識信心(0–1) |
| Tesseract | hOCR/TSV 框,以像素為單位(自架,無 API) | 無——只有純文字+版面 | 每個字的辨識信心(0–100) |
| Amazon Textract | BoundingBox,以頁面寬高正規化為 0–1(+Polygon) | 透過 AnalyzeDocument 處理表單/表格;收據透過 AnalyzeExpense | 每個區塊的辨識信心(%) |
| Azure Document Intelligence | 定界多邊形,以像素(影像)或英吋(PDF)為單位 | 預建/自訂模型 | 每個字的辨識信心 |
| space-ocr | bbox,正規化為 0–1000(+有方向的 vertices) | 內建範本+自訂欄位,含明細項目 | match_ratio——這個值有多少比例的字元在頁面上被找到——+bbox_source |
有兩件事值得注意。第一,座標單位不可移植——Vision/Tesseract/Azure 的像素框綁死在你送出的那張影像上,而正規化的框(Textract、space-ocr)則撐得過縮放。第二,信心那一欄代表的意思各不相同:多數 API 報的是辨識信心(模型有多確定),這跟量測一個回傳值有多少真的在頁面上被定位到,完全是兩回事。
框是怎麼推導出來的,跟它的格式一樣重要。 用 space-ocr,語言模型只回傳每個欄位的文字——外加它用到了哪些 word token 的提示——但從不自己給出那些框。引擎接著拿這段文字,去跟視覺 OCR 在頁面上實際偵測到的符號做字元層級的比對,於是框會落在這些字元真正被找到的像素上,而每個值也會得到一個 match_ratio,代表它被定位到的程度。那些 token 提示可能有雜訊(它有時會在重複的列之間張冠李戴),所以系統用欄一致性與列一致性檢查來驗證它們,而不是盲目相信。這就是「模型宣稱的座標」和「被拿回頁面上重新核對過的座標」之間的差別。
space-ocr 為每個值回傳什麼
在每個擷取出的值旁邊,你會拿到四樣東西,所以座標絕不只是一個你得選擇相信的數字:
bbox——一個軸對齊的矩形{ xmin, ymin, xmax, ymax },由整數組成,建立在 0–1000 正規化的網格上(0,0 = 左上,1000,1000 = 右下),與影像的像素尺寸無關。vertices——恰好四個有序的點(左上、右上、右下、左下),組成一個跟著文件傾斜角度走的有方向定界框,所以歪斜的手機照片照樣框得乾淨。match_ratio——這個值有多少比例(0–1)的字元真的在頁面上被定位到。一個欄位在 ≥ 0.85 時即視為高信心命中;1.0代表每一個字元都被找到了。bbox_source——一個標籤,說明這個座標是怎麼推導出來的(例如字元比對路徑用vision_symbol_match,比對命中率掉到門檻以下時用low_confidence)。
{
"total": {
"value": "2,045",
"bbox": { "xmin": 381, "ymin": 803, "xmax": 500, "ymax": 825 },
"vertices": [
{ "x": 380, "y": 804 }, { "x": 500, "y": 801 },
{ "x": 500, "y": 823 }, { "x": 381, "y": 826 }
],
"match_ratio": 1.0,
"bbox_source": "vision_symbol_match"
}
}像素還是正規化?轉換一次,縮放就不再出包
OCR 整合常見的一個 bug,是像素座標綁死在你上傳的那張影像上——為了存檔把它縮放或重新壓縮、或漏掉一個 EXIF 旋轉旗標,疊上去的框就會飄移、被裁切、或落在錯的文字上。正規化座標避開了這一整類 bug:一個 0–1000 的框能對應到同一頁面的任何一種呈現方式。
要在顯示的影像上畫一個框,只要轉換一次:
- SVG 疊圖——給 SVG 設
viewBox="0 0 1000 1000",然後原封不動地畫出bbox/vertices。 - 絕對定位的 div——
leftPct = xmin / 1000 * 100、topPct = ymin / 1000 * 100、widthPct = (xmax - xmin) / 1000 * 100、heightPct = (ymax - ymin) / 1000 * 100。 - 轉回像素——
pixel_x = bbox_x / 1000 * image_width、pixel_y = bbox_y / 1000 * image_height。
引擎在載入時也會套用 EXIF 方向,所以它回傳的座標已經跟顯示出來的影像對齊——一張旋轉過的手機照片(方向 6/8)不需要你這邊再做一次校正。
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 正好能逮到這種情況。把它當成一道閘門——針對 match_ratio < 0.85 排序或篩選,把那少數值得人看一眼的值浮出來,而不必把每樣東西都重查一遍。
先驗證,再查詢——不必重跑 OCR
當資料留得住,座標才最有用。用 POST /upload 把影像推進一張表格,再用 GET /view 在伺服器端查詢它——where、sort、select、limit、offset——好抓出,比方說,每一列 match_ratio 偏低或 total >= 40000 的資料,不必重跑 OCR,也不另外收費。每個回傳的值都保留它的 bbox/vertices(或者用 boxes=0 把它們丟掉,換一個更輕的回應)。想深入了解這套驗證流程,請看 用定界框驗證 OCR 和 OCR 稽核軌跡。
如何從這個 API 拿到可驗證的定界框
- 請求欄位把影像 POST 到 /ocr/fields,imageType 用「url」或「base64」,並附上一個 templateId 或你自己的 fields 陣列。引擎吃的是點陣影像(JPEG、PNG、GIF、BMP、TIFF、WebP)。
- 讀取座標每個值都回傳一個 0–1000 網格上的 bbox { xmin, ymin, xmax, ymax }、四個有方向的 vertices、一個 match_ratio,以及一個 bbox_source。
- 疊圖或轉換用一個 viewBox「0 0 1000 1000」的 SVG 畫出框,或用 pixel_x = bbox_x / 1000 * image_width 轉成像素。EXIF 旋轉已經套用過,所以框會跟顯示的影像對齊。
- 以比對命中率設閘門把 0.85 以上的 match_ratio 當成高信心命中;任何低於這個的就浮出來給人看一眼,而不是把每個值都重查一遍。
- 儲存並查詢用 /upload 把影像推進一張表格,再用 GET /view(where、sort、select)查詢它——座標會被保留,不必重跑 OCR,也不另外收費。