# Python Course

Previous Chapter: Contour Plots
Next Chapter: Image Processing Techniques

## Image Processing

### Introduction

It has never as easy as it is nowadays to take a picture. All it usually needs is a mobile phone. These are the bare essentials to shoot and to view an image. Taking a photograph is free, if we don't take the costs for the mobile phone into considerations. Just a generation ago, hobby artists and real artists needed special and often expensive and the costs per picture were far from being free.

We take pictures to preserve great moments in time. Pickled memories ready to be "opened" in the future at will.

Similar to pickling things, we have to pay attention to the right preservatives. Of course, mobile phone also provide us with a range of image processing software, but as soon as we need to manipulate a huge quantity of photographs we need other tools. This is when programming and Python comes into play. Python and its modules like Numpy, Scipy, Matplotlib and other special modules provide the optimal functionality to be able to cope with the flood of pictures.

To provide you with the necessary knowledge this chapter of our Python tutorial deals with basic image processing and manipulation. For this purpose we use the modules NumPy, Matplotlib and SciPy.

We start with the scipy package misc. The helpfile says that scipy.misc contains "various utilities that don't have another home".

    # the following line is only necessary in Python notebook:
    %matplotlib inline
    from scipy import misc
    lena = misc.lena()
    import matplotlib.pyplot as plt
    plt.gray()
    plt.imshow(lena)
    plt.show()

Additionally to the image, we can see the axis with the ticks. This may be very interesting, if you need some orientations about the size and the pixel position, but in most cases, you want to see the image without this information. We can get rid of the ticks and the axis by adding the command `plt.axis("off")`:

    from scipy import misc
    lena = misc.lena()
    import matplotlib.pyplot as plt
    plt.axis("off") # removes the axis and the ticks
    plt.gray()
    plt.imshow(lena)
    plt.show()

We can see that the type of this image is an integer array:

    lena.dtype

The above code returned the following:

    dtype('int64')

We can also check the size of the image:

    lena.shape

The previous Python code returned the following result:

    (512, 512)

The misc package contains an image of a racoon as well:

    import scipy.misc
    face = scipy.misc.face()
    print(face.shape)
    print(face.max)
    print(face.dtype)
    plt.axis("off")
    plt.gray()
    plt.imshow(face)
    plt.show()

This gets us the following output:

    (768, 1024, 3)
    <built-in method max of numpy.ndarray object at 0x2ca42b0>
    uint8

    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg

Only png images are supported by matplotlib

    img=mpimg.imread('frankfurt.png')

    print(img[:3])

After having executed the Python code above we received the following result:

    [[[ 0.41176471  0.56862748  0.80000001]
      [ 0.40392157  0.56078434  0.79215688]
      [ 0.40392157  0.56862748  0.79607844]
      ...,
      [ 0.48235294  0.62352943  0.81960785]
      [ 0.47843137  0.627451    0.81960785]
      [ 0.47843137  0.62352943  0.82745099]]
     [[ 0.40784314  0.56470591  0.79607844]
      [ 0.40392157  0.56078434  0.79215688]
      [ 0.40392157  0.56862748  0.79607844]
      ...,
      [ 0.48235294  0.62352943  0.81960785]
      [ 0.47843137  0.627451    0.81960785]
      [ 0.48235294  0.627451    0.83137256]]
     [[ 0.40392157  0.56862748  0.79607844]
      [ 0.40392157  0.56862748  0.79607844]
      [ 0.40392157  0.56862748  0.79607844]
      ...,
      [ 0.48235294  0.62352943  0.81960785]
      [ 0.48235294  0.62352943  0.81960785]
      [ 0.48627451  0.627451    0.83137256]]]

    plt.axis("off")
    imgplot = plt.imshow(img)

    lum_img = img[:,:,1]
    print(lum_img)

The Python code above returned the following:

    [[ 0.56862748  0.56078434  0.56862748 ...,  0.62352943  0.627451
       0.62352943]
     [ 0.56470591  0.56078434  0.56862748 ...,  0.62352943  0.627451    0.627451  ]
     [ 0.56862748  0.56862748  0.56862748 ...,  0.62352943  0.62352943
       0.627451  ]
     ...,
     [ 0.31764707  0.32941177  0.32941177 ...,  0.30588236  0.3137255
       0.31764707]
     [ 0.31764707  0.3137255   0.32941177 ...,  0.3019608   0.32156864
       0.33725491]
     [ 0.31764707  0.3019608   0.33333334 ...,  0.30588236  0.32156864
       0.33333334]]

    plt.axis("off")
    imgplot = plt.imshow(lum_img)

### Tint, Shade and Tone

Now, we will show how to tint an image. Tint is an expression from colour theory and an often used technique by painters. Thinking about painters and not think about the Netherlands is hard to imagine. So we will use a picture with Dutch windmills in our next example. (The image has been taken at Kinderdijk, a village in the Netherlands, about 15 km east of Rotterdam and about 50 kilometres from Den Haag (The Hague). It's a UNESCO World Heritage Site since 1997.)

    windmills = mpimg.imread('windmills.png')
    plt.axis("off")
    plt.imshow(windmills)
    plt.imshow(windmills)

The above Python code returned the following output:

    <matplotlib.image.AxesImage at 0x7f81410ba9e8>

We want to tint the image now. This means we will "mix" our colours with white. This will increase the lightness of our image. For this purpose, we write a Python function, which takes an image and a percentage value as a parameter. Setting 'percentage' to 0 will not change the image, setting it to one means that the image will be completely whitened:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    def tint(imag, percent):
        """
        imag: the image which will be shaded
        percent: a value between 0 (image will remain unchanged
                 and 1 (image will completely white)
        """
        tinted_imag = imag + (np.ones(imag.shape) - imag) * percent
        return tinted_imag
    windmills = mpimg.imread('windmills.png')
    tinted_windmills = tint(windmills, 0.8)
    plt.axis("off")
    plt.imshow(tinted_windmills)
    plt.imshow(tinted_windmills)

The above Python code returned the following output:

    <matplotlib.image.AxesImage at 0x7f81412718d0>

A shade is the mixture of a color with black, which reduces lightness.

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    def shade(imag, percent):
        """
        imag: the image which will be shaded
        percent: a value between 0 (image will remain unchanged
                 and 1 (image will be blackened)
        """
        tinted_imag = imag * (1 - percent)
        return tinted_imag
    windmills = mpimg.imread('windmills.png')
    tinted_windmills = shade(windmills, 0.7)
    plt.imshow(tinted_windmills)

The previous code returned the following output:

    <matplotlib.image.AxesImage at 0x7f814124a128>

    def vertical_gradient_line(image, reverse=False):
        """
        We create a horizontal gradient line with the shape (1, image.shape[1], 3))
        The values are incremented from 0 to 1, if reverse is False,
        otherwise the values are decremented from 1 to 0.
        """
        number_of_columns = image.shape[1]
        if reverse:
            C = np.linspace(1, 0, number_of_columns)
        else:
            C = np.linspace(0, 1, number_of_columns)
        C = np.dstack((C, C, C))
        return C
    horizontal_brush = vertical_gradient_line(windmills)
    tinted_windmills =  windmills * horizontal_brush
    plt.axis("off")
    plt.imshow(tinted_windmills)

This gets us the following result:

    <matplotlib.image.AxesImage at 0x7f8141221cc0>

We will tint the image now from right to left by setting the reverse parameter of our Python function to "True":

    def vertical_gradient_line(image, reverse=False):
        """
        We create a horizontal gradient line with the shape (1, image.shape[1], 3))
        The values are incremented from 0 to 1, if reverse is False,
        otherwise the values are decremented from 1 to 0.
        """
        number_of_columns = image.shape[1]
        if reverse:
            C = np.linspace(1, 0, number_of_columns)
        else:
            C = np.linspace(0, 1, number_of_columns)
        C = np.dstack((C, C, C))
        return C
    horizontal_brush = vertical_gradient_line(windmills, reverse=True)
    tinted_windmills =  windmills * horizontal_brush
    plt.axis("off")
    plt.imshow(tinted_windmills)

This gets us the following result:

    <matplotlib.image.AxesImage at 0x7f81412119e8>

    def horizontal_gradient_line(image, reverse=False):
        """
        We create a vertical gradient line with the shape (image.shape[0], 1, 3))
        The values are incremented from 0 to 1, if reverse is False,
        otherwise the values are decremented from 1 to 0.
        """
        number_of_rows, number_of_columns = image.shape[:2]
        C = np.linspace(1, 0, number_of_rows)
        C = C[np.newaxis,:]
        C = np.concatenate((C, C, C)).transpose()
        C = C[:, np.newaxis]
        return C
    vertical_brush = horizontal_gradient_line(windmills)
    tinted_windmills =  windmills
    plt.imshow(tinted_windmills)
    plt.imshow(tinted_windmills)

The above Python code returned the following:

    <matplotlib.image.AxesImage at 0x7f81411199e8>

A tone is produced either by the mixture of a color with gray, or by both tinting and shading.

    charlie = mpimg.imread('Chaplin.png')
    plt.gray()
    print(charlie)
    plt.imshow(charlie)

The above Python code returned the following output:

    [[ 0.16470589  0.16862746  0.17647059 ...,  0.          0.          0.        ]
     [ 0.16078432  0.16078432  0.16470589 ...,  0.          0.          0.        ]
     [ 0.15686275  0.15686275  0.16078432 ...,  0.          0.          0.        ]
     ...,
     [ 0.          0.          0.         ...,  0.          0.          0.        ]
     [ 0.          0.          0.         ...,  0.          0.          0.        ]
     [ 0.          0.          0.         ...,  0.          0.          0.        ]]

The code above returned the following:

    <matplotlib.image.AxesImage at 0x7f81407788d0>

    colored = np.dstack((charlie*0.1, charlie*1, charlie*0.5))
    plt.imshow(colored)

The Python code above returned the following:

    <matplotlib.image.AxesImage at 0x7f814075e940>

tinting gray scale images: http://scikit-image.org/docs/dev/auto_examples/plot_tinting_grayscale_images.html

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    charlie = mpimg.imread('Chaplin.png')
    #  colormaps plt.cm.datad
    cmaps = set(plt.cm.datad.keys())
    X = [  (4,3,1, (1, 0, 0)), (4,3,2, (0.5, 0.5, 0)), (4,3,3, (0, 1, 0)),
           (4,3,4, (0, 0.5, 0.5)),  (4,3,(5,8), (0, 0, 1)), (4,3,6, (1, 1, 0)),
           (4,3,7, (0.5, 1, 0) ),               (4,3,9, (0, 0.5, 0.5)),
           (4,3,10, (0, 0.5, 1)), (4,3,11, (0, 1, 1)),    (4,3,12, (0.5, 1, 1))]
    fig = plt.figure(figsize=(6, 5))
    #fig.subplots_adjust(bottom=0, left=0, top = 0.975, right=1)
    for nrows, ncols, plot_number, factor in X:
        sub = fig.add_subplot(nrows, ncols, plot_number)
        sub.set_xticks([])
        plt.colors()

        sub.imshow(charlie*0.0002, cmap=cmaps.pop())
        sub.set_yticks([])
    #fig.show()

### Creating Watermark

Previous Chapter: Contour Plots
Next Chapter: Image Processing Techniques