I often scan text documents - text and possibly some logo/letterhead on a page, either entirely or mostly black-and-white. After scanning, I:

  • Rotate the image to make sure the text is straight
    (this could be an adaptive transformation in case the page isn't a proper straight surface, but I can't do that manually)
  • Figure out the page boundaries
  • Crop to the page boundaries
    (sometimes a little further in for uniformity with other pages in the same sequence of scans)
  • Adjust levels, to try to get the text to be black, its surrounding gradient stay grey, and the background be white with most noise becoming white.
  • In some cases, do some manual spot/stain removal from the background.
  • Avoid the level adjustment for regions such as photos printed on the page (which might get their own level adjustments).

Is there software for automating these tasks? For individual images and for batch processing of image files?

I am mainly interested in software on Linux (I work with Debian Stretch, Fedora 22 and Lubuntu 15.10 currently), but Windows solutions are also somewhat relevant. For the sake of discussion, there are no "budget limits" and commercial software is also relevant.


  • I do not want or need text extraction, text recognition etc - that's a whole other kind of task (although not entirely unrelated I suppose).
  • I don't necessarily need everything I listed above. The idea is for me to be able to put the results together into a PDF, send it around and for it to be pleasingly readable. The more I can fix it up the better of course.
  • Thanks! That copyright part sounds strange, though. Just being curious: where is that?
    – Izzy
    Jan 1, 2016 at 12:12
  • Israel. There's a "personal use" exception to copyrights.
    – einpoklum
    Jan 1, 2016 at 13:40
  • 1
    @einpoklum Have you ever checked out ImageMagick? I've automated a ton conversions, etc. on a Windows PC for home-based documents with a batch script and some iteration loops, etc. I know if works for Linux as well but wanted to give you the link in case you find it helpful for an open source solution Unix - Binary Release Jan 2, 2016 at 7:42
  • @LMFAO_A_JOKE: Interesting username, that. Anyway, I know about ImageMagick, but I didn't realize it could be used for something other than image format conversion. Does it really do what I listed in the question?
    – einpoklum
    Jan 2, 2016 at 11:18
  • 2
    @einpoklum Well you did say it does not necessarily need to do everything listed in your request and I know it can do some of those things. I figured I'd point you to it and you could read up on it as a potential solution but I'm not 100% if it'll do ALL but it should be able to do some at least. I use GhostScript, PDFtk, and ImageMagick for everything I do with documents for home-use based stuff but my stuff is not as complex as yours. This will maybe at least give you a good starting point perhaps!! Jan 2, 2016 at 16:14

4 Answers 4


What you describe can be done with OpenCV and python as demonstrated here and Adrian's imutils, the rest of the blog posts are worth a read as well. (Note that the code in the blog post makes use of code from an earlier blog post https://pyimagesearch.com/2014/08/25/… looking at it it uses a directory called pyimagesearch with a file called transform.py - you obviously also need to pip install numpy skimage imuitls opencv-python-contrib - https://pyimagesearch.com/2018/09/19/pip-install-opencv).

  • Free, Gratis & Open Source
  • Cross Platform - works on Windows, OS-X, Linux, Android...
  • Completely customizable
  • The code to mostly perform the first 4 of your requirements comes to about 75 lines below.
  • You may wish to customise to crop to text area

Code & Images from Adrian Rosebrock's Blog

# import the necessary packages
from pyimagesearch.transform import four_point_transform
from pyimagesearch import imutils # may just be import imutils
from skimage.filters import threshold_adaptive
import numpy as np
import argparse
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True,
    help = "Path to the image to be scanned")
args = vars(ap.parse_args())
# load the image and compute the ratio of the old height
# to the new height, clone it, and resize it
image = cv2.imread(args["image"])
ratio = image.shape[0] / 500.0
orig = image.copy()
image = imutils.resize(image, height = 500)
# convert the image to grayscale, blur it, and find edges
# in the image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 75, 200)
# show the original image and the edge detected image
print("STEP 1: Edge Detection")
cv2.imshow("Image", image)
cv2.imshow("Edged", edged)
# find the contours in the edged image, keeping only the
# largest ones, and initialize the screen contour
(cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
# loop over the contours
for c in cnts:
    # approximate the contour
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    # if our approximated contour has four points, then we
    # can assume that we have found our screen
    if len(approx) == 4:
        screenCnt = approx
# show the contour (outline) of the piece of paper
print("STEP 2: Find contours of paper")
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
cv2.imshow("Outline", image)
# apply the four point transform to obtain a top-down
# view of the original image
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
# convert the warped image to grayscale, then threshold it
# to give it that 'black and white' paper effect
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
warped = threshold_adaptive(warped, 250, offset = 10)
warped = warped.astype("uint8") * 255
# show the original and scanned images
print("STEP 3: Apply perspective transform")
cv2.imshow("Original", imutils.resize(orig, height = 650))
cv2.imshow("Scanned", imutils.resize(warped, height = 650))
# Save as a PNG in the current directory courtesy of  Nicolas Raoul
cv2.imwrite('Scanned.png', warped)  # Not in original code


Whole Foods Reciept

  • 1
    (cnts, _) = cv2.findContours -> (_, cnts, _) = cv2.findContours in recent Python versions (2.x versions too).
    – Nicolas Raoul
    Dec 14, 2018 at 6:10
  • @NicolasRaoul I suspect that it is a change to the python wrappers with later versions of OpenCV rather than changes in Python (OpenCV 2.1 had a change away from SWING wrappers). Dec 14, 2018 at 21:28
  • Can you name the modules one needs to install (e.g. with pip) for this to work? I get ModuleNotFoundError: No module named 'pyimagesearch'
    – einpoklum
    Apr 25, 2020 at 8:13
  • @einpoklum You need to download the code from the previous blog post and save into a file called pyimagesearch - you also need to pip install imutils Apr 27, 2020 at 21:56
  • @SteveBarnes: Which one of the previous posts?
    – einpoklum
    Apr 27, 2020 at 22:05

I have found that Adobe Acrobat Professional can do most of what you are looking for. You can find out more at: Adobe Acrobat DC

Our Customer Support department receives hundreds of orders daily. These orders are scanned using a Xerox Documate 4760 scanner. This scanner is a workhorse that quickly scans duplex sheets in 1 pass. Once the orders are scanned, a co-worker uses Adobe Acrobat DC Professional to correct common scanning issues like crooked sheets, speckles, sharpness etc. Another nice feature Adobe Acrobat DC Professional brings to the table is document indexing.

And you can always try the trial version and draw your own opinion.

  • Thank you Izzy. I'll be sure to keep your suggestion in mind for future correspondence. Mar 9, 2018 at 15:01

If you want an open-source single-script solution, take a look at the textdeskew script by Fred Weinhaus.

If you want to see what the script does: there are a few before-after figures on the page that I've linked to.

There are quite a few command line options, for fine-tuning.

Find it on Fred's ImageMagick Scripts for more, e.g. texctcleaner, also with preview images.


I recommend checking out the LEADTOOLS Document Imaging SDK for this. This SDK includes support for scanning, image rotation, and image processing. There is an SDK for Windows and Linux.

For scanning on Windows, there is TWAIN integration. Using this, you could dictate the number of pages to acquire before scanning begins.

For scanning on Linux, there is SANE integration.

OCR Support is availble on both platforms if you do change your mind.

Rotation, deskew, croping, and adjusting color levels can all be done in a few lines of code like this:

//Rotate the image counter-clockwise 90 degrees

//Deskew the image
DeskewCommand deskewCmd = new DeskewCommand();
deskewCmd.Flags = DeskewCommandFlags.DeskewImage | DeskewCommandFlags.DoNotFillExposedArea;

//crop the image with a change of intensity level less than 30 (from center of image)
AutoCropCommand cropCmd = new AutoCropCommand();
cropCmd.Threshold = 30;

//Apply "Auto Leveling" to the image.
AutoColorLevelCommand colorLvlCmd = new AutoColorLevelCommand();

Since this is an SDK, you can create a batch application to handle this all automatically or an application to assist you in doing these things very quickly.

Disclaimer: I am an employee of the company that wrote this library.

  • 1
    It looks like this SDK can only partially automate my work, i.e. I can easily tell it to do these things, but the exact parameters - how much to rotate, where to crop, what threshold to use, whether to take the center of the image as the reference point etc. - is up to me. So, it doesn't quite look like what I'm after.
    – einpoklum
    Oct 14, 2016 at 21:52
  • It would be cool if it could find out the text's direction before applying (or not) RotateViewPerspective
    – Nicolas Raoul
    Mar 8, 2018 at 9:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.