Tesseract and two columns: the default reads them right
99%
of the text in order with psm 3
psm 4 and 6 read straight across
Proofread two-column scans from 4 encyclopedias, printed 1879 to 1921:
| Setting | In order | Words found |
|---|---|---|
--psm 3, the default |
99.2% | 95.8% |
--psm 4 |
56.2% | 93.9% |
--psm 6 |
50.8% | 92.6% |
30 of 30 pages 90% or more in order at psm 3
0 of 30 at psm 6
psm 4 and 6 skip the column search, so each line runs across both columns:
| Setting | First line read |
|---|---|
| psm 6 |
he had to fly for his life in the disguise of a priest. In
the next | ecclesiastical. This double character is sufficient
to explain
|
| psm 3 |
he had to fly for his life in the disguise of a priest. In
the next
|
Sorting word boxes by row breaks it too
A common recipe takes the word boxes from
image_to_data and sorts them into rows by height. Lines
of both columns sit at the same height, so they merge.
51.1% in order, boxes sorted into rows
99.2% in Tesseract's own order
Row sorting suits one-column receipts, as in our receipt guide. Not columns.
Keep the default and Tesseract's order
Leave out --psm. This writes page.txt with psm 3:
tesseract page.png page
In Python, if you need the word boxes, group them by block, paragraph and line, in the order Tesseract gives them:
import pytesseract
from pytesseract import Output
d = pytesseract.image_to_data("page.png", output_type=Output.DICT)
lines = {}
for i, word in enumerate(d["text"]):
if word.strip():
key = (d["block_num"][i], d["par_num"][i], d["line_num"][i])
lines.setdefault(key, []).append(word)
text = "\n".join(" ".join(words) for words in lines.values())
print(text)
Cutting the page in half adds little
I also cut each page at the whitest strip near its middle and read each half. That kept 99.3% in order, against 99.2% for the whole page.
How I tested it
- Pages: en.wikisource scans whose text was proofread (level 3) or also checked by a second person (level 4). Picked by a seeded shuffle, not by me. Pages with tables, pictures or math were skipped.
- Encyclopaedia Britannica, 1911: 16 pages
- New International Encyclopaedia, 1st ed.: 9 pages
- American Cyclopaedia, 1879: 3 pages
- Collier's New Encyclopedia, 1921: 2 pages
- Each scan is the wiki's page image, 1,280 px or 1,920 px wide.
- Running heads, page numbers and footnotes are not in the proofread text, so extra text costs nothing.
- In order: proofread letters and digits found in the same order. Words found: proofread words found anywhere on the page.
-
--psm 1read the same as psm 3 on all 30 pages. - Tesseract 5.5.4 with the eng file Homebrew installs (tessdata_fast 4.1.0), one thread.
Our Actor reads them in order
Our Apify Actor does its own layout step after Tesseract. On these 30 scans:
99.2% in order, live build 0.1.65
50.7% in order, old build 0.1.44
Build 0.1.65, live since Nov 11, splits narrow columns first. It matches psm 3: 99.2%. Each number is a build's code, run on my Mac.
What I did not test
- Three or more columns, newspapers and magazines.
- Pages that mix columns with tables or pictures.
- Phone photos of curved book pages.
- Languages other than English. Hindi two-column pages are on this page.
- Windows and Linux. One Mac.
Sources
Two ways to skip the work
Run it yourself. Our Apify Actor turns scanned PDFs into Markdown, tables included.
Or send us the scan. Tack, our AI, does the job for $29, up to 50 pages. First page free.
Questions people ask
Can Tesseract read two columns?
Yes, at its default psm 3. On 30 proofread scans it kept 99.2% of the text in order. psm 4 and 6 read across the columns.
Why does Tesseract mix up my columns?
Usually psm 4 or 6, or code that sorts the word boxes into rows. Each kept about half the text in order on 30 scans.
Do I need to split columns before OCR?
Not on clean scans like these. Cutting each page at its gutter kept 99.3% in order, against 99.2% for psm 3 on the whole page.