I have a collection of 160 photos that I would like to montage into a movie. Each photo was done on a different day and the brightness of each photo varies. This will definitely not look good on the photo, so I’ve decided to “normalize” the brightness across the images. That is:

  • Find a value for average brightness of my images.
  • Brighten those too dark, and darken those that are too bright. Contrast should also be adjusted.

Calculate average image brightness

I have used utility called identify from ImageMagick package

% identify -format "%[mean] %f\n" *JPG | sort -rn 
44153.8 2011.06.22.JPG
37955.8 2011.06.11.JPG
#...many more...
23019.2 2011.06.01.JPG
21256.8 2011.06.06.JPG

-format option allows for specifying what kind of information about the image we want to output. In this case I went for average brightness – %[mean] and filename – %f, see the full documentation if you’re interested in other possibilities.

The difference between top and bottom photos is quite big: 21256.8 for 2011.06.06.JPG and 44153.8 for 2011.06.22.JPG – see the photos below.

Now let’s calculate the average value of brightness – awk to the rescue!

% identify  -format "%[mean] %f\n" *JPG | sort -rn | awk 'BEGIN {FS=" "} { sum += $1; } END { printf "%s",sum/NR}' 

Equalize the brightness

So I need to bring all the photos to the mean brightness of about 29481.9. The best option I’ve found to do that is to use -sigmoidal-contrast from ImageMagick. I don’t know what values for -sigmoidal-contrast I need to use, to get from one brightness to another, so I wrote a simple script that will try to do that using binary search algorithm. It’s really very quick & dirty script but it does the job. The main loop is as follows:

do {
$current = ($min + $max) / 2;
$brightness = adjust($current, $file);
$diff = $target - $brightness;
if($diff > 0) {
//we need to make it lighter
$min = $current;
} else {
//we need to make it darker
$max = $current;
} while(abs($diff) > 200);

adjust function basically calls external convert utility to perform the adjustment:

convert $file -sigmoidal-contrast '$value,0%' $tmpfile

and then checks and returns the brightness after conversion. I use -sigmoidal-contrast option to increase brightness and +sigmoidal-contrast to decrease. Now, that’s much better:

Here is the complete script – as I’ve said: quick & dirty job.