---
title: "Tesseract PSM and OEM modes: Configuration and tuning in Python"
canonical_url: "https://www.nutrient.io/blog/tesseract-python-guide/"
md_url: "https://www.nutrient.io/blog/tesseract-python-guide.md"
last_updated: "2026-09-02T03:05:21.656Z"
description: "Configure Tesseract OCR in Python: PSM and OEM modes, character allowlists, image preprocessing, and performance tuning — with working code for each setting."
---

**TL;DR**

Tesseract’s accuracy and speed in Python depend on configuration: Page segmentation modes (PSM) control layout analysis, OCR engine modes (OEM) select the recognition engine, and character allowlists constrain output. This guide covers those settings, plus the preprocessing and performance tuning that go with them. For a beginner-focused walkthrough of basic extraction, see the [pytesseract tutorial](https://www.nutrient.io/blog/how-to-use-tesseract-ocr-in-python.md); for searchable PDFs without manual tuning, see the [Nutrient OCR API](https://www.nutrient.io/api/pdf-ocr-api/).

**Featured Content**

**Need production-ready OCR?**

Nutrient OCR API creates searchable PDFs from scanned images — no preprocessing required. 50 free credits/month.

[Try OCR API Free](https://www.nutrient.io/api/pdf-ocr-api/)

[Tesseract OCR](https://github.com/tesseract-ocr/tesseract) is the most widely used open source optical character recognition (OCR) engine, and most accuracy problems with it trace back to configuration — the wrong page segmentation mode, engine mode, or unprocessed input images. This guide focuses on those settings: PSM and OEM modes, character allowlists, preprocessing, and performance tuning. For a first-steps walkthrough of installing pytesseract and [extracting text from images](https://www.nutrient.io/blog/extract-text-from-pdf-using-python.md), start with the [pytesseract tutorial](https://www.nutrient.io/blog/how-to-use-tesseract-ocr-in-python.md) instead.

## What is Tesseract?

Tesseract is an open source OCR engine that extracts text from images, scanned documents, and PDFs. It’s originally developed by Hewlett-Packard (HP) and maintained by Google since 2006, and it recognizes more than 100 languages. It extracts text from scanned documents, images, and PDFs. With pytesseract, you can integrate Tesseract into Python projects to automate [data extraction](https://www.nutrient.io/blog/pdf-data-extraction-developer-guide.md).

## What is pytesseract?

pytesseract is a Python wrapper for the Tesseract OCR engine. It provides a Pythonic interface to Tesseract without requiring direct interaction with the C++ engine. For a hands-on tutorial with code examples, see our [pytesseract tutorial](https://www.nutrient.io/blog/how-to-use-tesseract-ocr-in-python.md).

| Feature            | Tesseract                             | pytesseract                                |
| ------------------ | ------------------------------------- | ------------------------------------------ |
| **Language**       | C++                                   | Python wrapper                             |
| **Usage**          | Command-line tool or C++ API          | Python `import pytesseract`                |
| **Installation**   | System package (brew, apt, installer) | `pip install pytesseract`                  |
| **Requires**       | Standalone installation               | Tesseract must be installed separately     |
| **Output formats** | Text, hOCR, TSV, PDF                  | String, dict, DataFrame, bytes             |
| **Best for**       | Direct CLI usage, C++ integration     | Python scripts, automation, data pipelines |

## Prerequisites

Make sure you have the following installed:

- **Installation of Python environment** — Install Python on your system. You can download it from the [official Python website](https://www.python.org/downloads/).

- **Pip package manager** — If you don’t have pip installed, follow these steps:
  - **Windows** — Pip comes bundled with Python. If it’s missing, [download `get-pip.py`](https://bootstrap.pypa.io/get-pip.py) and run:

```bash

python get-pip.py

```

- **macOS/Linux** — Open a terminal and run:

```bash

sudo apt install python3-pip  # For Debian-based Linux.

sudo dnf install python3-pip  # For Fedora-based Linux.

brew install python            # For macOS (via Homebrew).

```

- **OpenCV library** — This is required for image preprocessing tasks such as grayscale conversion, thresholding, and noise removal. Install it using:

```sh

pip install opencv-python

```

- **NumPy library** — Used for handling numerical operations on image data. Install it using:

```sh

pip install numpy

```

- **Pillow** — This is a fork of the Python Imaging Library (PIL), which you’ll need to open image files:

```bash

pip install Pillow

```

## Setting up Tesseract with Python

The setup process covers installing the Tesseract engine and the pytesseract Python wrapper.

### Installation

Install both the Tesseract OCR engine and the [`pytesseract`](https://pypi.org/project/pytesseract/) library.

#### Installing Tesseract

- **Windows** — Download the Windows installer from [Tesseract’s official repository](https://github.com/tesseract-ocr/tesseract) and follow the installation instructions provided.

- **macOS** — Install Tesseract using Homebrew, a package manager for macOS, by executing the following command:

```bash

brew install tesseract

```

- **Linux** — Most Linux distributions include Tesseract in their package repositories. So you can install it using APT with the following command:

```bash

sudo apt install tesseract-ocr

```

- For Fedora-based distributions, use:

```bash

sudo dnf install tesseract

```

After installation, make sure Tesseract is available in your system’s `PATH`, or provide the direct path in your code.

#### Installing pytesseract

Once Tesseract is installed on your system, install the [`pytesseract`](https://pypi.org/project/pytesseract/) library using Python’s package manager, `pip`:

```sh

pip install pytesseract

```

### Verifying installation

To ensure Tesseract has been installed correctly, open a terminal or command prompt and run the following command:

```bash

tesseract --version

```

If the installation was successful, the terminal will display the version number of Tesseract, along with other relevant details.

## How to use Tesseract with Python

To use Tesseract with Python, install pytesseract, open an image with Pillow, and call `pytesseract.image_to_string()` to return the recognized text as a string. The example below demonstrates this with a sample image containing printed text.![Sample image for OCR using Tesseract](@/assets/images/blog/2025/tesseract-python-guide/sample-image.png)

Use this code to get started with OCR using Tesseract and Python:

```python

from PIL import Image
import pytesseract

# Open an image file.

image = Image.open('example.png')

# Use pytesseract to do OCR on the image.

text = pytesseract.image_to_string(image)

# Print the extracted text.

print(text)

```

In this example:

- Open an image file using Pillow.

- Pass the image to `pytesseract.image_to_string()` to extract the text.![Terminal output showing the text Tesseract extracted from the sample image](@/assets/images/blog/2025/tesseract-python-guide/terminal.png)

## The image_to_string parameters

Most of Tesseract’s behavior in Python is controlled through the arguments to `pytesseract.image_to_string()`. The parameters below are the ones that matter most for accuracy and control.

| Parameter     | What it does                                                                                       |
| ------------- | -------------------------------------------------------------------------------------------------- |
| `image`       | Input to OCR. Accepts a Pillow `Image`, a NumPy array (e.g. an OpenCV `cv2` image), or a file path |
| `lang`        | Language(s) to recognize, e.g. `"eng"` or `"eng+deu"` for several at once. Defaults to English     |
| `config`      | Custom Tesseract flags as a string — `--psm`, `--oem`, and `-c` key-value options (covered below)  |
| `timeout`     | Maximum seconds to wait before raising `RuntimeError`. `0` (the default) means no limit            |
| `output_type` | Return format: `Output.STRING` (the default), `Output.DICT`, or `Output.BYTES`                     |

A single call can combine several of these:

```python

import pytesseract

text = pytesseract.image_to_string(
    image,
    lang="eng",
    config="--psm 6 --oem 1",
    timeout=30,
)

```

Because `image` accepts a NumPy array directly, an OpenCV image from `cv2.imread()` can be passed to `image_to_string()` without converting it back to a Pillow image first. The `config` string is where page segmentation modes, engine modes, and character allowlists are set — see the configuration reference below.

## Understanding OpenCV (cv2)

Image preprocessing in this guide uses [OpenCV](https://opencv.org/), an open source computer vision library for Python. The `cv2` module provides functions to manipulate and enhance images before passing them to Tesseract.

### Key features of OpenCV (cv2)

- **Reading and writing images** — OpenCV enables loading, displaying, and saving images using functions like `cv2.imread()` and `cv2.imwrite()`.

- **Image preprocessing** — It provides various image enhancement techniques, such as grayscale conversion, thresholding, noise removal, and edge detection.

- **Geometric transformations** — Functions like rotation, resizing, and deskewing help in improving OCR accuracy.

- **Object and text detection** — OpenCV supports contour detection, which is useful for extracting regions of interest in images containing text.

## Image preprocessing for better OCR accuracy

Tesseract accuracy depends on input image quality. Preprocessing the image before OCR reduces character misreads. For a complete walkthrough of preprocessing pipelines, see our guide on [building a document scanner with OCR in Python](https://www.nutrient.io/blog/creating-a-document-scanner-with-ocr-in-python.md).

### Grayscale conversion

Converting an image to grayscale reduces the complexity of the image by eliminating unnecessary color information, making it easier for Tesseract to focus on text detection:

```python

import cv2
image = cv2.imread('image.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imwrite('gray_image.png', gray)

```

| Original image                                                                                                                                                            | Grayscale image                                                                                                                                                                    |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|![A tiger walks on a forest path, surrounded by trees and warm light. Its black and orange stripes stand out.](@/assets/images/blog/2025/tesseract-python-guide/lion.jpg) |![A tiger walks on a forest path in black and white. The stripes and details are clear, but the colors are gone.](@/assets/images/blog/2025/tesseract-python-guide/gray_image.png) |

### Thresholding

[Thresholding](https://docs.opencv.org/4.x/d7/d4d/tutorial_py_thresholding.html) is a technique that helps separate text from a background by converting an image into a binary format where pixels are either black or white:

```python

thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cv2.imwrite('thresholded_image.png', thresh)

```

The code above applies [Otsu’s thresholding](https://en.wikipedia.org/wiki/Otsu%27s_method) to a grayscale image, converting it into a binary image where pixels are either black or white. The thresholded result is then saved as `thresholded_image.png`.

| Original image                                                                                                                                                                                           | Thresholded image                                                                                                                                                                                                           |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|![A simple image with clear, black text on a white background. The text should read ‘The quick brown fox jumps over the lazy dog.’](@/assets/images/blog/2025/tesseract-python-guide/original_image.png) |![A black-and-white thresholded image with clear, black text on a white background. The text reads: ‘The quick brown fox jumps over the lazy dog.’](@/assets/images/blog/2025/tesseract-python-guide/thresholded_image.png) |

### Noise removal

Noise, such as small speckles or distortions, can interfere with OCR. The following code, broken down into steps, applies image processing techniques to remove noise and improve text clarity.

#### Step 1

Load and convert to grayscale:

```python

import cv2
import numpy as np

image = cv2.imread('fax.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imwrite('gray_image.png', gray)

```

- Loads the image and converts it to grayscale for simpler processing.

#### Step 2

Apply a bilateral filter:

```python

denoised = cv2.bilateralFilter(gray, 9, 75, 75)

```

- Reduces noise while preserving edges using a bilateral filter.

#### Step 3

Sharpen the image:

```python

kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
sharpened = cv2.filter2D(denoised, -1, kernel)

```

- Sharpens the image by enhancing edges with a kernel filter.

#### Step 4

Save the processed image:

```python

cv2.imwrite('denoised_image.png', sharpened)

```

- Saves the final sharpened and denoised image.

#### Why does this matter for OCR?

- **Reduces noise**, making text more readable.

- **Preserves important details** while removing unwanted distortions.

- **Improves OCR accuracy**, as clearer text leads to better recognition.

| Original image                                                                                                                                                                  | Denoised image                                                                                                                                                                                                             |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|![‘A scanned fax from 21 May 1998, with typewritten text, faded black ink, and a yellowed background.’](@/assets/images/blog/2025/tesseract-python-guide/denoised_original.jpg) |![A cleaned-up version of a scanned fax from 21 May 1998, with sharper typewritten text, improved contrast, and reduced noise on a light background.](@/assets/images/blog/2025/tesseract-python-guide/denoised_image.png) |

### Deskewing for better OCR accuracy

After applying thresholding, some scanned documents may have tilted text, affecting OCR accuracy. Deskewing corrects this misalignment, ensuring Tesseract processes the text properly:

```python

coords = np.column_stack(np.where(thresh > 0))  # Find non-zero pixel coordinates.

angle = cv2.minAreaRect(coords)[-1]  # Calculate the skew angle.

# Adjust the angle for the correct rotation.

if angle < -45:
    angle = -(90 + angle)
else:
    angle = -angle

# Rotate the image to correct the skew.

(h, w) = thresh.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
deskewed = cv2.warpAffine(thresh, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

cv2.imwrite('deskewed_image.png', deskewed)

```

By detecting the text angle and rotating the image, this method straightens skewed text, improving OCR results.

| Original image                                                                                                                                                                                            | Deskewed image                                                                                                                                                                                                                                           |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|![‘A simple image with clear, black text on a white background. The text should read ‘The quick brown fox jumps over the lazy dog.’](@/assets/images/blog/2025/tesseract-python-guide/original_image.png) |![A deskewed image with clear, black text on a white background. The text reads, ‘The quick brown fox jumps over the lazy dog.’ The alignment is corrected for better readability.](@/assets/images/blog/2025/tesseract-python-guide/deskewed_image.png) |

## Multilingual text recognition

Tesseract supports more than 100 languages, which lets you extract text in different scripts and dialects. To enable multilingual OCR, the required language data files must be correctly installed and configured.

For Data Extraction API workflows, see the [multilingual extraction guide](https://www.nutrient.io/guides/dws-data-extraction/parsing/multilingual-extraction.md) and [supported languages](https://www.nutrient.io/guides/dws-data-extraction/supported-languages.md).

### Language data files

Tesseract provides language data files that can be downloaded from [Tesseract’s language repository](https://github.com/tesseract-ocr/tessdata) and placed in the `tessdata` directory of the Tesseract installation.

### Configuring language in pytesseract

To instruct Tesseract to recognize multiple languages in an image, specify the desired languages in the `lang` parameter of `pytesseract.image_to_string()`:

```python

import pytesseract
text = pytesseract.image_to_string(image, lang='eng+fra')
print(text)

```

## Tesseract configuration: PSM, OEM, and character allowlists

Most accuracy problems come down to three settings, all passed through the `config` string: the page segmentation mode (how the page layout is analyzed), the OCR engine mode (which recognition engine runs), and character allowlists (which characters are allowed in the output).

### Page segmentation modes (PSM)

Tesseract offers various [page segmentation modes (PSM)](https://www.kaggle.com/code/dhorvay/pytesseract-page-segmentation-modes-psms) that determine how text is segmented within an image. For example:

```python

text = pytesseract.image_to_string(image, config='--psm 6')

```

Common PSM modes include:

- **0** — Orientation and script detection (OSD) only, no OCR.

- **3** — Fully automatic page segmentation with no OSD (the default).

- **4** — A single column of text of variable sizes.

- **6** — A single uniform block of text.

- **7** — A single text line.

- **10** — A single character.

- **11** — Sparse text: Find as much text as possible in no particular order.

If OCR output is missing text or scrambled, the PSM is the first thing to change. Use `6` for a clean block of text, `3` for full-page documents with mixed layout, and `11` for scattered text such as labels or receipts.

### OCR engine modes (OEM)

Tesseract supports multiple OCR engine modes (OEM), which define the underlying text recognition approach:

```python

text = pytesseract.image_to_string(image, config='--oem 1')

```

Common OEM modes include:

- **0** — Uses the legacy OCR engine only.

- **1** — Uses the long short-term memory (LSTM)-based OCR engine.

- **3** — Uses a combination of the legacy and LSTM engines.

On modern Tesseract (v4 and later), the default LSTM engine (`1`) is almost always the right choice. The legacy modes exist mainly for compatibility with older training data.

### Character allowlists (tessedit_char_whitelist)

To improve accuracy, Tesseract allows restricting recognition to specific characters:

```python

custom_config = r'--psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
text = pytesseract.image_to_string(image, config=custom_config)

```

To exclude characters instead of allowing them, use `tessedit_char_blacklist` the same way. Constraining the character set is most useful on structured fields such as IDs, serial numbers, and monetary amounts, where the expected characters are known in advance.

## Extracting text from PDF

Tesseract can extract text from PDFs by converting them to images. Ensure you have [Poppler](https://poppler.freedesktop.org/) installed first. For alternative Python approaches to [PDF text extraction](https://www.nutrient.io/blog/pdf-text-extraction/), see our dedicated guides.

For a Linux CLI workflow that wraps Tesseract with OCRmyPDF, see [PDF OCR on the Linux command line](https://www.nutrient.io/blog/how-to-ocr-pdfs-in-linux.md).

### Installing Poppler

First, install Poppler:

- **macOS** — `brew install poppler`

- **Ubuntu** — `sudo apt-get install poppler-utils`

- **Windows** — [Download Poppler](https://github.com/oschwartz10612/poppler-windows/releases/) and add it to your `PATH`.

Then, use this code:

```python

import pytesseract
from pdf2image import convert_from_path

# Convert PDF to images.

images = convert_from_path('example.pdf')

# Extract text from the first page.

text = pytesseract.image_to_string(images[0])

print(text)

```

You’ll need to install pdf2image using:

```bash

pip install pdf2image

```

For extracting text from PDFs without OCR (when text is already selectable), see [how to extract text from a PDF using PyMuPDF](https://www.nutrient.io/blog/extract-text-from-pdf-pymupdf/).

## Tesseract vs. commercial OCR solutions

Choosing between Tesseract and a commercial OCR solution depends on your use case, volume, and accuracy requirements.

| Feature                 | Tesseract (open source)                      | Nutrient OCR API (commercial)           |
| ----------------------- | -------------------------------------------- | --------------------------------------- |
| **Cost**                | Free (Apache 2.0)                            | 50 free credits/month, then paid        |
| **Installation**        | Local engine required                        | Cloud API — no installation             |
| **Preprocessing**       | Manual (grayscale, threshold, deskew)        | Automatic — built-in preprocessing      |
| **Output format**       | Plain text, hOCR, TSV                        | Searchable PDF with embedded text layer |
| **Languages**           | 100+ (install language packs)                | 80+ languages built in                  |
| **Batch processing**    | Build your own pipeline                      | Single API call for multiple pages      |
| **PDF support**         | Requires pdf2image conversion                | Native PDF input and output             |
| **Layout preservation** | Limited                                      | Retains tables, columns, and formatting |
| **Accuracy**            | Good with proper preprocessing               | Consistent without manual tuning        |
| **Best for**            | Prototyping, local processing, customization | Production workflows, searchable PDFs   |

For production OCR that outputs searchable PDFs, see the [Nutrient OCR API](https://www.nutrient.io/api/pdf-ocr-api/). You can also [OCR PDFs directly using the API](https://www.nutrient.io/blog/how-to-ocr-pdf-api/) in JavaScript, Python, PHP, or Java.

## Performance optimization tips

When processing large batches of images or working with high-resolution scans, performance becomes critical. These tips help you get the most out of Tesseract.

1. **Use `tessdata_fast` models** — The [tessdata_fast](https://github.com/tesseract-ocr/tessdata_fast) models are smaller and faster than default models with minimal accuracy loss. Swap your `tessdata` directory to use the fast variants for production workloads.

2. **Resize images appropriately** — Tesseract works best with text at 300 dots per inch (DPI). Images that are too large waste processing time; images that are too small reduce accuracy. Resize to an optimal range before OCR.

3. **Limit the recognition region** — If you only need text from a specific area, crop the image before passing it to Tesseract. This reduces processing time significantly.

4. **Use the right PSM mode** — Choosing the correct page segmentation mode avoids unnecessary layout analysis. For single text blocks, `--psm 6` is faster than the default `--psm 3`.

5. **Process pages in parallel** — For multipage documents, use Python’s `concurrent.futures` to OCR pages in parallel:

```python

from concurrent.futures import ThreadPoolExecutor
import pytesseract
from pdf2image import convert_from_path

images = convert_from_path('document.pdf')

def ocr_page(image):
    return pytesseract.image_to_string(image)

with ThreadPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(ocr_page, images))

full_text = '\n'.join(results)

```

6. **Cache preprocessed images** — If you’re iterating on OCR settings, save preprocessed images to disk so you don’t repeat expensive preprocessing steps.

For high-volume document processing, consider [automated OCR workflows](https://www.nutrient.io/blog/how-to-create-automated-ocr-workflows-from-images/) or the [Nutrient OCR API](https://www.nutrient.io/api/pdf-ocr-api/), which handles preprocessing and optimization automatically.

## Common errors and troubleshooting

Most issues fall into four categories: the Tesseract engine can’t be found, output is empty or incorrect, the Python library won’t import, or processing is too slow.

### TesseractNotFoundError

This means Python can’t locate the Tesseract executable. Fix it by setting the path explicitly:

```python

pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'  # Windows.

# pytesseract.pytesseract.tesseract_cmd = '/usr/local/bin/tesseract'  # macOS/Linux.

```

### Empty or garbled output

If Tesseract returns empty strings or incorrect characters, check these common causes:

- **Image quality** — Apply grayscale conversion, thresholding, and noise removal before OCR.

- **Wrong PSM mode** — Try `--psm 6` for blocks of text, `--psm 7` for single lines.

- **Wrong language** — Specify the correct language with `lang='eng'` or install additional language packs.

- **Low resolution** — Upscale images to at least 300 DPI for reliable recognition.

### Import errors

If `import pytesseract` fails, ensure the library is installed in the correct Python environment. See the [troubleshooting guide in our pytesseract tutorial](https://www.nutrient.io/blog/how-to-use-tesseract-ocr-in-python.md#why-pytesseract-fails-to-recognize-or-import-text) for detailed solutions.

### Slow processing

If OCR is taking too long, reduce image resolution, use `tessdata_fast` models, limit the recognition region, or switch to parallel processing as described in the performance optimization section above.

## Common OCR challenges

The most frequent sources of reduced accuracy are poor image quality, unusual fonts, and non-standard characters.

### Low-quality images

For blurry or noisy images, apply preprocessing before OCR:

- Denoising — `cv2.fastNlMeansDenoising()`

- Binarization — `cv2.threshold()`

### Text in uncommon fonts

Tesseract may struggle with decorative or distorted fonts. Try training Tesseract on custom font data, or apply additional image processing to increase contrast and clarity.

### Non-standard characters

If Tesseract misrecognizes special characters or symbols, verify that you have the correct language data installed and try adjusting the OEM or PSM settings.

## Nutrient OCR solutions and features

Nutrient offers [OCR](https://www.nutrient.io/sdk/ocr/) across multiple platforms, extracting text from scanned PDFs and images to make [documents searchable](https://www.nutrient.io/blog/document-searchability-best-practices/) and editable.

### Nutrient products supporting OCR

- [Nutrient OCR API](https://www.nutrient.io/api/pdf-ocr-api/) — Cloud-based OCR with searchable PDF output. No local engine required.

- [Web SDK](https://www.nutrient.io/guides/web/ocr.md) — OCR via Document Engine in server-backed mode.

- [iOS SDK](https://www.nutrient.io/guides/ios/ocr/overview.md) and [Android SDK](https://www.nutrient.io/guides/android/ocr/overview.md) — On-device text recognition for mobile apps.

- [.NET SDK](https://www.nutrient.io/guides/dotnet/ocr.md) — OCR for Windows applications.

- [Java SDK](https://www.nutrient.io/guides/java.md) — OCR for Java applications. See [how to OCR images and PDFs using Java](https://www.nutrient.io/blog/how-to-ocr-images-and-pdfs-using-java/).

- [Document Converter](https://www.nutrient.io/low-code/document-converter/) — OCR for SharePoint and server-based conversions (from version 7.1).

Nutrient also supports OCR on Mac Catalyst, React Native, and Flutter.

### Key differentiators

- **Searchable PDFs** — Converts scanned documents into searchable, selectable text with the original layout preserved.

- **Built-in preprocessing** — No manual grayscale/threshold/deskew steps required.

- **Batch processing** — Single API call for multipage documents. See our guide on [automated PDF OCR workflows](https://www.nutrient.io/blog/how-to-create-automated-pdf-ocr-workflows/).

OCR may require an additional license component. For more details, visit [Nutrient OCR solutions](https://www.nutrient.io/sdk/ocr/) or [contact Sales](https://www.nutrient.io/contact-sales/?=sdk).

## Conclusion

Tesseract with Python is a free, customizable option for text recognition — from [digitizing medical records](https://www.nutrient.io/blog/medical-records-digitization-with-ocr/) to automating data entry. Image preprocessing and the right PSM/OEM settings make the biggest difference in accuracy. For production OCR that outputs searchable PDFs without manual preprocessing, see the [Nutrient OCR API](https://www.nutrient.io/api/pdf-ocr-api/) or [contact Sales](https://www.nutrient.io/contact-sales/?=sdk).

**Related Python guides**

- [pytesseract tutorial: Extract text from images](https://www.nutrient.io/blog/how-to-use-tesseract-ocr-in-python.md)

- [Watermark PDFs with Python](https://www.nutrient.io/blog/how-to-watermark-a-pdf-using-python/)

- [Generate PDF invoices with Python](https://www.nutrient.io/blog/how-to-generate-pdf-invoices-from-html-in-python/)

- [Convert HTML to PDF with Python](https://www.nutrient.io/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-python.md)

- [Extract text from PDF with Python](https://www.nutrient.io/blog/extract-text-from-pdf-using-python.md)

- [Extract text from PDF using PyMuPDF](https://www.nutrient.io/blog/extract-text-from-pdf-pymupdf/)

- [Top 10 Python PDF generator libraries](https://www.nutrient.io/blog/top-10-ways-to-generate-pdfs-in-python.md)

**OCR and document processing**

- [Build a document scanner with OCR in Python](https://www.nutrient.io/blog/creating-a-document-scanner-with-ocr-in-python.md)

- [OCR images and PDFs in Java](https://www.nutrient.io/blog/how-to-ocr-images-and-pdfs-using-java/)

- [OCR images and PDFs in C#](https://www.nutrient.io/blog/how-to-ocr-images-and-pdfs-using-csharp/)

- [Automated OCR workflows from images](https://www.nutrient.io/blog/how-to-create-automated-ocr-workflows-from-images/)

- [Automated PDF OCR workflows](https://www.nutrient.io/blog/how-to-create-automated-pdf-ocr-workflows/)

- [Barcode OCR](https://www.nutrient.io/blog/barcode-ocr/)

- [Document searchability best practices](https://www.nutrient.io/blog/document-searchability-best-practices/)

- [AI-powered redaction](https://www.nutrient.io/blog/how-ai-powered-redaction-can-transform-legal-discovery/)

- [Medical records digitization with OCR](https://www.nutrient.io/blog/medical-records-digitization-with-ocr/)

## FAQ

#### What is the difference between PSM and OEM in Tesseract?

PSM (page segmentation mode) controls how Tesseract analyzes page layout — whether it treats an image as a full page, a single block, a single line, or sparse text. OEM (OCR engine mode) selects which recognition engine runs: the legacy engine, the LSTM neural engine, or both. Both are set through the `config` string — for example, `--psm 6 --oem 1`.

#### Which Tesseract PSM mode should I use?

Use `--psm 6` for a single uniform block of text, `--psm 3` (the default) for full-page documents with mixed layout, and `--psm 11` for sparse or scattered text such as labels and receipts. If OCR output is missing text or scrambled, changing the PSM is usually the first fix.

#### What are the best practices for enhancing Tesseract OCR accuracy?

Start with high-quality images and apply preprocessing: grayscale conversion, thresholding, and noise removal. Then tune the page segmentation mode (PSM) and OCR engine mode (OEM) to match your document layout. These two steps account for most accuracy gains.

#### How do I OCR a PDF with pytesseract?

pytesseract doesn’t support PDFs directly. Convert PDF pages to images first using the `pdf2image` library: `images = convert_from_path('file.pdf')`. Then run `pytesseract.image_to_string()` on each image. You also need Poppler installed on your system. For native PDF OCR without this extra step, use the [Nutrient OCR API](https://www.nutrient.io/api/pdf-ocr-api/).

#### How do I fix <code>TesseractNotFoundError</code>?

This error means Python can’t find the Tesseract executable. Either add Tesseract to your system PATH, or set the path explicitly: `pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'` on Windows, or `pytesseract.pytesseract.tesseract_cmd = '/usr/local/bin/tesseract'` on macOS/Linux.

#### How do I restrict Tesseract to recognize only specific characters?

Pass a character allowlist through the `config` string with the `-c tessedit_char_whitelist=` option — for example, `--psm 6 -c tessedit_char_whitelist=0123456789` to read digits only. Use `tessedit_char_blacklist` to exclude characters instead. Constraining the character set improves accuracy on structured fields such as IDs, serial numbers, and amounts.

#### How do I set a timeout or pass a NumPy array to <code>image_to_string</code>?

Set the `timeout` parameter in seconds to stop OCR on a slow image — `pytesseract.image_to_string(image, timeout=30)` raises `RuntimeError` if it exceeds the limit. `image_to_string()` also accepts a NumPy array directly. So an OpenCV image from `cv2.imread()` can be passed without converting it back to a Pillow image first.

#### How does Nutrient enhance OCR workflows in modern applications?

Nutrient adds batch processing, built-in preprocessing, and multiplatform support on top of what Tesseract offers. The API produces searchable PDFs directly, which removes the need to build your own post-processing pipeline.

#### Which Nutrient product is best for web-based OCR integration?

Nutrient Web SDK handles OCR through Document Engine in server-backed mode. It extracts text from documents and images delivered via the browser and returns searchable PDF output.

#### How does the Nutrient OCR API handle scanned documents?

The Nutrient OCR API accepts PDF or image input via a REST call and returns a searchable PDF with an embedded text layer. It handles preprocessing automatically. So you don’t need to manage grayscale conversion, thresholding, or deskewing yourself.

#### Can Tesseract handle handwritten text?

Tesseract has limited support for handwriting recognition out of the box. While it can recognize clearly printed handwriting, it struggles with cursive or informal handwriting. For better results with handwritten text, consider training Tesseract on a custom dataset of handwriting samples, or use a commercial OCR solution with built-in handwriting support.

#### What image formats does pytesseract support?

pytesseract supports all image formats that Pillow (PIL) can open, including PNG, JPEG, TIFF, BMP, GIF, and WebP. For best OCR results, use lossless formats like PNG or TIFF. JPEG compression artifacts can reduce accuracy, especially with small or low-contrast text.
---

## Related pages

- [The business case for accessibility: Five ways it drives enterprise value](/blog/5-ways-accessibility-drives-enterprise-value.md)
- [Accessibility Untangled Why It Matters Guide](/blog/accessibility-untangled-why-it-matters-guide.md)
- [Advanced Techniques For React Native Ui Components](/blog/advanced-techniques-for-react-native-ui-components.md)
- [`vector_store` holds your indexed documents (see the multimodal RAG post](/blog/agentic-rag.md)
- [How to build an AI agent for contract redlining against a compliance playbook](/blog/ai-contract-redlining-compliance-playbook.md)
- [Ai Document Automation Extraction To Action](/blog/ai-document-automation-extraction-to-action.md)
- [Ai Legal Assistant Document Authoring](/blog/ai-legal-assistant-document-authoring.md)
- [Amazon Textract Alternatives](/blog/amazon-textract-alternatives.md)
- [Start (clears any prior buffer), navigate the document, then stop into a file.](/blog/android-faster-pdf-rendering.md)
- [Android Pdf Out Of Memory Handling](/blog/android-pdf-out-of-memory-handling.md)
- [Angular File Viewer Pdf Image Office Files](/blog/angular-file-viewer-pdf-image-office-files.md)
- [Approval Workflow Software](/blog/approval-workflow-software.md)
- [Approvals Matrix](/blog/approvals-matrix.md)
- [Auto Tagging And Document Accessibility In Dotnet Sdk](/blog/auto-tagging-and-document-accessibility-in-dotnet-sdk.md)
- [Simple PII redaction.](/blog/automated-pii-removal.md)
- [Best Ai Document Workflow Platforms](/blog/best-ai-document-workflow-platforms.md)
- [Best Document Ai Platforms](/blog/best-document-ai-platforms.md)
- [Best Document Classification Platforms](/blog/best-document-classification-platforms.md)
- [Best document parser for RAG: LlamaParse vs. Unstructured vs. Reducto vs. Nutrient](/blog/best-document-parser-llamaparse-unstructured-reducto.md)
- [Best Document Parsing Apis](/blog/best-document-parsing-apis.md)
- [Best Document Viewers](/blog/best-document-viewers.md)
- [Best Multilingual Ocr Software](/blog/best-multilingual-ocr-software.md)
- [Best Secure Document Collaboration Platforms](/blog/best-secure-document-collaboration-platforms.md)
- [Bpm Guide](/blog/bpm-guide.md)
- [Bpm Tools](/blog/bpm-tools.md)
- [Build Vs Buy Document Extraction](/blog/build-vs-buy-document-extraction.md)
- [Business Automation](/blog/business-automation.md)
- [Capex Vs Opex](/blog/capex-vs-opex.md)
- [The CEO’s AI playbook: Why decision architecture beats model selection](/blog/ceo-ai-playbook-decision-architecture.md)
- [1. Extract and chunk the PDF.](/blog/chat-with-pdf.md)
- [Complete Guide To Pdfjs](/blog/complete-guide-to-pdfjs.md)
- [Construction Document Data Extraction](/blog/construction-document-data-extraction.md)
- [Convert One Drive Files To Pdf In Sharepoint](/blog/convert-one-drive-files-to-pdf-in-sharepoint.md)
- [Create And Edit Pdfs In Flutter](/blog/create-and-edit-pdfs-in-flutter.md)
- [Create Pdfs With React](/blog/create-pdfs-with-react.md)
- [Creating A Document Scanner With Ocr In Python](/blog/creating-a-document-scanner-with-ocr-in-python.md)
- [Creating And Filling Pdf Forms Programmatically In Javascript](/blog/creating-and-filling-pdf-forms-programmatically-in-javascript.md)
- [The CTO’s AI playbook: Why accountability architecture beats orchestration](/blog/cto-ai-playbook-accountability-architecture.md)
- [Digital Signatures](/blog/digital-signatures.md)
- [Digital Workflow Automation](/blog/digital-workflow-automation.md)
- [Document Ai Vs Ocr](/blog/document-ai-vs-ocr.md)
- [Document Extraction Confidence Scores](/blog/document-extraction-confidence-scores.md)
- [Document Viewer](/blog/document-viewer.md)
- [Document Watermarking](/blog/document-watermarking.md)
- [Emerging threats: Your logging system may be an agentic threat vector](/blog/emerging-threats-your-logging-system.md)
- [Extend Alternatives](/blog/extend-alternatives.md)
- [Extract Patient Data On Premises](/blog/extract-patient-data-on-premises.md)
- [app.py](/blog/extract-text-from-pdf-using-python.md)
- [Fillable Pdf](/blog/fillable-pdf.md)
- [How To Add Digital Signature To Pdf Using React](/blog/how-to-add-digital-signature-to-pdf-using-react.md)
- [How To Build A Dotnet Maui Pdf Viewer](/blog/how-to-build-a-dotnet-maui-pdf-viewer.md)
- [How To Build A Flutter Pdf Viewer](/blog/how-to-build-a-flutter-pdf-viewer.md)
- [or](/blog/how-to-build-a-javascript-pdf-viewer-with-pdfjs.md)
- [How To Build A Javascript Pdf Viewer](/blog/how-to-build-a-javascript-pdf-viewer.md)
- [or](/blog/how-to-build-a-nextjs-pdf-viewer.md)
- [How To Build A Powerpoint Viewer Using Javascript](/blog/how-to-build-a-powerpoint-viewer-using-javascript.md)
- [Using Yarn](/blog/how-to-build-a-react-excel-viewer.md)
- [How To Build A React Native Pdf Viewer](/blog/how-to-build-a-react-native-pdf-viewer.md)
- [How To Build A React Powerpoint Viewer](/blog/how-to-build-a-react-powerpoint-viewer.md)
- [How To Build A Reactjs File Viewer](/blog/how-to-build-a-reactjs-file-viewer.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer-with-react-pdf.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer.md)
- [How To Build A Reactjs Viewer With Pdfjs](/blog/how-to-build-a-reactjs-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer With Pdfjs](/blog/how-to-build-a-vuejs-pdf-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer](/blog/how-to-build-a-vuejs-pdf-viewer.md)
- [How To Build An Android Pdf Viewer](/blog/how-to-build-an-android-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Ng2 Pdf Viewer](/blog/how-to-build-an-angular-pdf-viewer-with-ng2-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Pdfjs](/blog/how-to-build-an-angular-pdf-viewer-with-pdfjs.md)
- [How To Convert Docx To Pdf Using Javascript](/blog/how-to-convert-docx-to-pdf-using-javascript.md)
- [How To Convert Docx To Pdf Using Python](/blog/how-to-convert-docx-to-pdf-using-python.md)
- [How To Convert Html To Pdf Using Html2pdf](/blog/how-to-convert-html-to-pdf-using-html2pdf.md)
- [or](/blog/how-to-convert-html-to-pdf-using-react.md)
- [How To Convert Html To Pdf Using Wkhtmltopdf And Csharp](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-csharp.md)
- [or](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-python.md)
- [How To Convert Html To Pptx](/blog/how-to-convert-html-to-pptx.md)
- [Quarterly report](/blog/how-to-convert-pdf-to-markdown-using-python.md)
- [How To Convert Word To Pdf In Nodejs](/blog/how-to-convert-word-to-pdf-in-nodejs.md)
- [or](/blog/how-to-create-a-react-js-signature-pad.md)
- [How To Create Pdfs With React To Pdf](/blog/how-to-create-pdfs-with-react-to-pdf.md)
- [How To Edit Pdfs Using Ios Pdf Library](/blog/how-to-edit-pdfs-using-ios-pdf-library.md)
- [How To Embed A Pdf Viewer In Your Website](/blog/how-to-embed-a-pdf-viewer-in-your-website.md)
- [How To Extract Tables From Pdf And Images](/blog/how-to-extract-tables-from-pdf-and-images.md)
- [How To Generate Pdf From Html With Nodejs](/blog/how-to-generate-pdf-from-html-with-nodejs.md)
- [base_url tells WeasyPrint where to resolve relative asset paths](/blog/how-to-generate-pdf-reports-from-html-in-python.md)
- [How To Merge Pdfs Using Javascript](/blog/how-to-merge-pdfs-using-javascript.md)
- [How To Ocr Pdfs In Linux](/blog/how-to-ocr-pdfs-in-linux.md)
- [How To Print Pdf In Csharp](/blog/how-to-print-pdf-in-csharp.md)
- [How To Programmatically Create And Fill Pdf Form In Angular](/blog/how-to-programmatically-create-and-fill-pdf-form-in-angular.md)
- [Open an image.](/blog/how-to-use-tesseract-ocr-in-python.md)
- [From an HTML string.](/blog/html-in-pdf-format.md)
- [Html To Pdf In Javascript](/blog/html-to-pdf-in-javascript.md)
- [Invoice Approval Software](/blog/invoice-approval-software.md)
- [Javascript Document Editor](/blog/javascript-document-editor.md)
- [Javascript Pdf Editors](/blog/javascript-pdf-editors.md)
- [Javascript Pdf Libraries](/blog/javascript-pdf-libraries.md)
- [Langextract Vs Llamaindex Extraction Comparison](/blog/langextract-vs-llamaindex-extraction-comparison.md)
- [Linearized Pdf](/blog/linearized-pdf.md)
- [Uses OpenAI by default — set OPENAI_API_KEY.](/blog/llamaindex-vs-langchain-rag.md)
- [Llamaparse Alternatives](/blog/llamaparse-alternatives.md)
- [Low Code No Code Document Integrations](/blog/low-code-no-code-document-integrations.md)
- [Material Requisition](/blog/material-requisition.md)
- [or](/blog/merge-pdfs.md)
- [Swift Package Manager](/blog/mobile-pdf-sdk.md)
- [`elements` come from your document parser — each has a type and content.](/blog/multimodal-rag.md)
- [Nutrient Flutter 6 Bindings Api](/blog/nutrient-flutter-6-bindings-api.md)
- [Nutrient Flutter Bindings Architecture](/blog/nutrient-flutter-bindings-architecture.md)
- [Nutrient Vs Conga Composer](/blog/nutrient-vs-conga-composer.md)
- [Online Document Viewer](/blog/online-document-viewer.md)
- [Open Pdf In Your Web App](/blog/open-pdf-in-your-web-app.md)
- [PDF accessibility for developers: Meeting WCAG 2.2, Section 508, and PDF/UA with an SDK](/blog/pdf-accessibility.md)
- [Extract data from PDF files: A developer guide to structured data from PDFs and scans](/blog/pdf-data-extraction-developer-guide.md)
- [Pdf Extraction Benchmark Opendataloader Bench](/blog/pdf-extraction-benchmark-opendataloader-bench.md)
- [Pdf Extraction Document Case Studies](/blog/pdf-extraction-document-case-studies.md)
- [Pdf Page Labels](/blog/pdf-page-labels.md)
- [Pdf Sdk Compliance Security Checklist](/blog/pdf-sdk-compliance-security-checklist.md)
- [Pdf Sdk Performance Benchmark](/blog/pdf-sdk-performance-benchmark.md)
- [Pdf Ua Compliance Guide](/blog/pdf-ua-compliance-guide.md)
- [Pdf Ua Validation](/blog/pdf-ua-validation.md)
- [Pdfjs Accessibility Structtree Printing](/blog/pdfjs-accessibility-structtree-printing.md)
- [Pdfjs Advanced Loading Streaming Workers](/blog/pdfjs-advanced-loading-streaming-workers.md)
- [Pdfjs Annotation Editor Layer](/blog/pdfjs-annotation-editor-layer.md)
- [Pdfjs Area Annotations Canvas Capture](/blog/pdfjs-area-annotations-canvas-capture.md)
- [Pdfjs Coordinate Systems Pdf To Screen](/blog/pdfjs-coordinate-systems-pdf-to-screen.md)
- [Pdfjs Document Outline Bookmarks Metadata](/blog/pdfjs-document-outline-bookmarks-metadata.md)
- [Pdfjs Eventbus Guide](/blog/pdfjs-eventbus-guide.md)
- [macOS](/blog/pdfjs-file-format-conversion-to-pdf.md)
- [macOS](/blog/pdfjs-generating-pdf-thumbnails-pdf2pic.md)
- [Pdfjs Limitations Commercial Upgrade](/blog/pdfjs-limitations-commercial-upgrade.md)
- [Pdfjs Native Annotation Layer Forms](/blog/pdfjs-native-annotation-layer-forms.md)
- [Pdfjs Navigation Zoom Rotation](/blog/pdfjs-navigation-zoom-rotation.md)
- [Pdfjs Pdf Page Manipulation Pdf Lib](/blog/pdfjs-pdf-page-manipulation-pdf-lib.md)
- [Pdfjs React Viewer Setup](/blog/pdfjs-react-viewer-setup.md)
- [Pdfjs Rendering Overlays React Portals](/blog/pdfjs-rendering-overlays-react-portals.md)
- [Pdfjs Server Side Text Extraction](/blog/pdfjs-server-side-text-extraction.md)
- [Pdfjs Sticky Note Annotations](/blog/pdfjs-sticky-note-annotations.md)
- [Pdfjs Text Highlight Annotations](/blog/pdfjs-text-highlight-annotations.md)
- [Pdfjs Text Search Pdffindcontroller](/blog/pdfjs-text-search-pdffindcontroller.md)
- [Pdfjs Thumbnail Sidebar](/blog/pdfjs-thumbnail-sidebar.md)
- [People Process Tools](/blog/people-process-tools.md)
- [Process Flows](/blog/process-flows.md)
- [React Native Pdf Annotation](/blog/react-native-pdf-annotation.md)
- [React Pdf Annotation Layer Forms](/blog/react-pdf-annotation-layer-forms.md)
- [React Pdf Custom Rendering Hooks](/blog/react-pdf-custom-rendering-hooks.md)
- [Using Yarn](/blog/react-pdf-editor.md)
- [React Pdf Loading States Errors Passwords](/blog/react-pdf-loading-states-errors-passwords.md)
- [React Pdf Outline Table Of Contents](/blog/react-pdf-outline-table-of-contents.md)
- [React Pdf Performance Optimization](/blog/react-pdf-performance-optimization.md)
- [React Pdf Setup Basic Rendering](/blog/react-pdf-setup-basic-rendering.md)
- [React Pdf Text Layer Custom Renderer](/blog/react-pdf-text-layer-custom-renderer.md)
- [React Pdf Thumbnails Page Navigation](/blog/react-pdf-thumbnails-page-navigation.md)
- [Reducto Alternatives](/blog/reducto-alternatives.md)
- [Requisition System](/blog/requisition-system.md)
- [labels.py](/blog/route-documents-automatically-classify-api.md)
- [or](/blog/sample-blog-updated.md)
- [Sdk Product Updates Q2 2026](/blog/sdk-product-updates-q2-2026.md)
- [System Of Record Vs Source Of Truth](/blog/system-of-record-vs-source-of-truth.md)
- [Add DWS MCP Server to your Claude Code project.](/blog/teaching-llms-to-read-pdfs.md)
- [The Six Best Pdf Generator Apis](/blog/the-six-best-pdf-generator-apis.md)
- [Define the HTML part of the document.](/blog/top-10-ways-to-generate-pdfs-in-python.md)
- [Top 5 Javascript Pdf Viewers](/blog/top-5-javascript-pdf-viewers.md)
- [or](/blog/top-js-pdf-libraries.md)
- [Convert an HTML file to PDF.](/blog/top-ten-ways-to-convert-html-to-pdf.md)
- [Vector Pdf](/blog/vector-pdf.md)
- [Wcag2 Accessibility Requirements Documents](/blog/wcag2-accessibility-requirements-documents.md)
- [Web Sdk Is Now Headless](/blog/web-sdk-is-now-headless.md)
- [What Are Annotations](/blog/what-are-annotations.md)
- [What Is A Vpat](/blog/what-is-a-vpat.md)
- [What Is Business Logic](/blog/what-is-business-logic.md)
- [What Is Document Processing](/blog/what-is-document-processing.md)
- [What Is Intelligent Document Processing](/blog/what-is-intelligent-document-processing.md)
- [What Is Ocr Invoice Processing](/blog/what-is-ocr-invoice-processing.md)
- [What Is Pdf Ua](/blog/what-is-pdf-ua.md)
- [Why Pdfium Is A Trusted Platform For Pdf Rendering](/blog/why-pdfium-is-a-trusted-platform-for-pdf-rendering.md)
- [Why Your Ai Agent Hallucinates Pdf Table Data](/blog/why-your-ai-agent-hallucinates-pdf-table-data.md)

