AIの活用例 COORDOCR / 開発・検証記録
ローカルAIで座標表OCRを実用化するまで
―モデル比較・CPU/GPU検証からアプリ公開へ
配布版 v1.0 の到達点
PDFの座標表からSIMAへ
2026年9月に公開したv1.0では、PDFの座標表を囲んで切り抜き、PC内のAIで読み取り、原画像と見比べながら確認・修正し、SIMAファイルへ出力できます。SIMAは、座標などをCAD・測量ソフトへ受け渡すためのデータ形式です。公開時の紹介記事
- 01
切り抜く
人が範囲を選ぶ。
PDFから座標表を切り抜く。人が対象を決める。
- 02
読み取る
AIが表を読む。
GLM-OCRで読み取る。点名・X・Yを取り出す。
- 03
確認・修正する
人が原画像と照合。
原画像と照合して修正する。「修正を反映」で確定する。
- 04
SIMAへ出力する
CAD・測量ソフトへ。
SIMAへ出力する。CAD・測量ソフトでも確認する。
配布版 v1.0 の処理フロー。
出力後もCAD・測量ソフトで確認します。
専用GPUは必須ではなく、初期設定はCPUです。対応するGPUがあれば、NVIDIA向けのCUDAや、内蔵GPUなどで使えるVulkanへ切り替えられます。モデルと推論エンジンを同梱し、ダウンロード後のPDF処理・OCR・SIMA出力はオフラインで利用できる構成にしました。
ただし、読み取れた一覧をそのまま正解とする道具ではありません。数字の桁、小数点、マイナス符号、点名、XとYの対応を元資料で確かめ、出力先のCAD・測量ソフトでも確認するところまでが、実務での使い方です。
現在の機能や動作環境、ダウンロードの入口は、座標OCRの公式配布ページにまとめています。このページでは、そこへ至る過程を説明します。
この特集について
地積測量図や道路境界確定図の座標を手入力するのはめんどくさい。この業種に携わる方々ならだれもが思うことです。ところが、画像から数字を読み取れたことと、日々の仕事で使えることの間には、思った以上にいくつもの段階がありました。
PDFから表を切り出す。モデルに読ませる。返ってきた回答を点名・X座標・Y座標として取り出す。元の表と照合し、SIMAへ出力する。そのつなぎ目を一つずつ見直して、Windowsアプリ「座標OCR」の配布までたどり着きました。
ここでは、11モデルの比較を中心に、読み取り方の調整、CPU・内蔵GPU・専用GPUでの検証、アプリ化までを振り返ります。モデル比較とハードウェア比較は別の実験です。それぞれの条件を分けて、何を確かめ、次に何を変えたのかを追っていきます。
初期試作
Doclingを使ったOCRから、画像を読めるLLMの試作へ。
2026.09.10–11
2026年9月10〜11日:同じ9枚を比較し、モデル別の指示・解析を調整。
2026.09.23
2026年9月23日:Q8_0・llama.cppでCPU/GPUを検証。
2026.09.24
2026年9月24日:v1.0をGitHub Releasesで配布。
初期試作の実験日は未確認です。画面の統合は、比較と並行して進めています。日付は測定・Releaseの確認記録に基づきます。
きっかけ
02発端
入力するだけでも、確認するだけでも大変
座標表が256行あれば、点名が256個、XとYが合わせて512個。合計768項目を、図面と画面を行き来しながら入力することになります。1桁違えば別の場所になってしまうので、打ち終えた後の照合も欠かせません。
以前は、PDFから座標部分を切り出し、Doclingという文書処理ツールでOCRし、Excelを経由してSIMA化する流れを作っていました。ただ、新しい地積測量図のような条件のよい資料では動いても、道路境界確定図や紙をスキャンした資料では、安定して使えるところまで届きませんでした。傾き、文字の状態、切り出し方によって結果が変わります。初期の取り組み
小数点や「0」と「O」の違いだけでなく、列がずれたり、数字の間に空白が入ったりしても、その先の処理は困ります。一部をそれらしく取り出せるだけでは、結局、手入力した方が早いという話になってしまいます。
そこで、画像を読めるローカルLLMを試すことにしました。LLMは文章を扱うAIモデルですが、画像入力に対応するものや、文書・表の読み取りに特化したものもあります。ここで任せたいのは、座標を推測することではなく、表に書かれた文字を取り出すことです。
処理を分ける
03処理の設計
表を読む仕事と、データを扱う仕事を分ける
最初から図面全体を渡して、SIMAまで一度に作ってもらう構成にはしていません。PDF上で人が座標表の範囲を選び、表の画像をAIに渡します。図面全体から表を見つける問題を切り離し、点名・X・Yの読み取りに仕事を絞りました。
初期の指示では、左から3列を上から順に読み、推測しないこと、読めない行は出力しないこと、説明を付けずJSONだけを返すことを指定しました。JSONは、後のプログラムが項目ごとの値を受け取れるデータ形式です。Python側が回答を解析し、形式を確認してExcelやSIMAへつなぎます。
この分担では、「AIが返したから正しい」とは扱いません。逆に、プログラムが読めない数字を勝手に埋めることもしません。後の比較では、座標を文字列として扱い、小数を丸めたり末尾にゼロを足したりせずに、正解と比較しました。点名の表記をそろえる処理と、座標値を変える処理は分けています。処理の設計と比較条件
また、終了したかどうかの確認も必要でした。2026年9月9日の開発記録では、長い表のJSONが途中で切れる問題を確認しています。設定された4,096トークンの枠を使い切っていたため、コンテキストを8,192へ増やし、thinkingをオフにし、長さ制限による終了を失敗として扱うようにしました。トークンは、モデルが入力や出力を扱う単位です。モデルの公称上限と、その実行で割り当てた枠は同じではありません。
これは当時のOllama版での改善です。正常終了を示す情報が返っても、画像の全行を読み取った保証にはなりません。終了判定、行の取り出し、内容の照合は、それぞれ別に必要です。
最初の試作
04最初の試作
大きなモデルでは読めた。その次は
初期の記事で紹介したのは、qwen3.5:27bをRTX 4090で動かす構成でした。33点の表に1分56秒、23点の表に1分17秒かかり、そのサンプルでは誤りは見当たりませんでした。これは2枚のLLM処理時間であり、切り抜きからSIMA出力までの総作業時間ではありません。初期の試作結果
読み取れることは分かってきました。そうなると、次に知りたくなるのは、「座標表を読むために、この大きさのモデルや高価なGPUが必要なのか」ということです。もっと軽いモデルで同じように読めるなら、待ち時間も必要な機材も変わります。
そこで、同じ画像と正解データを用意して、モデルを比較しました。ここからは、使ってみた印象だけでなく、点名と座標が何行一致したか、時間とGPUメモリがどれだけ必要だったかを見ていきます。
検証 01 · 2026年9月10〜11日
0511モデル比較
大きさだけでは決まらなかった
同じ入力9枚・256行
読み取り方共通JSON+モデル別調整
時間の範囲API応答・9枚を各1回
同じ9枚を使い、読み取り方をモデルに合わせる
比較に使ったのは、TEST01〜TEST09の9枚、合計256行です。1枚あたり12〜48行で、点名にはハイフン、ピリオド、コロン、プラス、括弧なども含まれます。テストでは元の9枚をそれぞれ入力し、モデルごとに画像を加工したり、さらに分割したりはしていません。
推論環境はUbuntu・Ollama 0.33.0・RTX 5060 Ti 16GBです。PDF操作やPythonの実行はWindows側、モデルの推論はサーバー側で行いました。コンテキストは8,192、temperatureは0。9月10日の共通JSON方式の比較に、9月11日のモデル別調整結果を組み合わせたのが、公開した11モデルの表です。
Qwen系はJSON、GemmaはMarkdownの表、GLM-OCRはHTMLの表を読み取る方式です。つまり、同一プロンプトに対する能力順位ではなく、モデルに合わせて組んだ読取処理を、同じ資料で比較した結果です。設定を選ぶ予備試験に使った画像も、この9枚に含まれます。
読取結果・時間・VRAMの要約
薄い青の「調整」は、共通JSONから指示・回答形式を変えた結果です。出力一致は点名の空白処理後、rawはその処理前の解析値で比較。時間はモデル読み込み・通信を含むAPI応答です。
表は領域内で左右にスクロールできます。
| モデル(当時のタグ) | 指示・回答形式 | 出力一致/256行 | raw一致率 | 平均 秒/枚 | 合計 秒/9枚 | VRAM GiB |
|---|---|---|---|---|---|---|
glm-ocr:bf16 | 調整・HTML | 256/256 | 99.22% | 5.72 | 51.48 | 2.14 |
qwen3-vl:4b-instruct | 共通JSON | 256/256 | 83.20% | 10.85 | 97.64 | 3.94 |
qwen3.5:4b | 共通JSON | 256/256 | 78.52% | 10.90 | 98.06 | 3.11 |
qwen3-vl:8b-instruct | 共通JSON | 256/256 | 94.53% | 16.50 | 148.52 | 6.09 |
qwen3.5:9b | 共通JSON | 256/256 | 78.52% | 17.01 | 153.13 | 5.34 |
qwen3.6:27b | 共通JSON | 256/256 | 83.20% | 45.63 | 410.69 | 12.53 |
qwen3.5:27b | 共通JSON | 256/256 | 67.19% | 124.44 | 1119.94 | 13.44 |
qwen3.8:27b | 共通JSON | 256/256 | 83.20% | 53.09 | 477.84 | 12.42 |
gemma4:e4b | 調整・Markdown | 201/256 | 67.58% | 8.78 | 79.06 | 3.14 |
gemma4:12b | 調整・Markdown | 140/256 | 48.05% | 18.29 | 164.64 | 7.80 |
deepseek-ocr:3b | 調整・Markdown | 0/256 | 0.00% | 6.54 | 58.83 | 7.31 |
「出力一致」は点名・X・Yの3項目が正解と完全に一致した行数です。点名は文字幅をそろえ、内部の空白を除去してから、正解側にも同じ処理をして比較しました。「raw」は内部の空白除去前の行一致率で、JSONや表から取り出した値の比較です。回答文全体の一致率や、何も処理していない生応答の一致率ではありません。座標には丸めや桁補完をしていません。
平均は1枚あたり、合計は9枚を1回ずつ処理したAPI応答時間です。モデルの読み込み、通信、失敗した試行を含みます。PDFの切り抜き、結果の確認・修正、Excel保存、再検算、SIMA出力は含みません。冷間・温間の状態までそろえた速度試験ではなく、この環境での目安です。
VRAMはGPU上のメモリで、表の値はOllamaが報告したモデルへの割当量です。実際の使用率や、PC全体の必要メモリではありません。27Bの3モデルでは、CPU側への割当推定量も約2.78〜4.54 GiBありました。時間差を、その量だけで説明することはできません。
当時の記録では、Qwen・GemmaはQ4_K_M、DeepSeek-OCRはF16と報告されています。GLMは使用タグがglm-ocr:bf16ですが、同じ記録の精度形式欄はF16です。タグ名と記録値を区別し、後のQ8_0版とも混同しないで扱います。Q4_K_MやQ8_0は、モデルの重みを省メモリで扱うための量子化形式です。11モデル比較の詳細
比較を受けて、軽量モデルを候補にする
GLM-OCRとQwen系7モデルは、点名の空白処理後に256/256行が一致しました。一方、今回の9枚では、大きな27Bモデルに軽量モデルを上回る出力一致の差は見られず、時間とメモリの負担が増えています。
GLM-OCRは約51秒、VRAM割当は約2.14 GiB。qwen3-vl:4b-instructとqwen3.5:4bは約98秒でした。16GBのGPUでの実測から、8GBクラスでも使えそうだという見通しは得られましたが、この比較で8GB機そのものを試したわけではありません。
Gemmaは表形式の指示に変えて一致行が増えても、誤読や行抜けが残りました。DeepSeek-OCRの0/256は、文字を何も認識しなかったという意味ではありません。返ってきた回答から、点名・X・Yの行を曖昧さなく取り出せなかった結果です。
軽量Qwenの3モデルは、別の反復試験でも各768/768行が一致しました。ただし同じ9枚を3回読んだ結果であり、768種類の未知の座標を試したわけではありません。GLM-OCRのこの比較表は、全9枚を1回確認した値です。
実用化への転換点
06GLM-OCR
読めないのか、受け取り方が合っていないのか
この比較で特に大きく変わったのがGLM-OCRでした。最初の共通JSON指示では、各画像からほぼ1行ずつしか得られず、出力一致は8/256行でした。それを、表を読むための専用指示Table Recognition:へ変更すると、表全体がHTML形式で返ってきました。
ところが、今度は表を返した後もAPIが完了を通知しません。そこで、表の終わりを表す</table>を停止条件に加えました。これにより全9枚が正常終了し、HTMLのセルをPythonで取り出して比較できるようになりました。
表は領域内で左右にスクロールできます。
| 課題 | 試した変更 | 確認できた結果と次の判断 |
|---|---|---|
| 共通JSON指示では表全体を得られない。 | Table Recognition:で表認識を指示する。 | HTMLの表が返る。回答形式をモデルに合わせる。 |
| 表は返るが、APIが完了を通知しない。 | stop: ["</table>"]を指定する。 | 9枚すべて正常終了。1画像1表を前提にする。 |
| 返答を座標データへつなぐ必要がある。 | 明示的に区切られた3列のセルを解析する。 | 欠けた数字や曖昧な列を推測で復元しない。 |
| 点名の字間が空白として残る。 | 点名の文字幅・空白を同じ規則で整える。 | rawは254/256行、処理後は256/256行が一致。座標値は変更しない。 |
出典:GLM-OCRの指示・終了条件と結果。この停止条件は当時のOllamaで検証したものです。複数の表を一枚に入れると、最初の表の終端で止まる可能性があります。
「読み取りが悪い」と見えた結果にも、指示、回答形式、解析方法、終了判定の問題が含まれていました。最初の8/256行だけで候補から外していたら、このモデルを使う判断には至らなかったと思います。
この段階では、GLM-OCRと軽量Qwenを組み合わせた照合も構想していました。ただし、当時の構想を、配布版v1.0の実装済み機能とは扱いません。現在の配布版はGLM-OCR Q8_0を使用し、人が原画像を見ながら確認・修正する流れです。
検証 02 · 2026年9月23日
07CPU・内蔵GPU・専用GPU
使えるPCの範囲を確かめる
同じ入力9枚・256行
共通の実行条件GLM-OCR Q8_0 / llama.cpp
時間の範囲起動を除くOCR・原則3回
軽量モデルにめどが立つと、次は専用GPUのないPCでも使えるかが気になります。自分の高性能PCで速く動くことと、ほかの環境でも使い始められることは別です。
2026年9月23日の検証では、Windows 11・llama.cpp b10964・GLM-OCR Q8_0で、同じ9枚・256行を読み取りました。llama.cppはモデルを実行する推論エンジンです。ここではOllama経由のサーバー処理から、Windows上で実行する構成へ変わっています。
コンテキスト8,192、temperature 0、画像のトークン数1,024、最大生成6,144トークンを共通にし、各条件を3回測定しました。主な比較はテスト版0.5.0-test1です。CPUスレッドは論理CPU数の半分・上限8で、258Vは4、ほかは8でした。各CPUを個別に最適化した最高性能の比較ではありません。
検証 02 / 同じ9枚・256行
同じPCでも、処理方式で時間は変わる
GLM-OCR Q8_0 · Windows 11 · llama.cpp b10964
原則3回の中央値。起動・切り抜き・確認・修正・SIMA出力を除く。258V CPUは正常2回の参考値です。細線は正常回の最小〜最大。
9枚のOCR時間(秒)/短いほど処理時間が少ない
Ryzen AI MAX+ 395 RAM 128GB
Ryzen 7 7840HS RAM 32GB
Core i9-13900K RAM 64GB
Ryzen 7 5800U RAM 16GB
Core Ultra 7 258V RAM 32GB
図:9枚・256行のOCR時間(秒)。共通のモデル・画像・推論設定で測定したPC/処理方式の比較です。モデル起動、切り抜き、確認・修正、採点・CSV保存、SIMA出力を含みません。各PCはAC給電ですが、温度やバックグラウンド負荷は統一していません。条件の異なるRTX 5060 Tiの過去測定は含めていません。出典:CPU・内蔵GPU・専用GPU比較および同実験の保存済み集計値。
表は領域内で左右にスクロールできます。
| PCのCPU/搭載RAM | 処理方式 | 中央値 秒/9枚 | 正常完了 |
|---|---|---|---|
| Ryzen AI MAX+ 395/128GB | CPU・8スレッド | 349.73 | 3/3回 |
| Ryzen AI MAX+ 395/128GB | Radeon 8060S/VULKAN | 119.98 | 3/3回 |
| Ryzen 7 7840HS/32GB | CPU・8スレッド | 372.64 | 3/3回 |
| Ryzen 7 7840HS/32GB | Radeon 780M/VULKAN | 207.94 | 3/3回 |
| Core i9-13900K/64GB | CPU・8スレッド | 389.75 | 3/3回 |
| Core i9-13900K/64GB | Intel UHD 770/VULKAN | 561.79 | 3/3回 |
| Core i9-13900K/64GB | RTX 4090/CUDA | 23.13 | 3/3回 |
| Ryzen 7 5800U/16GB | CPU・8スレッド | 1,107.83 | 3/3回 |
| Ryzen 7 5800U/16GB | Radeon Graphics/VULKAN | 682.85 | 3/3回 |
| Core Ultra 7 258V/32GB | CPU・4スレッド | 1,167.13 ※参考 | 2/3回 |
| Core Ultra 7 258V/32GB | Intel Arc 140V/VULKAN | 219.00 | 3/3回 |
数値は保存済み集計の中央値を小数2桁で表示しています。元記事の「6分13秒」「6分30秒」などは、同じ値を秒単位に丸めた表記です。CPU・GPUによる速さの違いは、GPU機種とCUDA/Vulkanなどの実行方式を合わせた結果で、実行方式だけの優劣を示すものではありません。
Ryzen 7 7840HSはCPUで約6分13秒、内蔵のRadeon 780Mで約3分28秒でした。Core Ultra 7 258VのArc 140Vも約3分39秒。一方、Core i9-13900KではCPUの約6分30秒に対し、UHD 770は約9分22秒かかっています。GPUを使えば必ず速くなる、という結果ではありませんでした。
同じ13900K機でRTX 4090を使うと23.13秒です。CPUで数分かかる表を、この時間で処理してしまうのには、やはり驚かされます。ただ、先のRTX 5060 Tiの51.48秒とは、モデル形式、OS、エンジン、反復回数、起動時間の扱いが違います。二つの数字を同条件のGPU速度ランキングにはできません。
別途、Ryzen AI MAX+ 395は8スレッドの349.73秒から、16スレッドで283.90秒へ短縮しました。所要時間は約18.8%減です。16スレッド側はテスト版0.5.0-test2で、モデル・エンジン・画像・スレッド数以外の推論設定が一致することを記録で確認しています。スレッドを倍にしても、速度は倍にはなりませんでした。メモリ帯域だけで時間差が決まるわけでもなく、実効帯域や温度などを測っていないため、原因の断定はできません。
258VのCPUは1回目の1画像で接続エラーがあり、図表では正常に完了した2回の参考値としています。その2回も約15分52秒と23分02秒に分かれました。誤読、処理の未完了、時間のばらつきは、分けて見る必要があります。
395の16スレッド測定を含め、正常取得できた323画像・延べ9,183行は、点名の正規化後に正解と一致しました。同じ9枚の反復結果です。これは任意の図面での100%精度を意味せず、各PCで切り抜きからCAD取込みまでの全操作を測定した結果でもありません。
この検証から、CPUや内蔵GPUでも、機種と処理量を選べば使えることが見えてきました。一方、古いCPUで大量の表を繰り返すのは厳しい。専用GPUを必須にせず、対応環境では処理方式を選べる形で案内するための、具体的な判断材料になりました。
操作をつなぐ
08アプリ化
処理をつなぎ、確認する場所を作る
Codexを使い始めてから、今後のComputer Use(AIによる画面操作)も見据えて、各種バッチファイルで実行していた処理を一つの画面から操作できるようにしました。
私の環境では、今でもQwenでの処理を行っています。長い期間使ってきたこともあり、ある程度の信頼性があると感じているからです。
ただ、GLM-OCR Q8_0がある程度動くと分かったので、「GitHubで配布するのもありかな」と思い、配布用アプリの作成をCodex様に依頼することにしました。
操作動画で紹介した2表・47点、19秒と12秒という読取時間は、Qwenを使った構成での例です。当時の操作動画と実行環境
動画の記事には、「もう手入力には戻れません」と書きました。もちろん確認は必要ですが、数字を一つずつ打ち込む手間がなくなるだけでも、ずいぶん楽です。ただ、自分の環境で動く処理を配るには、別途PythonやOllamaを準備するところも含めて考え直す必要がありました。
配布版では、GLM-OCR Q8_0とllama.cppを同梱し、PDFの切り抜き、対象画像の選択、OCR、原画像との照合、修正、SIMA出力を一つのウィンドウへまとめました。別のPDFやページから追加した表も、同じ一覧で扱えます。アプリ公開の記事
確認・修正では、入力欄を書き換えた瞬間に確定するのではなく、「修正を反映」を押した内容を保存するようにしました。別の点や画像へ移ると、未反映の入力は取り消されます。点名の先頭に同じ文字を付ける機能や、連番へ変更する機能も、現在見ている画像を対象にしています。
ここで大事なのは、OCRの秒数だけを縮めることではありません。読んだ結果をどこで確かめ、どの修正を出力へ反映したのかが分かることです。元のPDF、切り抜いた画像、座標一覧、修正履歴は配布フォルダ内へ残す構成にしました。
使い始められる形へ
09GitHubでの配布
ZIPを展開して使い始める形へ
GitHubの配布用リポジトリは、chosashi-tsurumi/coordocrです。2026年9月24日に「座標OCR(COORDOCR)v1.0 正式版」のReleaseを公開し、COORDOCR-v1.0.zipと照合用のSHA-256ファイルを掲載しました。Releaseは、版ごとの配布物を置く場所です。GitHubのv1.0 Release
ZIPは2,123,207,889バイト、約2.12GBです。モデルと推論エンジンを含むため大きくなりますが、利用者はPython・Ollama・Excelを別途インストールせず、ZIPをすべて展開して「座標OCR.exe」を起動できます。EXEだけを取り出さず、同梱フォルダを一式で保管します。
配布までには、PDF処理の部品をPDFiumへ置き換え、不要な同梱物や重複する部品を整理し、第三者ライセンスの通知をまとめる作業もありました。9月24日のリリース記録では、展開後のファイル照合や、開発用Pythonを参照しない条件での起動確認を残しています。読取処理を作ることに加えて、ほかのPCへ一式を渡せる形に整える工程が必要でした。
GitHubに置いたからといって、アプリをオープンソース化したわけではありません。確認時点の公開リポジトリには利用案内のREADMEがあり、アプリのソースは非公開です。READMEは、同梱ソフトウェア・モデルのライセンスをZIP内のlicensesで確認するよう案内しています。アプリ本体と同梱物を一律のライセンスとは説明しません。公開リポジトリの案内
使い始めるときは、公式配布ページで動作環境と注意事項を確認し、配布ZIPを選びます。GitHubが表示する「Source code」は、このアプリの配布ZIPではありません。まず小さな表で読み取りと照合を試すところから始めてください。
実務で使うために
10限界と、取り組みを通じて分かったこと
今回の9枚には、設定の調整に使った資料も含まれています。英数字中心の点名、小数3桁の正解座標での検証であり、漢字を含む点名、別の桁数の実画像、さらに長い表、状態の悪いスキャンなどを網羅した評価ではありません。11モデル比較の対象で最も長い表は48行でした。
点名の空白処理後に全行一致した結果も、内容を見ずに使ってよいという意味ではありません。座標表では、たった一つの符号や数字の違いが問題になります。読み取り後は元資料と照合し、SIMAを取り込んだ先でも確認する。この前提は、最初の試作から配布版まで変わりません。
ローカル処理は、読み取り画像を外部のAIサービスへ送らずに済む構成です。ただし、保存したPDFや画像、座標データがPC内に残る以上、その保管やバックアップの管理も必要です。「ローカルだから絶対に安全」という保証にはなりません。
モデルの大きさより、読み取らせたい対象と、回答の受け取り方が効いた場面がありました。GPUを使うよりCPUの方が速い機種もありました。そして、読む処理ができた後にも、確認・修正、保存、配布のための仕事が残りました。そうした一つずつを確かめて、ようやく使う流れがつながったのだと思います。
全工程を通した時間短縮は測定していないので、「何分の仕事が何分になった」とは言えません。それでも、768項目を一つずつ入力する負担が減り、確認するところへ早く進める意味は大きいと感じます。確認が済んだら、少しゆっくりお茶でも飲みたいですね。
根拠を確かめる