Image processing experiments (2) - Bash/ImageMagick

Filed under: bash, programming

TL;DR My bash version of the image processing experiments that I did in three languages is by far the shortest. Find the source code in this repository: spitzfaust/image-processing-experiments

The introduction to the image processing experiments can be found in my first article of the series.

Just to recall the program should do the following:

  1. Read in an image as the first argument passed to it on the command line.
  2. Print the file path, width and height of the image to the console.
  3. Display the original image and a blurred version of the image.
  4. Convert the image to grayscale and save it besides the original image as gray-IMAGENAME.

After implementing a solution in Rust I decided to look into Bash and ImageMagick which led to the following script.

magick identify -format "Using image file: %f, width %w, height %h\n" "${1}"
magick convert "${1}" -blur 0x5 - | \
magick montage -geometry +1+1 "${1}" - - | \
magick display&
magick convert "${1}" -colorspace gray \
-set filename:f "%d/gray-%f" "%[filename:f]"

The first thing in this Bash script is the so called shebang #!/bin/bash. This combination of a number sign and an exclamation mark which is followed by a path and optionally arguments is used by the operating system to determine the interpreter that should execute the script. In my case I want to execute the script with Bash and my Bash executable can be called via /bin/bash.

In my script I am executing a series of ImageMagick magick commands that use the first parameter $1 passed to the script as image path. The zero parameter $0 would return the name of the script. To access the value of the $1 parameter I use the ${1} syntax instead of just accessing the variable via $1 because it prevents errors if variables are used inside of strings.

ImageMagick provides the identify command which can extract information from an image. The -format flag can be used to customize which values are returned and how they are printed to the console.

In the third line (continued via \ for readability) the input image gets blurred, combined with the original image, and then displayed. The convert and montage commands do not write the generated image to a file but instead output the image to stdout via the - parameter. By using pipes | the output of one command is passed to the input of the next command. Another operator that is used at the end of the line is the ampersand & operator. This operator instructs the shell to fork an asynchronous sub-shell which executes the command while the parent-shell continues to execute the rest of the script. By using this operator the script is not waiting on the display command but goes on to execute the last line of the script.

By using the mighty convert command the image can be easily converted to grayscale. The -set parameter allows the creation of a template that is used to determine the output file path and name by combining the original directory %d with the original file name %f. Therefore the grayscale image will be saved besides the original image but with the filename prefixed with gray-.

In this article I wrote about some features of Bash and ImageMagick. Hopefully you found it interesting. The next article of this series will discuss my solution in F#. The source code for all the implementations can be found in this repository: spitzfaust/image-processing-experiments.