Programming to process images : scripting

If you don’t want to learn a programming language, but you do want to go beyond the likes of Photoshop and GIMP, then you should consider ImageMagick, and the use of scripts. ImageMagick is used to create, compose, edit and convert images. It can deal with over 200 image formats, and allows processing on the command-line.

1. Using the command line

Most systems like MacOS and Linux, provide what is known as a “shell”. For example in OSX it can be accessed through the “Terminal” app, although it is nicer to use an app like iTerm2. When a window is opened up in the Terminal (or iTerm2), the system applies a shell, which is essentially an environment that you can work in. In a Mac’s OSX, this is usually the “Z” shell, or zsh for short. It let’s you list files, change folders (directories), and manipulate files, among many other things. At this lower level of the system, aptly known as the command-line, programs can be executed using the keyboard. The command-line is different from using an app. It is not WYSIWYG, What-You-See-Is-What-You-Get, but it is perfect for tasks where you know what you want done, or you want to process a whole series of images in the same way.

2. Processing on the command line

Processing on the command-line is very much a text-based endeavour. No one is going to apply a curve-tool to an image in this manner because there is no way of seeing the process happen live. But for other tasks, things are just done way easier on the command line. A case in point is batch-processing. For example say we have a folder of 16 megapixel images, which we want to reduce in size for use on the web. It is uber tedious to have to open them up in an application, and then save each individually at a reduced size. Consider the following example which reduces the size of an image by 50%, i.e. its dimensions are reduced by 50%, using one of the ImageMagick commands:

magick yorkshire.png -resize 50% yorkshire50p.png

There is also a plethora of ready-made scripts out there, for example Fred’s ImageMagick Scripts.

3. Scripting

Command-line processing can be made more powerful using a scripting language. Now it is possible to do batch processing in ImageMagick using mogrify. For example to reduce all PNG images by 40% is simple:

magick mogrify -resize 40% *.png

The one problem here is that mogrify  will overwrite the existing images, so it should be run on copies of the original images. An easier way is to learn about shell scripts, which are small programs designed to run in the shell – basically they are just a list of commands to be performed. These scripts use some of the same constructs as normal programming languages to perform tasks, but also allow the use of a myriad of programs from the system. For example, below is a shell script written in bash (a type of shell), and using the convert command from ImageMagick to convert all the JPG files to PNG.

#!/bin/bash
for img in *.jpg
do
    filename=$(basename "$img")
    extension="${filename##*.}"
    filename="${filename%.*}"
    echo $filename
    convert "$img" "$filename.png"
done

It uses a loop to process each of the JPG files, without affecting the original files. There is some fancy stuff going on before we call convert, but all that does is split the filename and its extension (jpg), keeping the filename, and ditching the extension, so that a new extension (png) can be added to the processed image file.

Sometimes I like to view the intensity histograms of a folder of images but don’t want to have to view them all in an app. Is there an easier way? Again we can write a script.

#!/bin/bash
var1="grayH"
for img in *.png
do
   # Extract basename, ditching extension
   filename=$(basename "$img")
   extension="${filename##*.}"
   filename="${filename%.*}"
   echo $filename

   # Create new filenames
   grayhist="$filename$var1"

   # Generate intensity / grayscale histograms
   convert $filename.png -colorspace Gray -define histogram:unique-colors=false histogram:$grayhist.png
done

Below is a sample of the output applied to a folder. Now I can easily see what the intensity histogram associated with each image looks like.

Histograms generated using a script.

Yes, some of these seem a bit complicated, but once you have a script it can be easily modified to perform other batch processing tasks.

Programming to process images : coding

People take photographs for a number of reasons. People process images for a number of reasons. Some people (like me) spend as little time as possible post-processing images, others spend hours in applications like Photoshop, tweaking every possible part of an image. To each their own. There are others still who like to tinker with the techniques themselves, writing their own software to process their images. There are many different things to consider, and my hope in this post is to try and look at what it means to create your own image processing programs to manipulate images.

Methods of image manipulation

1. What do you want to achieve?

The first thing to ask is what do you want to achieve? Do you want to implement algorithms you can’t find in regular photo manipulating programs? Do you want to batch process images? There are various different approaches here. If you want to batch process images, for example converting hundreds of images to another file format, or automatically generating histograms of images, then it is possible to learn some basic scripting, and use existing image manipulation programs such as ImageMagick. If you want to write heavier algorithms, for example some fancy new Instagram-like filter, then you will have to learn how to program using a programming language.

2. To program you need to understand algorithms

Programming of course is not a trivial thing, as much as people like to make it sound easy. It is all about taking an algorithm, which is a precise description of a method for solving a problem, and translating it into a program using a programming language. The algorithms can already exist, or they can be created from scratch. For example, a Clarendon-like (Instagram) image filter can be reproduced with the following algorithm (shown visually below):

  1. Read in an image from file.
  2. Add a blue tint to the image by blending it with a blue image of the same size (e.g. R=127, G=187, B=227, opacity = 20%).
  3. Increase the contrast of the image by 20%.
  4. Increase the saturation of the image by 35%.
  5. Save the new Clarendon-like filtered image in a new file.
A visual depiction of the algorithm for a Clarendon filter-like effect

To reproduce any of these tasks, we need to have an understanding of how to translate the algorithm into a program using a programming language, which is not always a trivial task. For example to perform the task of increasing the saturation of an image, we have to perform a number of steps:

  1. Convert the image to a colour model which allows saturation to be easily modified, for example HSI, which has three component layers: Hue, Saturation, and Intensity.
  2. Increase in saturation by manipulating the Saturation layer, i.e. multiplying all values by 1.2.
  3. Convert the image from HSI back to RGB.

Each of these tasks in turn requires additional steps. You can see this could become somewhat long-winded if the algorithm is complex.

3. To implement algorithms you need a programming language

The next trick is the programming language. Most people don’t really want to get bogged down in programming because of the idiosyncrasies of programming languages. But in order to convert an algorithm to a program, you have to choose a programming language, and learn how to code in it.

There are many programming languages, some are old, some are new. Some are easier to use than others. Novice programmers often opt for a language such as Python which is easy to learn, and offers a wide array of existing libraries or algorithms. The trick with programming is that you don’t necessarily want to reinvent the wheel. You don’t want to have to implement an algorithm that already exists. That’s why programming languages provide functions like sqrt() and log(), so people don’t have to implement them. For example, Akiomi Kamakura has already created a Python library called Pilgram, which contains a series of mimicked Instragram filters (26 of them), some CSS filters, and blend modes. So choosing Python means that you don’t have to build these from scratch, if anything they might provide inspiration to build your own filters. For example the following Python program uses Pilgram to apply the Clarendon filter to a JPG image:

from PIL import Image
import pilgram
import os

inputfile = input('Enter image filename (jpg): ')
base = os.path.splitext(inputfile)[0]
outputfile = base + '-clarendon.jpg'
print(base)
print(outputfile)

im = Image.open(inputfile)
pilgram.clarendon(im).save(outputfile)

The top part of the program imports the libraries, the middle portion deals with obtaining the filename of the image to be processed, and producing an output filename, and the last two lines actually open the image, process it with the filter, and save the filtered image. Fun right? But you still have to learn how to code in Python. Python comes with it’s own baggage (like dependencies, and being uber slow), but overall it is still a solid language, and easy to learn for novices. There are also other computer vision/image processing libraries such as scikit-image, SimpleCV and OpenCV. And in reality that is the crux here, programming for beginners.

If you really want to program in a more “complex” language, like C or C++ there is often a much steeper learning curve, and fewer libraries. I would not advocate for a fledgling programmer to learn any C-based language, only because it will result in being bogged down by the language itself. For the individual hell-bent on learning one of these languages I would suggest Fortran. Fortran was the first high-level programming language, introduced in 1957, however it has evolved, and modern Fortran is easy to learn, and use. It doesn’t come with much in the way of image processing libraries, but if you persevere you can build them.