rryBlog
Wed, 22 Feb 2006 @ 13:42
[/tech]
Working with graphics from the command-line

Sarah’s been busy in the studio, taking photos of various gorgeous people for her project on body modification. Yesterday’s session produced around a gigabyte of images, which were uploaded to wintermute for safekeeping.

Unfortunately, some of them didn’t turn out properly. In this one, for example, the studio flash didn’t fire - so the image was taken with the modelling lights only. Therefore, it’s underexposed and the colour balance is badly off.

underexposed peet

What could I do to help?

Well, the images are on a remote server, and they’re almost 4 MB each. I didn’t fancy having to download, edit, then re-upload them - so that limited me to the command-line tools available in the Imagemagick suite. In particular, I’ve used the “mogrify” and “convert” commands - “mogrify” changes the original image, whereas “convert” saves the changes to a new file.

Step one: auto-rotation

Sarah’s Canon 350D camera has a sensor that detects if a photo is taken in portatrait orientation, rather than landscape. This information is encoded in the EXIF data within the jpeg headers, and can be used to rotate any images that need it without losing any quality:

jhead -autorot *.jpg
Step two: normalization

Okay, the image is now the right way up, but it’s still very dark. Imagemagick’s “normalize” option will spread out the colour values over the full range, increasing contrast and (usually) helping to correct colour balances (note that this is called “Auto Levels” in the GIMP and Photoshop:

mogrify -normalize *.jpg
normalized peet

Step three: converting to b&w

Hm, those colours are awful - he looks jaundiced and spotty and hungover, nothing like his appearance in the properly-lit pictures - and the damage is probably beyond repair without lots of tedious pixel-level editing. The range of tones is decent enough, though, and there’s plenty of contrast - so lets try converting that one black and white:

mogrify -monochrome 1213.jpg
monochrome peet

Ooops. That’s a dithered two-colour image - we want a grayscale. The “grayscale” or “desaturate” option in GUI graphics programs wil almost always average the red, green, and blue values of each pixel - thus creating a b&w image that contains information from all three colour channels. to replicate this in the gimp, we use the “modulate” option, which lets us specify a percentage change for brightness, saturation, and hue:

mogrify -modulate 100,0,100 1213.jpg
desaturated peet

Not much better, is it? Unfortunately, the colour image was rather noisy - but that noise was largely confined to the colour of each pixel, rather than the brightness of it. So, rather than just extracting the r, g, and b values from each pixel, lets try extracting the “intensity” and “luminosity” values from each pixel.

convert 1213.jpg -fx 'luminosity' 1213.luminosity.jpg
luminous peet

convert 1213.jpg -fx 'intensity' 1213.intensity.jpg
intense peet

For a portrait, the luminosity version is probably the better - but either is a huge improvement over a simple desaturation. Hurrah!

Step four: noise reduction

There’s still a little bit of noise in that image - so, let’s try to smooth that out using imagemagick’s “enhance” option:

convert 1213.luminosity.jpg -enhance 1213.enhanced.jpg
enhanced peet

That’s an improvement - but at the cost of a little loss of detail in his hair, and a general softening of the image. Personally, I think the original was fine - but Imagemagick’s noise enhancement can work wonders on images that would otherwise have been ruined by grain.

Step five: sharpening

All the cool kids apply an unsharp mask to their images, so lets do that, too. Imagemagick can auto-select appropriate values, which is really handy for doing a reasonable-enough job on huge batches of images:

convert 1213.unsharp.jpg -unsharp 1213.unsharp.jpg
unsharp peet

And finally…

Becuase jpegs are lossy, the manipulations we’ve made in steps two to four should really be done at the same time, in order to preserve maximum image quality (and also to keep the file size down):

convert 1213.jpg -normalize -fx 'luminosity' -enhance -unsharp 0 1213.processed.jpg
final peet

easy, eh?