Skip to main content

Deskew

Note: Skew is measured in degrees. Deskewing is a process whereby skew is removed by rotating an image by the same amount as its skew but in the opposite direction. This results in a horizontally and vertically aligned image where the text runs across the page rather than at an angle.

The return angle is between -45 and 45 degrees to don't arbitrary change the image orientation.

By using the library you can set the argument angle_pm_90 to True to have an angle between -90 and 90 degrees.

Skew detection and correction in images containing text

Image with skew Image after deskew
Image with skew Image after deskew

Installation

You can install deskew directly from pypi directly using the following comment

python3 -m pip install deskew

Or to upgrade to newer version

python3 -m pip install -U deskew

Cli usage

Get the skew angle:

deskew input.png

Deskew an image:

deskew --output output.png input.png

Lib usage

With scikit-image:

import numpy as np
from skimage import io
from skimage.color import rgb2gray
from skimage.transform import rotate

from deskew import determine_skew

image = io.imread('input.png')
grayscale = rgb2gray(image)
angle = determine_skew(grayscale)
rotated = rotate(image, angle, resize=True) * 255
io.imsave('output.png', rotated.astype(np.uint8))

With OpenCV:

import math
from typing import Tuple, Union

import cv2
import numpy as np

from deskew import determine_skew


def rotate(
        image: np.ndarray, angle: float, background: Union[int, Tuple[int, int, int]]
) -> np.ndarray:
    old_width, old_height = image.shape[:2]
    angle_radian = math.radians(angle)
    width = abs(np.sin(angle_radian) * old_height) + abs(np.cos(angle_radian) * old_width)
    height = abs(np.sin(angle_radian) * old_width) + abs(np.cos(angle_radian) * old_height)

    image_center = tuple(np.array(image.shape[1::-1]) / 2)
    rot_mat = cv2.getRotationMatrix2D(image_center, angle, 1.0)
    rot_mat[1, 2] += (width - old_width) / 2
    rot_mat[0, 2] += (height - old_height) / 2
    return cv2.warpAffine(image, rot_mat, (int(round(height)), int(round(width))), borderValue=background)

image = cv2.imread('input.png')
grayscale = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
angle = determine_skew(grayscale)
rotated = rotate(image, angle, (0, 0, 0))
cv2.imwrite('output.png', rotated)

Debug images

If you get wrong skew angle you can generate debug images, that can help you to tune the skewing detection.

If you install deskew with pip install deskew[debug_images] you can get some debug images used for the skew detection with the function determine_skew_debug_images.

To start the investigation you should first increase the num_peaks (default 20) and use the determine_skew_debug_images function.

Then you can try to tune the following arguments num_peaks, angle_pm_90, min_angle, max_angle, min_deviation and eventually sigma.

Inspired by Alyn: https://github.com/kakul/Alyn

Contributing

Install the pre-commit hooks:

pip install pre-commit
pre-commit install --allow-missing-config

Metadata

Release files for deskew 1.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for deskew 1.6.1
File Size Uploaded
deskew-1.6.1.tar.gz 7.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for deskew 1.6.1
File Interpreter ABI Platform
deskew-1.6.1-py3-none-any.whl Python 3 none any Details

Total release size: 16.1 kB

Release files / deskew-1.6.1.tar.gz

Download URL deskew-1.6.1.tar.gz
Size 7.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9b10c8c460c6fb9523394768ee6873a6de8da7a12bfc2f94a8a92f0db205b83a
BLAKE2b-256 checksum
How to use checksums
754b542cf2f38db581e7e0d8c26b2f3c1b60a0b955aa2ca29c1dbb794ddbbdf5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Release files / deskew-1.6.1-py3-none-any.whl

Download URL deskew-1.6.1-py3-none-any.whl
Size 8.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6fd0d04f3667d566b52f8ff862c44916a3ab48511c188efc7ded63d1feca1483
BLAKE2b-256 checksum
How to use checksums
a7327278ba4afbed135a09b7069594148b6a545d4db1f016a258eae0956a6361
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Release history Release notifications | RSS feed

This release

1.6.1 This release

2 release files

1.6.0

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.4.3

2 release files

1.4.2

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.3

1 release file

1.3.2

1 release file

1.3.1

1 release file

1.3.0

1 release file

1.2.0

1 release file

1.1.0

1 release file

1.0.26

1 release file

1.0.25

1 release file

1.0.24

1 release file

1.0.23

1 release file

1.0.22

1 release file

1.0.21

1 release file

1.0.19

2 release files

1.0.18

2 release files

1.0.17

2 release files

1.0.16

2 release files

1.0.15

2 release files

1.0.14

2 release files

1.0.13

2 release files

1.0.9

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

0.10.6

2 release files

0.10.5

2 release files

0.10.4

2 release files

0.10.3

2 release files

0.10.2

2 release files

0.10.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page