Python Multimedia: Enhancing Images


Python Multimedia

Python Multimedia

Learn how to develop Multimedia applications using Python with this practical step-by-step guide

  • Use Python Imaging Library for digital image processing.
  • Create exciting 2D cartoon characters using Pyglet multimedia framework
  • Create GUI-based audio and video players using QT Phonon framework.
  • Get to grips with the primer on GStreamer multimedia framework and use this API for audio and video processing.


        Read more about this book      

(For more resources on Python, see here.)

Adjusting brightness and contrast

One often needs to tweak the brightness and contrast level of an image. For example, you may have a photograph that was taken with a basic camera, when there was insufficient light. How would you correct that digitally? The brightness adjustment helps make the image brighter or darker whereas the contrast adjustments emphasize differences between the color and brightness level within the image data. The image can be made lighter or darker using the ImageEnhance module in PIL. The same module provides a class that can auto-contrast an image.

Time for action – adjusting brightness and contrast

Let's learn how to modify the image brightness and contrast. First, we will write code to adjust brightness. The ImageEnhance module makes our job easier by providing Brightness class.

  1. Download image 0165_3_12_Before_BRIGHTENING.png and rename it to Before_BRIGHTENING.png.
  2. Use the following code:
    1 import Image
    2 import ImageEnhance
    4 brightness = 3.0
    5 peak = "C:\\images\\Before_BRIGHTENING.png ")
    6 enhancer = ImageEnhance.Brightness(peak)
    7 bright = enhancer.enhance(brightness)
    8 "C:\\images\\BRIGHTENED.png ")
  3. On line 6 in the code snippet, we created an instance of the class Brightness. It takes Image instance as an argument.
  4. Line 7 creates a new image bright by using the specified brightness value. A value between 0.0 and less than 1.0 gives a darker image, whereas a value greater than 1.0 makes it brighter. A value of 1.0 keeps the brightness of the image unchanged.
  5. The original and resultant image are shown in the next illustration.
    Comparison of images before and after brightening.

    Python Multimedia

  6. Let's move on and adjust the contrast of the brightened image. We will append the following lines of code to the code snippet that brightened the image.
    10 contrast = 1.3
    11 enhancer = ImageEnhance.Contrast(bright)
    12 con = enhancer.enhance(contrast)
    13 "C:\\images\\CONTRAST.png ")
  7. Thus, similar to what we did to brighten the image, the image contrast was tweaked by using the ImageEnhance.Contrast class. A contrast value of 0.0 creates a black image. A value of 1.0 keeps the current contrast.
  8. The resultant image is compared with the original in the following illustration.
    The original image with the image displaying the increasing contrast.

    Python Multimedia

  9. In the preceding code snippet, we were required to specify a contrast value. If you prefer PIL for deciding an appropriate contrast level, there is a way to do this. The ImageOps.autocontrast functionality sets an appropriate contrast level. This function normalizes the image contrast. Let's use this functionality now.
  10. Use the following code:
    import ImageOps
    bright = "C:\\images\\BRIGHTENED.png ")
    con = ImageOps.autocontrast(bright, cutoff = 0)
  11. The highlighted line in the code is where contrast is automatically set. The autocontrast function computes histogram of the input image. The cutoff argument represents the percentage of lightest and darkest pixels to be trimmed from this histogram. The image is then remapped.

What just happened?

Using the classes and functionality in ImageEnhance module, we learned how to increase or decrease the brightness and the contrast of the image. We also wrote code to auto-contrast an image using functionality provided in the ImageOps module.

Tweaking colors

Another useful operation performed on the image is adjusting the colors within an image. The image may contain one or more bands, containing image data. The image mode contains information about the depth and type of the image pixel data. The most common modes we will use are RGB (true color, 3x8 bit pixel data), RGBA (true color with transparency mask, 4x8 bit) and L (black and white, 8 bit).

In PIL, you can easily get the information about the bands data within an image. To get the name and number of bands, the getbands() method of the class Image can be used. Here, img is an instance of class Image.

>>> img.getbands()
('R', 'G', 'B', 'A')

Time for action – swap colors within an image!

To understand some basic concepts, let's write code that just swaps the image band data.

  1. Download the image 0165_3_15_COLOR_TWEAK.png and rename it as COLOR_TWEAK.png.
  2. Type the following code:
    1 import Image
    3 img = "C:\\images\\COLOR_TWEAK.png ")
    4 img = img.convert('RGBA')
    5 r, g, b, alpha = img.split()
    6 img = Image.merge( "RGBA ", (g, r, b, alpha))
  3. Let's analyze this code now. On line 2, the Image instance is created as usual. Then, we change the mode of the image to RGBA.

    Here we should check if the image already has that mode or if this conversion is possible. You can add that check as an exercise!

  4. Next, the call to Image.split() creates separate instances of Image class, each containing a single band data. Thus, we have four Image instances—r, g, b, and alpha corresponding to red, green, and blue bands, and the alpha channel respectively.
  5. The code in line 6 does the main image processing. The first argument that Image.merge takes mode as the first argument whereas the second argument is a tuple of image instances containing band information. It is required to have same size for all the bands. As you can notice, we have swapped the order of band data in Image instances r and g while specifying the second argument.
  6. The original and resultant image thus obtained are compared in the next illustration. The color of the flower now has a shade of green and the grass behind the flower is rendered with a shade of red.

    Please download and refer to the supplementary PDF file Chapter 3 Supplementary Material.pdf. Here, the color images are provided that will help you see the difference.

    Original (left) and the color swapped image (right).

    Python Multimedia

What just happened?

We accomplished creating an image with its band data swapped. We learned how to use PIL's Image.split() and Image.merge() to achieve this. However, this operation was performed on the whole image. In the next section, we will learn how to apply color changes to a specific color region.

Changing individual image band

In the previous section, we saw how to change the data represented by the whole band. As a result of this band swapping, the color of the flower was changed to a shade of green and the grass color was rendered as a shade of red. What if we just want to change the color of the flower and keep the color of the grass unchanged? To do this, we will make use of Image.point functionality along with Image.paste operation.

However, note that we need to be careful in specifying the color region that needs to be changed. It may also depend on the image. Sometimes, it will select some other regions matching the specified color range, which we don't want.

Time for action – change the color of a flower

We will make use of the same flower image used in the previous section. As mentioned earlier, our task is to change the color of the flower while keeping the grass color unchanged.

  1. Add this code in a Python source file.
    1 import Image
    3 img = "C:\\images\\COLOR_TWEAK.png ")
    4 img = img.convert('RGBA')
    5 r, g, b, alpha = img.split()
    6 selection = r.point(lambda i: i > 120 and 150)
    7 "C:\\images\\COLOR_BAND_MASK.png ")
    8 r.paste(g, None, selection)
    9 img = Image.merge( "RGBA ", (r, g, b, alpha))
    10 "C:\\images\\COLOR_CHANGE_BAND.png ")
  2. Lines 1 to 5 remain the same as seen earlier. On line 5, we split the original image, creating four Image instances, each holding a single band data.
  3. A new Image instance 'selection' is created on line 6. This is an important operation that holds the key to selectively modify color! So let's see what this line of code does. If you observe the original image, the flower region (well, most of it) is rendered with a shade of red color. So, we have called the point(function) method on Image instance r. The point method takes a single function and an argument maps the image through this function. It returns a new Image instance.
  4. What does this lambda function on line 6 do? Internally, PIL's point function does something of this sort:
    lst = map(function, range(256)) * no_of_bands

    In this example, function is nothing but the lambda function. The no_of_bands for the image is 1. Thus, line 6 is used to select a region where the red value is greater than 120. The lst is a list which, in this case has the first 120 values as False whereas the remaining values as 150. The value of 150 plays a role in determining the final color when we perform the paste operation.

  5. The image mask thus created after the application of point operation is shown in the following illustration. The white region in this image represents the region captured by the point operation that we just performed. Only the white region will undergo change when we perform paste operation next.

    Python Multimedia

  6. On line 8, we perform a paste operation. Here, the image g is pasted onto image r using mask selection. As a result, the band data of image r is modified.
  7. Finally, a new Image instance is created using the merge operation, by making use of the individual r, g, b, and alpha image instances containing the new band information.
  8. The original and final processed images are compared in the next illustration. The new flower color looks as cool as the original color, doesn't it?

Python Multimedia

What just happened?

We worked out an example that modified a selective color region. Individual image band data was processed to accomplish this task. With the help of point, paste, and merge operations in PIL's Image module, we accomplished changing the color of the flower in the provided image.

Gray scale images

If you want to give a nostalgic effect to an image, one of the many things that you can do is to convert it to gray scale. There is more than one way to create a gray scale image in PIL. When the mode is specified as L, the resultant image is gray scale. The basic syntax to convert color images to black and white is:

img = img.convert('L')

Alternatively, we can use functionality provided in the ImageOps module.

img = ImageOps.grayscale(img)

If you are creating the image from scratch, the syntax is:

img ='L', size)

The following illustration shows the original and the converted gray scale images created using one of these techniques.

Original and gray scale images of a bridge:

Python Multimedia

Cook up negatives

Creating a negative of an image is straightforward. We just need to invert each color pixel. Therefore, if you have a color x at a pixel, the negative image will have (255 – x) at that pixel. The ImageOps module makes it very simple. The following line of code creates a negative of an image.

img = ImageOps.invert(img)

Here is the result of this operation:

Original image (left) and its negative (right).

Python Multimedia


In this article we learnt some image enhancement techniques. With the help of ample examples, we learned how to adjust the color, brightness, and contrast of an image.

Further resources on this subject:

You've been reading an excerpt of:

Python Multimedia

Explore Title