Surya OCR Tutorial: Document AI for Text Detection, OCR, and Layout Analysis

# Tutorial Surya OCR: Document AI untuk Text Detection, OCR, dan Layout Analysis Surya adalah library Document AI open-source yang powerful untuk melakukan OCR (Optical Character Recognition), text d...

By Ruby Abdullah · · tutorial
SuryaOCRDocument AIComputer VisionPython

Surya OCR Tutorial: Document AI for Text Detection, OCR, and Layout Analysis

Surya is a powerful open-source Document AI library for OCR (Optical Character Recognition), text detection, layout analysis, reading order detection, and table recognition. Developed by Vik Paruchuri (creator of Marker), Surya supports over 90 languages and delivers accuracy that is highly competitive with commercial solutions like Google Cloud Vision.

In this tutorial, we will learn how to use Surya for various document AI tasks, from installation to advanced usage for processing complex documents.

Why Surya?

Before we begin, here are some reasons why Surya is worth considering:

  • Multi-language: Supports 90+ languages including CJK, Arabic, Indonesian, and many more
  • High accuracy: Benchmarks show accuracy comparable to or better than Google Cloud Vision across many languages
  • Open-source: GPL-3.0 license, free for non-commercial use
  • Feature-complete: OCR, text detection, layout analysis, table recognition, and reading order detection in one package
  • GPU acceleration: CUDA support for faster processing
  • Easy to use: Simple and intuitive API

Installation

System Requirements

  • Python 3.9 or newer
  • PyTorch (installed automatically)
  • NVIDIA GPU with CUDA (optional but highly recommended for performance)

Installation via pip

pip install surya-ocr

Installation from Source (for development)

git clone https://github.com/VikParuchuri/surya.git

cd surya

pip install -e .

Verify Installation

import surya

print(surya.version)

Additional Dependencies

To process PDF files, also install:

pip install pypdfium2

Basic Usage

1. Text Detection

Text detection is the first step in the OCR pipeline. Surya detects areas where text is present in an image.

from surya.detection import DetectionPredictor

from PIL import Image

Load image

image = Image.open("document.png")

Initialize detector

detector = DetectionPredictor()

Detect text

predictions = detector([image])

View detection results

for prediction in predictions:

for bbox in prediction.bboxes:

print(f"Bounding box: {bbox.bbox}")

print(f"Confidence: {bbox.confidence:.4f}")

print(f"Polygon: {bbox.polygon}")

print()

2. OCR (Optical Character Recognition)

After detecting text areas, we can perform OCR to extract text from images.

from surya.recognition import RecognitionPredictor

from surya.detection import DetectionPredictor

from surya.ocr import OCRPredictor

from PIL import Image

Load image

image = Image.open("document.png")

Initialize predictors

detpredictor = DetectionPredictor()

recpredictor = RecognitionPredictor()

ocrpredictor = OCRPredictor(detpredictor, recpredictor)

Run OCR

predictions = ocrpredictor([image])

Display results

for prediction in predictions:

for textline in prediction.textlines:

print(f"Text: {textline.text}")

print(f"Confidence: {textline.confidence:.4f}")

print(f"BBox: {textline.bbox}")

print()

3. Specifying Languages

Surya can detect languages automatically, but you can also specify languages explicitly for more accurate results:

from surya.recognition import RecognitionPredictor

from surya.detection import DetectionPredictor

from surya.ocr import OCRPredictor

from PIL import Image

image = Image.open("documentmixed.png")

detpredictor = DetectionPredictor()

recpredictor = RecognitionPredictor()

ocrpredictor = OCRPredictor(detpredictor, recpredictor)

Specify language: English

predictions = ocrpredictor([image], langs=[["en"]])

for prediction in predictions:

for textline in prediction.textlines:

print(f"{textline.text}")

Language codes follow the ISO 639 standard. Some examples: en (English), id (Indonesian), zh (Chinese), ja (Japanese), ar (Arabic).

Layout Analysis

Layout analysis identifies document structure such as paragraphs, headings, tables, figures, and other elements.

from surya.detection import DetectionPredictor

from surya.layout import LayoutPredictor

from PIL import Image

image = Image.open("document.png")

detpredictor = DetectionPredictor()

layoutpredictor = LayoutPredictor()

Analyze layout

predictions = layoutpredictor([image])

for prediction in predictions:

for layoutbox in prediction.bboxes:

print(f"Label: {layoutbox.label}")

print(f"BBox: {layoutbox.bbox}")

print(f"Confidence: {layoutbox.confidence:.4f}")

print()

Available labels in layout analysis include:

  • Text - Regular text paragraphs
  • Title - Titles or headings
  • Table - Tables
  • Figure - Images or diagrams
  • List - Lists
  • Caption - Image captions
  • Header - Page headers
  • Footer - Page footers
  • PageNumber - Page numbers

Table Recognition

Surya can detect and extract table structures from documents.

from surya.detection import DetectionPredictor

from surya.layout import LayoutPredictor

from surya.tablerec import TableRecPredictor

from PIL import Image

image = Image.open("documenttable.png")

detpredictor = DetectionPredictor()

layoutpredictor = LayoutPredictor()

tablepredictor = TableRecPredictor()

Detect layout first to find tables

layoutpredictions = layoutpredictor([image])

Get table areas

tableboxes = []

for pred in layoutpredictions:

for box in pred.bboxes:

if box.label == "Table":

tableboxes.append(box.bbox)

Recognize tables

if tableboxes:

tablepredictions = tablepredictor(

[image],

[tableboxes[0]] # Process first table

)

for prediction in tablepredictions:

for cell in prediction.cells:

print(f"Row: {cell.row}, Col: {cell.col}")

print(f"Text: {cell.text}")

print(f"BBox: {cell.bbox}")

print()

Reading Order Detection

Reading order detection determines the correct reading sequence for elements in a document, which is especially useful for multi-column documents.

from surya.detection import DetectionPredictor

from surya.layout import LayoutPredictor

from surya.ordering import OrderingPredictor

from PIL import Image

image = Image.open("documentmulticolumn.png")

detpredictor = DetectionPredictor()

layoutpredictor = LayoutPredictor()

orderingpredictor = OrderingPredictor()

Get layout

layoutpredictions = layoutpredictor([image])

Determine reading order

orderpredictions = orderingpredictor(

[image],

[layoutpredictions[0].bboxes]

)

for prediction in orderpredictions:

for item in prediction.bboxes:

print(f"Order: {item.position}, Label: {item.label}")

print(f"BBox: {item.bbox}")

print()

Advanced Usage

Batch Processing Multiple Documents

When you need to process many documents at once, use batch processing for efficiency:

from surya.recognition import RecognitionPredictor

from surya.detection import DetectionPredictor

from surya.ocr import OCRPredictor

from PIL import Image

import os

detpredictor = DetectionPredictor()

recpredictor = RecognitionPredictor()

ocrpredictor = OCRPredictor(detpredictor, recpredictor)

Load all images

imagedir = "documents/"

images = []

filenames = []

for filename in os.listdir(imagedir):

if filename.endswith((".png", ".jpg", ".jpeg")):

img = Image.open(os.path.join(imagedir, filename))

images.append(img)

filenames.append(filename)

Batch process (Surya optimizes GPU usage automatically)

predictions = ocrpredictor(images, langs=[["en"]] len(images))

Save results

for filename, prediction in zip(filenames, predictions):

print(f"\n=== {filename} ===")

fulltext = "\n".join([line.text for line in prediction.textlines])

print(fulltext)

# Save to file

outputpath = f"output/{filename}.txt"

with open(outputpath, "w", encoding="utf-8") as f:

f.write(fulltext)

Processing PDF Files

from surya.recognition import RecognitionPredictor

from surya.detection import DetectionPredictor

from surya.ocr import OCRPredictor

import pypdfium2 as pdfium

from PIL import Image

def pdftoimages(pdfpath, dpi=150):

"""Convert PDF pages to a list of PIL Images."""

pdf = pdfium.PdfDocument(pdfpath)

images = []

for i in range(len(pdf)):

page = pdf[i]

bitmap = page.render(scale=dpi / 72)

pilimage = bitmap.topil()

images.append(pilimage)

return images

Convert PDF to images

images = pdftoimages("report.pdf")

print(f"Total pages: {len(images)}")

Initialize OCR

detpredictor = DetectionPredictor()

recpredictor = RecognitionPredictor()

ocrpredictor = OCRPredictor(detpredictor, recpredictor)

OCR all pages

predictions = ocrpredictor(images, langs=[["en"]] len(images))

Combine results

fulldocument = []

for i, prediction in enumerate(predictions):

pagetext = "\n".join([line.text for line in prediction.textlines])

fulldocument.append(f"--- Page {i+1} ---\n{pagetext}")

result = "\n\n".join(fulldocument)

print(result)

Complete Pipeline: OCR + Layout + Table Recognition

Here is a complete pipeline that combines all of Surya's features:

from surya.recognition import RecognitionPredictor

from surya.detection import DetectionPredictor

from surya.layout import LayoutPredictor

from surya.tablerec import TableRecPredictor

from surya.ordering import OrderingPredictor

from surya.ocr import OCRPredictor

from PIL import Image

import json

def processdocument(imagepath, language="en"):

"""Complete pipeline for document processing."""

image = Image.open(imagepath)

# Initialize all predictors

detpredictor = DetectionPredictor()

recpredictor = RecognitionPredictor()

layoutpredictor = LayoutPredictor()

tablepredictor = TableRecPredictor()

orderingpredictor = OrderingPredictor()

ocrpredictor = OCRPredictor(detpredictor, recpredictor)

# Step 1: Layout analysis

layoutpreds = layoutpredictor([image])

layout = layoutpreds[0]

# Step 2: Reading order

orderpreds = orderingpredictor([image], [layout.bboxes])

order = orderpreds[0]

# Step 3: OCR

ocrpreds = ocrpredictor([image], langs=[[language]])

ocr = ocrpreds[0]

# Step 4: Table recognition (if tables exist)

tables = []

for box in layout.bboxes:

if box.label == "Table":

tablepred = tablepredictor([image], [box.bbox])

tables.append({

"bbox": box.bbox,

"cells": [

{

"row": cell.row,

"col": cell.col,

"text": cell.text,

"bbox": cell.bbox

}

for cell in tablepred[0].cells

]

})

# Compile results

result = {

"textlines": [

{

"text": line.text,

"confidence": line.confidence,

"bbox": line.bbox

}

for line in ocr.textlines

],

"layout": [

{

"label": box.label,

"bbox": box.bbox,

"confidence": box.confidence

}

for box in layout.bboxes

],

"readingorder": [

{

"position": item.position,

"label": item.label,

"bbox": item.bbox

}

for item in order.bboxes

],

"tables": tables

}

return result

Use the pipeline

result = processdocument("complexdocument.png", language="en")

Save results to JSON

with open("analysisresult.json", "w", encoding="utf-8") as f:

json.dump(result, f, ensureascii=False, indent=2)

Display text in correct reading order

print("=== Document Text (Reading Order) ===")

for line in result["textlines"]:

print(f"[{line['confidence']:.2f}] {line['text']}")

Visualizing Detection Results

You can visualize detection results using PIL or matplotlib:

from surya.detection import DetectionPredictor

from PIL import Image, ImageDraw, ImageFont

image = Image.open("document.png")

detector = DetectionPredictor()

predictions = detector([image])

Create a copy for visualization

visimage = image.copy()

draw = ImageDraw.Draw(visimage)

for prediction in predictions:

for bbox in prediction.bboxes:

coords = bbox.bbox # [x1, y1, x2, y2]

draw.rectangle(coords, outline="red", width=2)

visimage.save("detectionresult.png")

print("Visualization saved to detectionresult.png")

Using the CLI

Surya also provides a command-line interface for quick usage:

# OCR

suryaocr document.png --langs en

Text detection

suryadetect document.png

Layout analysis

suryalayout document.png

Table recognition

suryatable document.png

To process a folder of images:

suryaocr ./documentsfolder/ --langs en --resultsdir ./output/

Configuration and Optimization

GPU Settings

import os

Use a specific GPU

os.environ["CUDAVISIBLEDEVICES"] = "0"

Set batch sizes (adjust based on GPU VRAM)

os.environ["RECOGNITIONBATCHSIZE"] = "64"

os.environ["DETECTORBATCHSIZE"] = "16"

os.environ["LAYOUTBATCHSIZE"] = "16"

os.environ["ORDERBATCHSIZE"] = "16"

os.environ["TABLERECBATCHSIZE"] = "16"

Running on CPU

If you don't have a GPU, Surya can still run on CPU, though it will be slower:

import torch

Force CPU mode

device = "cpu"

Reduce batch sizes for CPU

os.environ["RECOGNITIONBATCHSIZE"] = "8"

os.environ["DETECTORBATCHSIZE"] = "4"

Performance Optimization Tips

  • Resize images: Oversized images will slow down processing. Resize to a reasonable resolution (e.g., 2000-3000px on the longest side)
  • def resizeimage(image, maxsize=3000):
    

    """Resize image while maintaining aspect ratio."""

    w, h = image.size

    if max(w, h) > maxsize:

    ratio = maxsize / max(w, h)

    neww = int(w ratio)

    newh = int(h ratio)

    return image.resize((neww, newh), Image.LANCZOS)

    return image

  • Batch processing: Always process images in batches rather than one at a time
  • Model caching: Models are cached automatically after the first download in ~/.cache/huggingface/
  • Memory management: For large documents, process page by page and clean up memory
  • import gc
    

    import torch

    def processlargepdf(pdfpath):

    images = pdftoimages(pdfpath)

    results = []

    for i, img in enumerate(images):

    pred = ocrpredictor([img], langs=[["en"]])

    results.append(pred[0])

    # Clean memory every 10 pages

    if (i + 1) % 10 == 0:

    gc.collect()

    if torch.cuda.isavailable():

    torch.cuda.emptycache()

    return results

    Best Practices

    1. Image Pre-processing

    Input quality significantly affects OCR results. Here are some pre-processing tips:

    from PIL import Image, ImageEnhance, ImageFilter
    
    

    def preprocessforocr(imagepath):

    """Pre-process image for better OCR results."""

    img = Image.open(imagepath)

    # Convert to RGB if needed

    if img.mode != "RGB":

    img = img.convert("RGB")

    # Increase contrast

    enhancer = ImageEnhance.Contrast(img)

    img = enhancer.enhance(1.5)

    # Increase sharpness

    enhancer = ImageEnhance.Sharpness(img)

    img = enhancer.enhance(2.0)

    return img

    2. Graceful Error Handling

    def safeocr(imagepath, language="en"):
    

    """OCR with proper error handling."""

    try:

    image = Image.open(imagepath)

    if image.mode not in ("RGB", "L"):

    image = image.convert("RGB")

    detpredictor = DetectionPredictor()

    recpredictor = RecognitionPredictor()

    ocrpredictor = OCRPredictor(detpredictor, recpredictor)

    predictions = ocrpredictor([image], langs=[[language]])

    if not predictions or not predictions[0].textlines:

    return {"success": False, "error": "No text detected"}

    textlines = [

    {

    "text": line.text,

    "confidence": line.confidence

    }

    for line in predictions[0].textlines

    ]

    return {

    "success": True,

    "text": "\n".join([l["text"] for l in textlines]),

    "lines": textlines,

    "avgconfidence": sum(l["confidence"] for l in textlines) / len(textlines)

    }

    except FileNotFoundError:

    return {"success": False, "error": f"File not found: {imagepath}"}

    except Exception as e:

    return {"success": False, "error": str(e)}

    3. Post-processing OCR Results

    import re
    
    

    def cleanocrtext(text):

    """Clean up OCR results."""

    # Remove excess spaces

    text = re.sub(r' +', ' ', text)

    # Fix line breaks

    text = re.sub(r'\n{3,}', '\n\n', text)

    # Remove non-printable characters

    text = re.sub(r'[^\S\n]+', ' ', text)

    # Strip each line

    lines = [line.strip() for line in text.split('\n')]

    text = '\n'.join(lines)

    return text.strip()

    4. Exporting Results to Various Formats

    import json
    

    import csv

    def exportresults(predictions, outputformat="json", outputpath="output"):

    """Export OCR results to various formats."""

    lines = []

    for pred in predictions:

    for line in pred.textlines:

    lines.append({

    "text": line.text,

    "confidence": line.confidence,

    "bbox": line.bbox

    })

    if outputformat == "json":

    with open(f"{outputpath}.json", "w", encoding="utf-8") as f:

    json.dump(lines, f, ensureascii=False, indent=2)

    elif outputformat == "csv":

    with open(f"{outputpath}.csv", "w", encoding="utf-8", newline="") as f:

    writer = csv.DictWriter(f, fieldnames=["text", "confidence", "bbox"])

    writer.writeheader()

    for line in lines:

    line["bbox"] = str(line["bbox"])

    writer.writerow(line)

    elif outputformat == "txt":

    with open(f"{outputpath}.txt", "w", encoding="utf-8") as f:

    for line in lines:

    f.write(f"{line['text']}\n")

    print(f"Results saved to {outputpath}.{outputformat}")

    Comparison with Alternatives

    | Feature | Surya | Tesseract | EasyOCR | PaddleOCR |

    |---------|-------|-----------|---------|-----------|

    | Languages Supported | 90+ | 100+ | 80+ | 80+ |

    | GPU Support | Yes | Limited | Yes | Yes |

    | Layout Analysis | Yes | Limited | No | Yes |

    | Table Recognition | Yes | No | No | Yes |

    | Reading Order | Yes | No | No | No |

    | Accuracy (general) | High | Medium | High | High |

    | Speed | Fast (GPU) | Fast (CPU) | Medium | Fast |

    | License | GPL-3.0 | Apache-2.0 | Apache-2.0 | Apache-2.0 |

    Conclusion

    Surya is a comprehensive and powerful Document AI solution. With multi-language OCR, text detection, layout analysis, table recognition, and reading order detection, Surya is a top choice for various document processing needs.

    Key takeaways:

  • Easy installation: Simply pip install surya-ocr
  • Multi-language: Supports 90+ languages including less common ones
  • Complete pipeline: From text detection to table extraction in one library
  • GPU optimization: Leverage GPU for significantly faster processing
  • Pre-processing matters: Input image quality greatly affects accuracy
  • Batch processing: Always use batch processing for efficiency
  • CLI available: For quick usage without coding
  • Surya is actively developed with continuous model improvements and new features. For commercial use, make sure to review the GPL-3.0 license details and available commercial licensing options.

    Related Articles

    PaddleOCR: High Accuracy Text Extraction from Images and Documents

    PaddleOCR: Ekstraksi Teks dari Gambar dan Dokumen dengan Akurasi Tinggi Halo temen-temen, kali ini kita bahas salah satu...

    Florence-2: Microsoft's Multi-Task Vision Foundation Model

    Florence-2: Model Vision Multi-Task dari Microsoft Daftar Isi Pendahuluan Prasyarat Instalasi Memuat Model Florence-2

    Supervision: Computer Vision Toolkit by Roboflow

    Supervision: Toolkit Computer Vision dari Roboflow Dalam proyek computer vision, setelah model mendeteksi objek, Anda ma...

    OpenCV + Deep Learning Tutorial: Modern Image Processing with Python

    OpenCV + Deep Learning: Tutorial Komprehensif Daftar Isi Pendahuluan Prasyarat Dasar-Dasar Preprocessing Gambar [T...