Menu OCR: Turning Restaurant Menu Photos into Structured JSON
How a six-stage pipeline handles multi-column layouts, ambiguous price-item pairing, and hierarchy extraction that off-the-shelf OCR cannot.
The problem
A menu photo is one of the least structured inputs you can hand an OCR system: no declared reading order, prices far from their items, hierarchy implied only by font size. Off-the-shelf OCR returns boxes and strings, not structure, and models trained on receipts (CORD-v2) don't transfer to menus.
The solution
Build the structure explicitly instead of hoping a model learns it. Cluster text x-coordinates into columns, assign prices globally with Hungarian matching, enforce the section-group-item hierarchy with an FSM decoded by Viterbi. Rules do the primary work; ML only steps in when rule confidence drops below 0.7.
Outcomes
- Cut per-image processing to roughly 330ms on GPU, a 3.5x speedup over CPU.
- Eliminated conflicting price assignments by replacing greedy matching with Hungarian-algorithm bipartite matching over vertical alignment, horizontal distance, and column consistency.
- Resolved multi-column reading order through DBSCAN clustering of text coordinates, with automatic identification of the price column.
+2 more in the write-up
Inside the write-up
- The pipeline
- Why the rules beat the models
- Performance