What sucks, who sucks and you suck

Scan Magick

2009-06-10

Enhancing scanned images with ImageMagick

Having nailed down a faster b/w workflow for digital images, using Bibble, I’ve been considering something similar for scanned negatives. Obviously, the bulk of time is unavoidably expended on developing and scanning those negatives (which is why I now have four unprocessed rolls of film sitting in a drawer), but that time can be amortized over all the frames on a roll, whereas taking those scans through to a finished print absorbs more time per image. What I want is a quick, automated way to perform the minimum remaining steps necessary to produce an acceptable result.

Let’s define “acceptable”. It doesn’t involve any image-specific changes, such as the various dodging and burning steps that normally go into a “perfect” b/w print. At the minimum, I’d perform:

Auto-levels adjustment to fix the poor contrast of the scan, possibly combined with lowering the mid-point to darken the rather pale scanner output.

Some degree of unsharp masking to recover soft detail.

Resizing to a resolution suitable for web display (but also a version for producing a standard 6x4” print).

Output sharpening to recover detail lost by resizing.

This would be pretty much equivalent to receiving a set of lab machine prints from a roll of chromogenic B&W (ah, the good old days, before I’d heard of “burning in”). For the purposes I have in mind, this would be acceptable; the rellies want to see pictures of their grandchildren and don’t greatly care if they’ve been tonally balanced and corrected.

Local contrast enhancement (the “USM with a large radius” technique) to lift the overall image.

Some sort of toning, probably warming the image slightly if nothing else.

Optionally, subtle vignetting, edge burning or corner darkening to focus attention on the centre of the frame.

Bibble would be ideal for all this, since it’s pretty much the aforementioned digital b/w workflow, but unfortunately it can’t handle non-RAW file formats (even DNG conversions); just one tiny change to accept standard TIFF would fix this, but alas. Instead, I looked at the open source ImageMagick utilities, which have a number of useful options that can, with some hacking, be cajoled into performing the above steps. As a bonus, they will work with 16 bit scans to lessen the overall pixel deterioration.

There are a number of caveats surrounding IM. It isn’t the most stable of packages, and it certainly doesn’t have a stable interface. Bear in mind that the online documentation always refers to the latest version of the software, whereas you may have something older bundled in your OS unless you opt to install the upstream releases directly from the IM web site. Several options useful for processing photographic images are only present in the most recent releases, and it isn’t uncommon for bugs to occur with certain options in older versions. The documentation isn’t always unambiguous or consistent, and the examples sometimes confuse rather than explain; the key lies in experimentation.

The IM options of interest are:

-normalize

Roughly the equivalent of “auto levels” in the GIMP, although not quite as dramatic (it uses a slightly different algorithm). This would be a good first step, but you may prefer -contrast-stretch if your version of IM supports it.

-level

Manual levels adjustment, which you may want to further boost contrast (the author of VueScan reckons shifting the black and white points in by 5% gives a result equivalent to most high street prints; you may prefer something more subtle). I’d let normalize set the white point and use this to shift the black point up only, and maybe lower the mid-point if your scans are habitually too light.

-unsharp

The USM parameters in IM work slightly differently to other packages. This can be used for the initial sharpening, local contrast enhancement (but remember to increase the sigma value) and output sharpening.

-resize

IM’s geometry parameters have a number of features to let you specify fixed or proportional resizing, together with limits so that images below a certain dimension are not scaled. The resizing algorithm can be explicitly chosen by preceding it with a -filter option; ‘box’ seems like a good choice for downsampling, as it averages pixels to produce a smoother result (unless you want to retain grain effects), but ‘sinc’ is actually a more intelligent algorithm.

-trim

Potentially, trim with a suitable -fuzz factor may be able to remove dark edges on oversized scans, but I haven’t actually got it to work like this yet. You may also wish to retain the frame edges on some images (e.g. Holga shots).

-colorize

Colorize with a low percentage amount can be used to add a light, uniform tone to the image, with the colour specified by -fill. I suspect there are better ways to do this in IM, possibly using gradients generated on the fly, but I haven’t looked into it too deeply yet.

-enhance, -despeckle

Possibly of use, but I didn’t see worthwhile results with either.

Contrast masking

A bit more involved: a mask file can be generated from the image using -negate and -gaussian, and then reapplied to the original with composite in overlay mode. In theory, this could be done in one operation; in practice, I couldn’t figure out how.

Edge burning

If someone can figure out a way with IM to algorithmically generate a frame matching the image size with a graduated, darkened edge, this could probably be applied using composite as above. Answers on a postcard…

The result is a Bash script, scan2web, that applies the appropriate options with some measure of parameterisation possible, to each image file listed on the command line. Apart from the optional arguments, there are some settings at the top of the script that you may wish to customise to your needs.

To use it:

Scan with minimal corrections or adjustments in 16 bit: the aim is to create a full range image file.

To generate a web-ready image with a longest side of 600 pixels, run:

$ scan2web <imagefile>

which will generate a file called imagefile-web.jpg

To create a full size image suitable for printing, simply specify a size greater than the longest side of the original image; e.g.:

$ scan2web -r 6000 <imagefile>

(Note: this post was originally written two years ago, but I have only just got around to finishing it off. The script has proved very useful during this period.)