GithubHelp home page GithubHelp logo

deskew's Introduction

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

deskew's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar geo-ghci-int[bot] avatar kuz-man avatar pre-commit-ci[bot] avatar renovate-bot avatar renovate[bot] avatar sbrunner avatar theamdara avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

deskew's Issues

I'm getting an error here: grayscale = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

The error message is:

cv2.error: OpenCV(4.9.0) /Users/runner/work/opencv-python/opencv-python/opencv/modules/imgproc/src/color.cpp:196: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'

I'm using Python 3.11.7
I have versions:
opencv-python == 4.9.0.80

The code is:

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)

def rotate2(file):
    
    image = cv2.imread(file)
    grayscale = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    angle = determine_skew(grayscale)
    rotated = rotate(image, angle, (0, 0, 0))
    cv2.imwrite(file, rotated)
  
    return
rotate2(file)

num-angles not passed in cli.py

In cli.py the argument --num-angles is never used. It should be added to the call to determine_skew (i.e. add num_angles=options.num_angles to the parameter list being passed). Whatever the default is appears to fairly coarse and since num-angles is ignored it makes it appear the code does nothing when using the CLI on many kinds of files with small rotations.

Again, apologies for not just pushing a change since I'm a troglodyte. Thanks again for the nice library!

cli.py argparse missing types, causes errors

The parser.add_argument lines in main() in cli.py do not include a type which results in the arguments being passed as a string further in the code causing run time errors when they are compared with numerics. Adding the following types fixes things:

--sigma type=float
--num-peaks type=int
--num-angles type=int

Sorry - I'm a gidiot who doesn't understand git so I haven't pushed the fixes myself. Thanks for the wonderful library!

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • Update CI dependencies (patch) (c2cciutils, camptocamp/c2cciutils, prettier)
  • Update all patch versions (patch) (matplotlib, numpy)
  • Update CI dependencies (minor) (asottile/pyupgrade, pre-commit, psf/black, python-jsonschema/check-jsonschema)
  • Update all minor versions (minor) (coverage, pytest)
  • Update dependency importlib-metadata to v8
  • Lock file maintenance

Detected dependencies

github-actions
.github/workflows/main.yaml
  • actions/checkout v4
  • actions/cache v4
  • actions/upload-artifact v4
  • actions/setup-python v5
  • actions/checkout v4
  • actions/upload-artifact v4
  • actions/checkout v4
  • actions/checkout v4
  • actions/upload-artifact v4
  • ubuntu 22.04
  • ubuntu 22.04
  • ubuntu 22.04
.github/workflows/pull-request-automation.yaml
  • actions/github-script v7
  • actions/github-script v7
  • actions/github-script v7
  • ubuntu 22.04
pep621
pyproject.toml
  • poetry-core >=1.0.0
pip_requirements
ci/requirements.txt
  • c2cciutils ==1.6.21
  • poetry ==1.8.3
  • poetry-plugin-tweak-dependencies-version ==1.5.2
  • poetry-dynamic-versioning ==1.4.0
  • pre-commit ==3.7.1
  • poetry-plugin-drop-python-upper-constraint ==0.1.0
  • poetry-plugin-export ==1.8.0
  • importlib-metadata <8.0.0
  • certifi >=2024.7.4
  • zipp >=3.19.1
poetry
pyproject.toml
  • python >=3.10,<3.13
  • numpy 2.0.0
  • scikit-image 0.24.0
  • opencv-python-headless 4.10.0.84
  • matplotlib 3.9.0
  • prospector 1.10.3
  • pytest 8.2.2
  • pytest-profiling 1.7.0
  • coverage 7.5.4
  • prospector-profile-duplicated 1.5.0
pre-commit
.pre-commit-config.yaml
  • pre-commit/pre-commit-hooks v4.6.0
  • sbrunner/hooks 1.0.0
  • codespell-project/codespell v2.3.0
  • pre-commit/mirrors-prettier v3.1.0
  • shellcheck-py/shellcheck-py v0.10.0.1
  • jumanjihouse/pre-commit-hooks 3.0.0
  • python-jsonschema/check-jsonschema 0.28.6
  • sirwart/ripsecrets v0.1.8
  • psf/black 24.4.2
  • PyCQA/isort 5.13.2
  • PyCQA/autoflake v2.3.1
  • asottile/pyupgrade v3.16.0
  • PyCQA/prospector v1.10.3
  • sbrunner/jsonschema-validator 0.1.0
regex
.pre-commit-config.yaml
  • poetry 1.8.3
  • poetry 1.8.3
  • prettier 3.3.2
  • prettier-plugin-sh 0.14.0
  • prettier-plugin-toml 2.0.1
  • pyjson5 1.6.6
  • prospector-profile-duplicated 1.5.0
ci/config.yaml
  • camptocamp/c2cciutils 1.6.21

  • Check this box to trigger a request for Renovate to run again on this repository

error using the CLI

Hello,

Trying to run deskew from command line, I get this error -

Traceback (most recent call last):
  File "/usr/local/bin/deskew", line 7, in <module>
    from deskew.cli import main
  File "/usr/local/lib/python2.7/dist-packages/deskew/__init__.py", line 8
    def _get_max_freq_elem(peaks: List[int]) -> List[float]:
                                ^
SyntaxError: invalid syntax

certifi-2022.9.24-py3-none-any.whl: 1 vulnerabilities (highest severity is: 6.8)

Vulnerable Library - certifi-2022.9.24-py3-none-any.whl

Python package for providing Mozilla's CA Bundle.

Library home page: https://files.pythonhosted.org/packages/1d/38/fa96a426e0c0e68aabc68e896584b83ad1eec779265a028e156ce509630e/certifi-2022.9.24-py3-none-any.whl

Path to dependency file: /ci/requirements.txt

Path to vulnerable library: /ci/requirements.txt,/ci/requirements.txt

Vulnerabilities

CVE Severity CVSS Dependency Type Fixed in (certifi version) Remediation Available
CVE-2022-23491 Medium 6.8 certifi-2022.9.24-py3-none-any.whl Direct certifi - 2022.12.07

Details

CVE-2022-23491

Vulnerable Library - certifi-2022.9.24-py3-none-any.whl

Python package for providing Mozilla's CA Bundle.

Library home page: https://files.pythonhosted.org/packages/1d/38/fa96a426e0c0e68aabc68e896584b83ad1eec779265a028e156ce509630e/certifi-2022.9.24-py3-none-any.whl

Path to dependency file: /ci/requirements.txt

Path to vulnerable library: /ci/requirements.txt,/ci/requirements.txt

Dependency Hierarchy:

  • certifi-2022.9.24-py3-none-any.whl (Vulnerable Library)

Found in base branch: master

Vulnerability Details

Certifi is a curated collection of Root Certificates for validating the trustworthiness of SSL certificates while verifying the identity of TLS hosts. Certifi 2022.12.07 removes root certificates from "TrustCor" from the root store. These are in the process of being removed from Mozilla's trust store. TrustCor's root certificates are being removed pursuant to an investigation prompted by media reporting that TrustCor's ownership also operated a business that produced spyware. Conclusions of Mozilla's investigation can be found in the linked google group discussion.

Publish Date: 2022-12-07

URL: CVE-2022-23491

CVSS 3 Score Details (6.8)

Base Score Metrics:

  • Exploitability Metrics:
    • Attack Vector: Network
    • Attack Complexity: Low
    • Privileges Required: High
    • User Interaction: None
    • Scope: Changed
  • Impact Metrics:
    • Confidentiality Impact: None
    • Integrity Impact: High
    • Availability Impact: None

For more information on CVSS3 Scores, click here.

Suggested Fix

Type: Upgrade version

Origin: https://www.cve.org/CVERecord?id=CVE-2022-23491

Release Date: 2022-12-07

Fix Resolution: certifi - 2022.12.07

Step up your Open Source Security Game with Mend here

Updated binaries?

Hi,

Considering that version 1.5.1 was released last month, I wanted to know you intend to update the binaries for the CLI Tool and the GUI Frontend. These are the latest versions you can find on the web:

Deskew CLI Tool v1.30. Posted on: June 19, 2019.
GUI Frontend for Deskew. Posted on: December 4, 2018.

By the way, I was finally able to access the web on https://galfar.vevb.net/wp/projects/deskew/, but the first time I try, there was a weird webpage with a robot and message to click on something to prove that I wasn't a bot.

Thanks!

Different Angle Predictions at Different Image scales/sizes

Hey There,

I've been using this Repo for more than a quarter. I use to deal with the images of ~4000 x 5000 resoultions.
The Determine skew is resulting different angles at different scales.

I've tried to resize the image to its 1 scale, 0.5 scale, 0.25 scale and so on...

Here is the results,
iteration -> Scale(fx, fy) -> angle -> resolution
0 --> 1 --> 0.0 --> (5500, 4250)
1 --> 0.5 --> 0.0 --> (2750, 2125)
2 --> 0.25 --> 0.0 --> (1375, 1062)
3 --> 0.125 --> 0.0 --> (688, 531)
4 --> 0.0625 --> 0.5027932960893793 --> (344, 266)

You can see at 0.0625 scale angle has been figured out and after correcting the angle image was looking good at least for naked eye.

Please let me know your thoughts.

Support 3.12 on PyPI

Hi!

I tried to upgrade one of my projects to 3.12 and I found I was blocked on this package, with the following error:

The current project's supported Python range (>=3.12,<3.13) is not compatible with some of the required packages Python requirement:
  - deskew requires Python >=3.8,<3.12, so it will not be satisfied for Python >=3.12,<3.13

I checked the current code and it seems that on master 3.12 should be supported.

Would it please be possible to make a release to PyPI which would support 3.12?

I would be happy to help with anything if there's something blocking it.

Thanks,
Miki

Detect Text direction

I have an image which is rotated 90 degrees. The program rotates it back 90 degrees but in wrong direction - text is on reverse direction.

Do you have any idea how to fix this?

How to run?

Hi there! Just want to ask how to run this properly as I can't seem to make it run just using the cli. Do I need to install other stuffs aside from

scikit image
numpy

How does this calculate the angle?

I know the preprocessing it takes like the gray scale, Hough lines and Hough lines peak, but how does it use them to calculate the skew angle?
I tried plotting the intermediate lines, how does it get to know the prominent green lines?
Can you please explain it.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • Update all patch versions (patch) (c2cciutils, coverage)
  • Update dependency poetry to v1.3.2
  • Lock file maintenance

Edited/Blocked

These updates have been manually edited so Renovate will no longer make changes. To discard all commits and start over, click on a checkbox.

  • Update all minor versions (minor) (numpy, opencv-python-headless, prospector)

Detected dependencies

github-actions
.github/workflows/changelog.yaml
  • actions/cache v3
.github/workflows/codeql.yaml
  • actions/checkout v3
  • github/codeql-action v2
  • github/codeql-action v2
.github/workflows/delete-old-workflows-run.yaml
  • MajorScruffy/delete-old-workflow-runs v0.3.0
.github/workflows/dependabot-auto-merge.yaml
.github/workflows/main.yaml
  • actions/setup-python v4
  • actions/checkout v3
  • actions/upload-artifact v3
  • actions/checkout v3
  • actions/checkout v3
.github/workflows/pr-checks.yaml
  • actions/checkout v3
pip_requirements
ci/requirements.txt
  • c2cciutils ==1.4.4
  • poetry ==1.3.1
  • poetry-plugin-tweak-dependencies-version ==1.2.1
  • poetry-dynamic-versioning ==0.21.3
  • pip ==22.3.1
poetry
pyproject.toml
  • numpy 1.23.5
  • scikit-image 0.19.3
  • opencv-python-headless 4.6.0.66
  • matplotlib 3.6.2
  • prospector 1.7.7
  • pytest 7.2.0
  • pytest-profiling 1.7.0
  • coverage 7.0.3

Your .dependabot/config.yaml contained invalid details

Dependabot encountered the following error when parsing your .dependabot/config.yaml:

Automerging is not enabled for this account. You can enable it from the [account settings](https://app.dependabot.com/accounts/sbrunner/settings) screen in your Dependabot dashboard.

Please update the config file to conform with Dependabot's specification using our docs and online validator.

Slow performance on 'larger' jpg files

Hi Stéphane,
thank you for your nice repo.
I have been using it to deskew jpg files of scanned documents.
I was noticing that I get very poor performance when trying to detect the skew of files larger than approx. 5mb.
It takes like 3 minutes for one file. Do you have an idea what I could try to speed this up?

Thanks a lot and best regards!

deskew confidence?

Hi @sbrunner,

Is there a way to retrieve the deskew confidence?

It would make it much easier to avoid rotating the image when the confidence in the skew angle is low.

can we customize background mask ?

Hi thanks for the library, i explored various libraries so far to deskew the image but the one you developed gives far better results then rest.

have a doubt

can we customize the background ? i went through the docs but did not found anything related

here is my image
output

as you can see background by default is set to black.

error with correcting straight images

I've run into what I'm guessing is a bug,
I'm running a script that deskews a whole dataset of .tif images, and i've encountered some problems with apparently straight images.
this is the original image(s): out
out_2

this is the ouput from running the following program:
out
out_2

for file in os.listdir(indir):
    if file.endswith(".jpg") or file.endswith(".jpeg") or file.endswith(".png") or file.endswith(".tif"):
        image = cv2.imread(indir +'/'+ file)
        grayscale = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        angle = determine_skew(grayscale)
        rotated = rotate(image, angle, (0, 0, 0))

where rotate is the open cv example here.

The output angle is -45 for both images.

ValueError: the input array must have size 3 along 'channel axis'

I am running this against a PNG file of a completed and scanned survey form and am receiving the following error:

ValueError: the input array must have size 3 along 'channel axis', got (3416, 2645)

I'm using the deskew cli with no optional parameters as input (i.e. I'm running deskew myimage.png). My python version is 3.9 on Debian 11.

different angles than expected

Version: deskew-1.3.3

def deskew(image):
    grayscale = rgb2gray(image)
    angle = determine_skew(grayscale)
    print(angle)
    rotated = rotate(image, angle, resize=True) * 255
    return rotated.astype(np.uint8)

def display_avant_apres(_original):
    dpi = matplotlib.rcParams['figure.dpi']

    image = io.imread(_original)
    height, width, _ = image.shape
    figsize = width / float(dpi), height / float(dpi)
    plt.figure(figsize=figsize)

    plt.subplot(1, 2, 1)
    plt.imshow(image)
    plt.subplot(1, 2, 2)
    plt.imshow(deskew(image))

display_avant_apres("input.jpeg")

-7.999999999999998
image

Doesn't seem to match what is demonstrated in the README, and generally doesn't work properly with +-90deg rotated images.

with angle_pm_90=True made it upside down. Any fixes? using

image

Request for changelog and tagged versions

I just discovered your library and considered using it, but quickly got aware that at least Python 3.8 is required which I am not able to upgrade to yet. Going through the list of releases on PyPI, 0.10.29 seems to be the last version supporting Python < 3.8.

Such things would be much easier if there was a changelog for the different releases as well as tagged versions on GitHub. For now there seem to be tons of new package releases on PyPI to skim through - given that there are 25 releases in 2022 already, this corresponds to more than one release per week, which is hard to keep up with.

With a changelog, it would be easier to check how important an update might be, as well as some easy way to detect deprecations like for Python < 3.8. With GitHub releases or tags comparing the actual differences between the different versions would be possible as well.

Incorrect Angles

Hello

I've tried using the determine_skew function, and have had limited success. If take an image rotate clockwise roughly 15 degrees, the function correctly gives me an angle of 15 degrees. If I provide an image rotate roughly 15 degrees counter clockwise, I get the same result, 15 degrees. I'd expect to get -15 or or 345, not 15. If I've missed something, I apologize. There isn't much to go on from the readme, so I'm not sure if there are limitations to this (perhaps it only works with smaller angles?) or if I am using the library incorrectly.

If I rotate an image -1 and check it with determine_skew, it correctly tells me its angle of rotation is -1. Are there known limitations here?

Does not work with images rotated around 90 degrees

Deskew works great for me for small angles. However, it totally fails for me if images are orientated around 90 degrees.

This is strange, as I have clear horizontal lines through all the documents which should be very easy to detect

I can send example files with private message as this is medical data and I am not at ease to shere it publicly, even after anonymization.

Link to PyPi

If you find the library through GitHub, it's not clear that there's an installable pip package for the project. A link to PyPi package would be helpful.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.