XLA_LT TT
XLA_LT TT
THEORIES...................................................................................................................................4
1.1. Image processing.............................................................................................................4
1.1.1. What is image processing?.......................................................................................4
1.1.2. Purposes....................................................................................................................4
1.1.3. Intro to scikit-image.................................................................................................4
1.1.4. What is an image?....................................................................................................4
1.1.5. Images in scikit-image..............................................................................................5
1.1.6. RGB channels...........................................................................................................5
1.1.7. Grayscaled images....................................................................................................5
1.1.8. RGB vs Grayscale....................................................................................................5
1.1.9. Visualizing images in the course..............................................................................6
1.2. NumPy for images...........................................................................................................7
1.2.1. NumPy for images....................................................................................................7
1.2.2. Images as NdArrays.................................................................................................7
1.2.3. Colors with NumPy..................................................................................................7
1.2.4. Shapes and size.........................................................................................................8
1.2.5. Flipping images........................................................................................................9
1.2.6. What is a histogram?................................................................................................9
1.2.7. Color histograms......................................................................................................9
1.2.8. Applications of histograms.....................................................................................10
1.2.9. Histograms in Matplotlib........................................................................................10
1.3. Thresholding..................................................................................................................11
1.3.1. Thresholding...........................................................................................................11
1.3.2. Categories...............................................................................................................12
1.3.3. Try more thresholding algorithms..........................................................................12
1.3.4. Optimal thresh value...............................................................................................13
EXERCISE:................................................................................................................................15
Exercise 1:...............................................................................................................................15
Exercise 2: RGB to Grayscale.................................................................................................16
Exercise 3: Flipping out.............................................................................................................17
Exercise 4: Histograms..............................................................................................................18
Exercise 5: Apply global thresholding....................................................................................19
Exercise 6: When the background isn't that obvious...............................................................20
Exercise 7: Trying other methods............................................................................................21
Exercise 8: Apply thresholding...............................................................................................22
1
CHAPTER 2. FILTERS.............................................................................................................24
THEORIES:................................................................................................................................24
Filtering...................................................................................................................................24
2.1. Filters.............................................................................................................................24
2.1.1. Neighborhoods.......................................................................................................24
2.1.2. Edge detection........................................................................................................24
2.1.3. Comparing plots.....................................................................................................25
2.1.4. Gaussian smoothing................................................................................................26
2.2. Contrast.........................................................................................................................27
2.2.1. Contrast enhancement............................................................................................27
2.2.2. Contrast...................................................................................................................28
2.2.3. Enhance contrast.....................................................................................................28
2.2.4. Histogram equalization...........................................................................................29
2.2.5. Adaptive Equalization............................................................................................30
2.2.6. Contrastive Limited Adaptive Equalization...........................................................30
2.2.7. CLAHE in scikit-image..........................................................................................31
2.3. Transformations............................................................................................................31
2.3.1. Why transform images?..........................................................................................31
2.3.2. Rotating..................................................................................................................32
2.3.3. Rescaling................................................................................................................33
2.3.4. Aliasing in digital images.......................................................................................33
2.3.5. Resizing..................................................................................................................34
2.4. Morphology:..................................................................................................................36
2.4.1. Binary images.........................................................................................................36
2.4.2. Morphological filtering..........................................................................................36
2.4.3. Morphological operations.......................................................................................36
2.4.4. Structuring element................................................................................................36
2.4.5. Shapes in scikit-image............................................................................................37
2.4.6. Erosion in scikit-image...........................................................................................37
2.4.7. Dilation in scikit-image..........................................................................................38
EXERCISE:................................................................................................................................39
Exercise 1: Edge detection......................................................................................................39
Exercise 2: Blurring to reduce noise.............................................................................................40
Exercise 3:...............................................................................................................................42
Exercise 4: Medical images.....................................................................................................42
Exercise 5: Aerial image............................................................................................................43
Exercise 6: Let's add some impact and contrast......................................................................44
Exercise 7: Aliasing, rotating and rescaling............................................................................46
Exercise 8: Enlarging images..................................................................................................46
Exercise 9: Proportionally resizing.........................................................................................48
Exercise 10: Morphology........................................................................................................49
Exercise 11: Improving thresholded image.............................................................................50
2
CHAPTER 3. IMAGE RESTORATION...................................................................................51
THEORIES.................................................................................................................................51
3.1. Image restoration...........................................................................................................51
3.1.1. Restore an image....................................................................................................51
3.1.2. Image reconstruction..............................................................................................51
3.1.3. Masks......................................................................................................................53
3.2. Noise..............................................................................................................................54
3.2.1. Noise.......................................................................................................................54
3.2.2. Apply noise in scikit-image:...................................................................................55
3.2.3. Reducing noise.......................................................................................................55
3.3. Superpixels & segmentation..........................................................................................57
3.3.1. Segmentation..........................................................................................................57
3.3.2. Image representation..............................................................................................58
3.3.3. Superpixels.............................................................................................................59
3.3.4. Segmentation..........................................................................................................59
3.3.5. Unsupervised segmentation....................................................................................59
3.4. Finding contours............................................................................................................61
3.4.1. Finding contours.....................................................................................................61
3.4.2. Find contours using scikit-image............................................................................62
3.4.3. Constant level value...............................................................................................63
3.4.4. The steps to spotting contours................................................................................63
3.4.5. A contour's shape....................................................................................................64
EXERCISE.................................................................................................................................64
Exercise 1: restore a damaged image......................................................................................64
Exercise 2: Removing logos.......................................................................................................65
Exercise 3: Noise.....................................................................................................................66
Exercise 4: Reducing noise........................................................................................................67
Exercise 5: Reducing noise while preserving edges........................................................................68
Exercise 6: Number of pixels......................................................................................................69
Exercise 7: Superpixel segmentation............................................................................................70
Exercise 8: Contouring shapes....................................................................................................71
Exercise 9: Find contours of an image that is not binary..................................................................72
Exercise 10: Count the dots in a dice's image................................................................................72
THEORIES:................................................................................................................................74
4.1. Finding the edges with Canny.......................................................................................74
4.1.1. Detecting edges......................................................................................................74
4.1.2. Edge detection........................................................................................................74
4.1.3. Canny edge detector...............................................................................................75
4.2. Right around the corner.................................................................................................76
4.2.1. Corner detection.....................................................................................................76
3
4.2.2. Points of interest.....................................................................................................76
4.2.3. Corners...................................................................................................................77
4.2.4. Matching corners....................................................................................................77
4.2.5. Harris corner detector.............................................................................................78
4.3. Face detection................................................................................................................80
4.3.1. Face detection use cases.........................................................................................80
4.3.2. Detecting faces with scikit-image..........................................................................81
4.3.3. Let's try detecting faces..........................................................................................81
4.4. Real-world applications.................................................................................................84
4.4.1. Applications............................................................................................................84
4.4.2. Privacy protection...................................................................................................84
4.4.3. More cases..............................................................................................................87
EXERCISE:................................................................................................................................87
Exercise 1: Finding the edges with Canny..............................................................................87
Exercise 2: Less edgy................................................................................................................88
Exercise 3:...............................................................................................................................89
Exercise 4: Less corners.............................................................................................................91
Exercise 5: Face detection.......................................................................................................92
Exercise 6: Multiple faces..........................................................................................................93
Exercise 7: Segmentation and face detection..........................................................................94
Exercise 8: Privacy protection.................................................................................................96
Exercise 9: Help Sally restore her graduation photo...............................................................97
4
CHAPTER 1. MAKE IMAGES COME ALIVE WITH SCIKITIMAGE
THEORIES
1.1. Image processing
1.1.1. What is image processing?
1.1.2. Purposes
The purpose of image processing can be divided into five groups. Visualization: observe
objects that are not visible. Image sharpening and restoration: to create a better image. Image
retrieval: to seek for the image of interest. Measurement of pattern: to measure objects. And
Image Recognition: to distinguish objects in an image
Let's get started with images! A digital image is an array, or a matrix, of square pixels
(picture elements) arranged in columns and rows: in other words, a 2-dimensional matrix.
These pixels contain information about color and intensity. Here's an example of the
matrix for a 2D grayscale image. Here we can see that the first image is a pixelated image. The
numbers that we see on top of the following image next to the first one correspond to the
intensity of each pixel in the image. So at the end, an image can be treated as an intensities
matrix.
5
1.1.5. Images in scikit-image
There are some testing-purpose images provided by scikit-image, in a module called data.
If we want to load a colored image of a rocket, we can do so by: Importing data from skimage.
And then from data, call a method named rocket.
Code:
from skimage import data
rocket_image = data.rocket()
Grayscale images only have shades of black and white. Often, the grayscale intensity is
stored as an 8-bit integer giving 256 possible different shades of gray. Grayscale images don't
have any color information
6
1.1.8. RGB vs Grayscale
RGB images have three color channels, while grayscaled ones have a single channel. We
can convert an image with RGB channels into grayscale using the function rgb2gray() provided
in the color module. We can also turn grayscale to RGB using gray2rgb().
Code:
from skimage import color
grayscale = color.rgb2gray(original)
rgb = color.gray2rgb(grayscale)
During the course, we'll usually use a preloaded function called show image to display the
images using Matplotlib. This way we can focus on image processing code. This is what the
show image function looks like.
Code:
def show_image(image, title='Image', cmap_type='gray'):
plt.imshow(image, cmap=cmap_type)
plt.title(title)
plt.axis('off')
plt.show()
So if we want to show an image that we have converted to grayscale, we just need to pass
the image as the first parameter of the "show_image" function and the title "Grayscale" as the
second parameter. We will then see the image Grayscale displayed in the console output.
Code:
from skimage import color
grayscale = color.rgb2gray(original)
7
show_image(grayscale, "Grayscale")
With NumPy, we can practice simple image processing techniques, such as flipping
images, extracting features, and analyzing them.
Imagine that we have an image and we load it using matplotlib's imread() function. If you
check it's type, using the type() python function, you can see that is a numpy ndarray object.
Because images can be represented by NumPy multi-dimensional arrays (or "NdArrays"),
NumPy methods for manipulating arrays work well on these images
Code:
# Loading the image using Matplotlib
madrid_image = plt.imread('/madrid.jpeg')
type(madrid_image)
Remember that a color image is a NumPy array with an third dimension for color
channels. We can slice the multidimensional array and obtain these channels separately.
Here we can see the individual color intensities along the image. For example, we obtain
the red color of an image by keeping the height and width pixels and selecting only the values
of the first color layer. Here we use Matplotlib to display them with the default colormap. We
can observe the different intensities in their tone.
Code:
# Obtaining the red values of the image
red = image[: , : , 0]
# Obtaining the green values of the image
green = image[: , : , 1]
# Obtaining the blue values of the image
blue = image[: , : , 2]
8
We can also display them using the gray colormap, specifying it with the cmap attribute,
of the imshow function. We can still see the different intensities along the images, one for each
color. The red, green and blue.
Code:
plt.imshow(red, cmap="gray")
plt.title('Red')
plt.axis('off')
plt.show()
9
1.2.5. Flipping images
Vertically: We can flip the image vertically by using the flipud() method. We are using
the show_image() function to display an image.
Horizontally: You can flip the image horizontally using the fliplr() method.
Code:
# Flip the image in up direction
vertically_flipped = np.flipud(madrid_image)
show_image(vertically_flipped, 'Vertically flipped image')
10
1.2.7. Color histograms
We can also create histograms from RGB-3 colored images. In this case each channel:
red, green and blue will have a corresponding histogram.
We can learn a lot about an image by just looking at its histogram. Histograms are used to
threshold images (an important topic in computer vision that we will cover later in this course),
to alter brightness and contrast, and to equalize an image (which we will also cover later in this
course).
Matplotlib has a histogram method. It takes an input array (frequency) and bins as
parameters. The successive elements in bin array act as the boundary of each bin. We obtain
the red color channel of the image by slicing it. We then use the histogram function. Use ravel
to return a continuous flattened array from the color values of the image, in this case red. And
pass this ravel and the bins as parameters. We set bins to 256 because we'll show the number of
pixels for every pixel value, that is, from 0 to 255. Meaning you need 256 values to show the
histogram.
Visualizing histograms with Matplotlib: So to display it, once we obtain the blue color of
the image and use the hist method, by passing the array and the bins to put in the graphic. Plot
it using plt.show().
Code:
# Red color of the image
red = image[: , : , 0]
# Obtain the red histogram
plt.hist(red.ravel(), bins=256)
blue = image[: , : , 2]
plt.hist(blue.ravel(), bins=256)
plt.title('Blue Histogram')
11
plt.show()
1.3. Thresholding
1.3.1. Thresholding
12
Inverted thresholding: We can also apply inverted thresholding, which is just inverting
the color. We apply it just as we do in thresholding, except we use "<=" operator instead of
">". Here the resulting image is also binary but the background is black and foreground white.
Code:
# Obtain the optimal threshold value
thresh = 127
# Apply thresholding to the image
binary = image <= thresh
# Show the original and thresholded
show_image(image, 'Original')
show_image(inverted_binary,'Inverted
Thresholded')
1.3.2. Categories
What if I want to try more algorithms? Well scikit-image includes a function that
evaluates several global algorithms, so that you can choose the one that gives you best results:
the try_all_threshold function from filters module. Here we import it, use the function by
passing the image and set verbose to False so it doesn't print function name for each method.
And show results
Code:
from skimage.filters import try_all_threshold
13
# Obtain all the resulting images
fig, ax = try_all_threshold(image, verbose=False)
# Showing resulting plots
show_plot(fig, ax)
It will use seven global algorithms, so here we see first the original image followed by the
resulting images of the thresholding methods. We cover only the otsu. So this is a easy way the
rest!
When the background of an image seems uniform, global thresholding works best.
Previously, we arbitrarily set the thresh value, but we can also calculate the optimal value. For
that we import the threshold_otsu() function from filters module. Then obtain the optimal
global thresh value by calling this function. Apply the local thresh to the image. And that's it!
Code:
# Import the otsu threshold function
from skimage.filters import threshold_otsu
# Obtain the optimal threshold value
thresh = threshold_otsu(image)
# Apply thresholding to the image
binary_global = image > thresh
# Show the original and binarized image
show_image(image, 'Original')
show_image(binary_global, 'Global thresholding')
Let’s see the image
14
We see the resulting binarized image, next to the original to compare it. We see how the
optimal thresh is spotted by a red line in the histogram of the image.
If the image doesn't have high contrast or the background is uneven, local thresholding
produces better results. Import threshold_local(), also from filters. With this function, we
calculate thresholds in small pixel regions surrounding each pixel we are binarizing. So we
need to specify a block_size to surround each pixel; also known as local neighborhoods. And
an optional offset, that's a constant subtracted from the mean of blocks to calculate the local
threshold value. Here in the threshold_local function we set a block_size of 35 pixels and an
offset of 10. Then apply that local thresh.
Code:
# Import the local threshold function
from skimage.filters import threshold_local
# Set the block size to 35
block_size = 35
# Obtain the optimal local thresholding
local_thresh = threshold_local(text_image, block_size, offset=10)
# Apply local thresholding and obtain the binary image
binary_local = text_image > local_thresh
# Show the original and binarized image
show_image(image, 'Original')
show_image(binary_local, 'Local thresholding')
Showing the original and the resulting image, we can see it works well in this image that
has different lighting conditions.
15
EXERCISE:
Exercise 1:
Question: Whats the main difference between the images shown below?
These images have been preloaded as coffee_image and coins_image from the
scikit-image data module using:
coffee_image = data.coffee()
coins_image = data.coins()
Choose the right answer that best describes the main difference related to color and
dimensional structure.
In the console, use the function shape() from NumPy, to obtain the image shape
(Height, Width, Dimensions) and find out. NumPy is already imported as np.
Code
# Import the modules from skimage
from skimage import ____, ____
Instruction
Both have 3 channels for RGB-3 color representation
coffee_image has a shape of (303, 384), grayscale. And coins_image (400, 600, 3),
RGB-3
16
coins_image has a shape of (303, 384), grayscale. And coffee_image (400, 600,
3), RGB-3
Both are grayscale, with single color dimension
Code
Import the data and color modules from Scikit image. The first module provides
example images, and the second, color transformation functions.
Load the rocket image.
Convert the RGB-3 rocket image to grayscale.
As a prank, someone has turned an image from a photo album of a trip to Seville upside-
down and back-to-front! Now, we need to straighten the image, by flipping it.
Using the NumPy methods learned in the course, flip the image horizontally and
vertically. Then display the corrected image using the show_image() function.
NumPy is already imported as np.
Code
Exercise 4: Histograms
Question:
In this exercise, you will analyze the amount of red in the image. To do this, the
histogram of the red channel will be computed for the image shown below:
green = image[:, :, 1]
19
Code
In this exercise, you'll transform a photograph to binary so you can separate the
foreground from the background.
To do so, you need to import the required modules, load the image, obtain the optimal
thresh value using threshold_otsu() and apply it to the image.
You'll see the resulting binarized image when using the show_image() function,
previously explained.
20
Image loaded as chess_pieces_image.
Remember we have to turn colored images to grayscale. For that we will use the
rgb2gray() function learned in previous video. Which has already been imported for you.
Code
Sometimes, it isn't that obvious to identify the background. If the image background is
relatively uniform, then you can use a global threshold value as we practiced before,
using threshold_otsu(). However, if there's uneven background illumination, adaptive
thresholding threshold_local() (a.k.a. local thresholding) may produce better results.
21
In this exercise, you will compare both types of thresholding methods (global and local),
to find the optimal way to obtain the binary image we need.
Code
Import the otsu threshold function, obtain the optimal global thresh value of the image,
and apply global thresholding
Import the local threshold function, set block size to 35, obtain the local thresh value,
and apply local thresholding
As we saw in the video, not being sure about what thresholding method to use isn't a
problem. In fact, scikit-image provides us with a function to check multiple methods and see
for ourselves what the best option is. It returns a figure comparing the outputs of
different global thresholding methods.
22
Image loaded as fruits_image.
You will apply this function to this image, matplotlib.pyplot has been loaded
as plt. Remember that you can use try_all_threshold() to try multiple global
algorithms.
Code
23
In this exercise, you will decide what type of thresholding is best used to binarize an
image of knitting and craft tools. In doing so, you will be able to see the shapes of the objects,
from paper hearts to scissors more clearly.
What type of thresholding would you use judging by the characteristics of the image? Is
the background illumination and intensity even or uneven?
Code
24
CHAPTER 2. FILTERS
THEORIES:
In this new chapter we'll learn about filtering, contrast, transformations and morphology
Filtering
1.4. Filters
Filtering is a technique for modifying or enhancing an image. In essence, a filter is a
mathematical function that is applied to images. It can be used to emphasize or remove certain
features, like edges. Smoothing, sharpening and edge detection. In this video we will cover
smoothing and edge detection. Filtering is a neighborhood operation, lets see what that means.
1.4.1. Neighborhoods
So, with filtering we can detect edges. This technique can be used to find the boundaries
of objects within images. As well as segment and extract information like how many coins are
in an image. Most of the shape information of an image is enclosed in edges.
25
Edge detection works by detecting discontinuities in brightness. Like in this image, where
we spot the chocolate kisses shapes in the image.
A common edge detection algorithm is Sobel. This is a filter that we can find in scikit
image's module filters with the sobel function. The previously used coins image is preloaded as
image coins. We apply the filter by passing the image we want to detect the edges from as
parameter. This function requires a 2-dimensional grayscale image as input. So in the case of a
colored image, we'll need to convert it to grayscale first. Then, we show the original and the
resulting image with a function that uses Matplotlib subplots.
So we see that the filter is detecting the edges in the original image and highlighting the
boundaries as closed lines in the resulting image.
Code:
26
1.4.3. Comparing plots
This is the plot comparison function we just used. It plots the original image next to the
resulting one. Using this function allows us to reuse this code and focus more on the image
processing part of the code.
Lets look at another filtering technique, smoothing. We can achieve this with a Gaussian
filter. This technique is typically used to blur an image or to reduce noise. Here we see the
effect of applying a Gaussian filter, which can especially be seen in the edges of the dogs hair.
The Gaussian filter will blur edges and reduce contrast. This is used in other techniques like
anti-aliasing filtering.
Code:
Lets see how we can do this with Scikit image using this picture in Amsterdam.
We import the Gaussian function from the filters module of scikit-image. To apply the
filter, the original image is passed as first parameter to the Gaussian function and the
multichannel boolean parameter is set to True if the image is colored, otherwise it needs to be
set to False. Finally, lets compare the original and the resulting image.
1.5. Contrast
1.5.1. Contrast enhancement
28
Image enhancement can be extremely useful in multiple areas. Often medical images like
this X-ray can have low contrast, making it hard to spot important details. When we improve
the contrast,the details become more visible. It's definitely easier to spot things on this one!
1.5.2. Contrast
The contrast of an image can be seen as the measure of its dynamic range, or the "spread"
of its histogram. Consider this image. The contrast is the difference between the maximum and
minimum pixel intensity in the image. The histogram of this image is shown on the right. The
maximum value of pixel intensity is 255 while the minimum is 0. 255 - 0 = 255.
An image of low contrast has small difference between its dark and light pixel values. Is
usually skewed either to the right (being mostly light), to the left (when is mostly dark), or
located around the middle (mostly gray).
29
1.5.3. Enhance contrast
We can enhance contrast through contrast stretching which is used to stretch the
histogram so the full range of intensity values of the image is filled. And histogram
equalization, that spreads out the most frequent histogram intensity values using probability
distribution. We'll cover histogram equalization in this video.
In general, there are three types of histogram equalization. The standard, the adaptive, and
the limited adaptive. In scikit-image we can apply standard histogram equalization, contrast
stretching, and contrast limited adaptive as we can see in these images.
As we have seen Histogram equalization spreads out the most frequent intensity values.
To apply this type of histogram equalization import the exposure module from scikit-
image. We then have access to all equalization methods. In this case, the equalize_hist
function, applies normal histogram equalization to the original image.
Code:
We get a result that, despite the increased contrast, doesn't look natural. In fact, it doesn't
even look like the image has been enhanced at all.
Another type of histogram equalization is the adaptive one. This method computes
several histograms, each corresponding to a distinct part of the image, and uses them to
redistribute the lightness values of the image histogram. A type of this method is the
Contrastive Limited Adaptive Histogram Equalization (CLAHE) which was developed to
prevent over-amplification of noise that adaptive histogram equalization can give rise to. In this
image, we see the result of the CLAHE method and it may seem very similar to the standard
method.
But if you look closer and compare the results, you will see that the adaptive method is
not that intense, so it looks more natural. This is because it is not taking the global histogram of
the entire image, but operates on small regions called tiles or neighborhoods.
31
1.5.7. CLAHE in scikit-image
To apply this kind of adaptive equalization we can use the equalize_adapthist function
provided by scikit-image. It calculates the contrast transform function for each tile individually.
We pass the original image as first parameter and a clip_limit. This clipping limit, is
normalized between 0 and 1 (higher values give more contrast).
Code:
Comparing them, the resulting image is enhanced and we can better detail small objects
and figures. Like the footprints in the ground.
1.6. Transformations
1.6.1. Why transform images?
32
For example when you need to pass images to a Machine Learning model so it can
classify if it's a cat or a dog, and we want the image to be upright. To optimize the size of
images so it doesn't take long to analyze them. Or when we need all the images to have the
same proportion before processing them further.
1.6.2. Rotating
We have flipped images before using Numpy. Rotating images allows us to apply angles,
like when you rotate an image 90 degrees, clockwise. Meaning, to the right. Or like when you
rotate images 90 degrees anticlockwise, meaning, to the left. Like we see in this example
image.
Rotating clockwise: We can use the rotate function from scikit-image module
"transform" to rotate an image by a certain angle around its center Once we import the module
and function. In this code we are obtaining the rotated image with 90 degrees clockwise. The
first parameter is the image we want to rotate and the second parameter is the angle. The
rotation angle is in degrees in counter-clockwise or anticlockwise direction. So we use negative
values. Here, you can see the original and rotated images.
Code:
from skimage.transform import rotate
# Rotate the image 90 degrees clockwise
image_rotated = rotate(image, -90)
show_image(image_rotated, 'Original')
33
show_image(image_rotated, 'Rotated 90 degrees clockwise')
Rotating anticlockwise: If we want to rotate anticlockwise, that is, to the left, we need to
specify the degrees angles with positive numbers. In this case, we are rotating 90 degrees to the
left.
Code:
from skimage.transform import rotate
# Rotate the image 90 degrees clockwise
image_rotated = rotate(image, 90)
show_image(image_rotated, 'Original')
show_image(image_rotated, 'Rotated 90 degrees anticlockwise')
1.6.3. Rescaling
The rescale operation resizes an image by a given scaling factor. This can either be a
single floating point value, or multiple values - one for each axis.
We can use the rescale function from the transform module. Once imported, in this
example we make an image to be 4 times smaller than its original size by setting the scaling
factor to 1/4. Setting an anti_aliasing boolean parameter to true specifies if applying a filter to
smooth the image prior to down-scaling. We'll get into more detail later on. Then a
multichannel if the image is colored.
Code: (Downgrading)
from skimage.transform import rescale
# Rescale the image to be 4 times smaller
image_rescaled = rescale(image, 1/4, anti_aliasing=True,
multichannel=True)
show_image(image, 'Original image')
34
show_image(image_rescaled, 'Rescaled image')
1.6.5. Resizing
Resizing is used for making images match a certain size. The same purpose as rescale, but
allows to specify an output image shape instead of a scaling factor.
35
We can use the resize function from the transform module. This function requires the
original image as the first parameter and a tuple holding the desired height and width to resize
the image. Optionally, we can also set the anti-aliasing method.
Code:
from skimage.transform import resize
# Height and width to resize
height = 400
width = 500
# Resize image
image_resized = resize(image, (height, width),
anti_aliasing=True)
# Show the original and resulting images
show_image(image, 'Original image')
show_image(image_resized, 'Resized image')
We can see how the image has been resized to a height of 400 and a width of 600.
36
1.7. Morphology:
When you try to spot objects in an image, you can do so by its characteristics, like the
shape. This what Morphology does
Binary regions
produced by simple
thresholding can be distorted
by noise and texture, as we
can see in the image.
Basic morphological operations are dilation and erosion. Dilation adds pixels to the
boundaries of objects in an image, while erosion removes pixels on object boundaries. The
number of pixels added or removed from the objects in an image depends on the size and shape
of a structuring element used to process the image.
37
1.7.4. Structuring element
The structuring element is a small binary image used to probe the input image. We try to
"fit" in the image object we want to get its shape. Here, the square structuring element named
"A" fits in the object we want to select. The "B" intersects the object and the "C" is out of it. So
if we want to select an apple in a table, we want the structuring element fit in that apple so then
expands, probe and obtain the shape.
The dimensions specify the size of the structuring element. Like a square of 5 by 5 pixels.
The pattern of ones and zeros specifies the shape of the structuring element. This should be of a
similar form to the shape of the object we want to select. So we see in here different types of
shapes, from squares, to diamond. The pink cell is the center or origin of the structuring
element. Identifies the pixel being processed.
scikit-image has multiple shapes for this structured element, each one with its own
method from the morphology module. If we want square as the structured element, we can
38
obtain it with the square method. Or a rectangle with width and height. This will return the
desired shape and if we print we'll see how these are formed with 1s.
[[1 1 1 1]
[1 1 1 1] [[1 1]
[1 1 1 1] [1 1]
[1 1 1 1]] [1 1]
[1 1]]
To apply erosion we can use the binary erosion function. With this we can optionally set a
structuring element to use in the operation. Here we import it and load a binary horse image.
Set the structuring element to a rectangular-shaped, since it's somewhat similar to the shape we
want to obtain, which is a horse. And obtain the eroded image by using this function, passing
the image and structuring element as parameters. If not set, the function will use a cross-shaped
structured element.
Code:
39
Binary erosion with default selem: If we apply binary erosion with default structuring
element shape, we would obtain this eroded image. It's working better, more accurate than
before. So for this image the cross-shaped works great.
Code:
Now let's look at dilation. As the name implies, this operation sort of "expands" the
objects in the image. Here, we use binary dilation function, also from the morphology module,
on image_horse. Let's use the default structuring element, which is cross-shaped.
Code:
from skimage import morphology
# Obtain dilated image, using binary dilation
dilated_image = morphology.binary_dilation(image_horse)
# See results
plot_comparison(image_horse, dilated_image, 'Erosion')
40
EXERCISE:
Exercise 1: Edge detection
Question: Detect edges in an image by applying the Sobel filter
Code
Instruction
Import the color module so you can convert the image to grayscale
41
Import the sobel() function from filters module
Make soaps_image grayscale using the appropriate method from the color
module
Apply the sobel edge detection filter on the obtained image grayscale
soaps_image_gray
____
# Apply filter
gaussian_image = ____
42
# Show original and resulting image to compare
show_image(____, "Original")
Instruction:
Exercise 3:
Question: What is the contrast of this image?
Instruction:
Possible Answers
43
The contrast is 255 (high contrast)
The contrast is 148
The contrast is 189
The contrast is 49 (low contrast)
Exercise 4: Medical images
Question: You are trying to improve the tools of a hospital by pre-processing the X-ray
images so that doctors have a higher chance of spotting relevant details. You'll test our code on
a chest X-ray image from the National Institutes of Health Chest X-Ray Dataset
First, you'll check the histogram of the image and then apply standard histogram
equalization to improve the contrast. Remember we obtain the histogram by using
the hist() function from Matplotlib, which has been already imported as plt
Code:
44
Exercise 5: Aerial image
Question: In this exercise, we will improve the quality of an aerial image of a city. The
image has low contrast and therefore we can not distinguish all the elements in it.
For this we will use the normal or standard technique of Histogram Equalization
Code:
Instruction:
45
Exercise 6: Let's add some impact and contrast
Question: Have you ever wanted to enhance the contrast of your photos so that they appear
more dramatic?
In this exercise, you'll increase the contrast of a cup of coffee. Something you could share
with your friends on social media. Don't forget to use #ImageProcessingDatacamp as
hashtag!
Even though this is not our Sunday morning coffee cup, you can still apply the same
methods to any of our photos.
A function called show_image(), that displays an image using Matplotlib, has already
been defined. It has the arguments image and title, with title being 'Original' by
default.
Code:
Instruction:
46
Import the module that includes the Contrast Limited Adaptive Histogram Equalization
(CLAHE) function
Obtain the image you'll work on, with a cup of coffee in it, from the module that holds all
the images for testing purposes
From the previously imported module, call the function to apply the adaptive equalization
method on the original image and set the clip limit to 0.03
Remember that aliasing is an effect that causes different signals, in this case pixels, to
become indistinguishable or distorted.
You'll make this cat image upright by rotating it 90 degrees and then rescaling it two
times. Once with the anti aliasing filter applied before rescaling and a second time without it,
so you can compare them.
Code:
Instruction: Import the module and the rotating and rescaling functions
Have you ever tried resizing an image to make it larger? This usually results in loss of
quality, with the enlarged image looking blurry.
The good news is that the algorithm used by scikit-image works very well for enlarging
images up to a certain point. In this exercise you'll enlarge an image three times!
You'll do this by rescaling the image of a rocket, that will be loaded from the data module
Code:
Introduction:
Import the module and function needed to enlarge images, you'll do this by rescaling.
Import the data module.
Load the rocket() image from data.
Enlarge the rocket_image so it is 3 times bigger, with the anti aliasing filter
applied. Make sure to set multichannel to True or you risk your session timing
out!
Remember that by looking at the shape of the image, you can know its width and height.
Code:
Instruction:
As we can see it's the letter R, already binary, with some noise in it. It's already loaded
as upper_r_image. Apply the morphological operation that will discard the pixels near the
letter boundaries.
Code:
Instruction:
Apply the morphological operation for eroding away the boundaries of regions of
foreground pixels.
Instruction:
51
Import the module
Obtain the binarized and dilated image, from the original image world_image
52
CHAPTER 3. IMAGE RESTORATION
THEORIES
3.1. Image restoration
1.7.8. Restore an image
Have you ever wondered if it's possible to restore a damaged or defect image? This could
have happened because your laptop memory got corrupted. Or, it could also be a picture of
your grandparents that over time has been scratched and now is somewhat deteriorated.
Whatever happened, the cool thing is that yes, you can restore them.
53
In scikit-image, we can apply inpainting with the inpaint biharmonic function, from the
restoration module. It needs the location of the damaged pixels to be filled, as a mask image on
top of the image to work with. A mask image is simply an image where some of the pixel
intensity values are zero, and others are non-zero.
Image reconstruction in scikit-image: To use this function we first need to import the
module and function. Having the image with the defect already loaded, we need to set the mask
with the location of the damaged pixels in the image. Remember that images are matrix of
pixels. For this, in the course, we use the get_mask() function. This is something that we'll take
a closer look at in a moment. Once we have the mask, we can invoke the inpaint_biharmonic
function to apply it to the image with the defect. This will be passed as the first parameter, then
the mask, and optionally we can set a boolean for the multichannel. Set it to true if the image is
colored.
Code:
from skimage.restoration import inpaint
# Obtain the mask
mask = get_mask(defect_image)
# Apply inpainting to the damaged image using the mask
restored_image = inpaint.inpaint_biharmonic(defect_image,
mask,
multichann
el=True)
# Show the resulting image
show_image(restored_image)
# Show the defect and resulting images
show_image(defect_image, 'Image to restore')
show_image(restored_image, 'Image restored')
54
Then we can look at the resulting image.
We look at the original image with the defect and the resulting restored image to compare
them. In this example, we can see how the masked pixels get inpainted by the inpainting
algorithm based on the biharmonic equation assumption.
1.7.10.Masks
Imagine you have an old picture of your parents you want to fix. In this image, we
intentionally added the missing pixels by setting them to black. In case you want to remove an
object you can manually delineate it in the mask. And if you want to automatically detect it,
you would need to use Thresholding or segmentation to do so. Something we will learn later
on. In the right image we see the damaged areas of the image as a mask.
The scikit-image inpainting function requires the mask to be an array of pixels that need
to be inpainted. This mask has to be the same shape as one of the image channels. Unknown
pixels have to be represented with 1 and known pixels with 0. So we add the missing pixels by
copying the image and turning the pixels into a numpy array of zeros, meaning it's empty. We
only copy the width and height dimensions of the image, excluding the color dimension, in this
case RGB-3. And then, set the 1s in the specific areas we want to be treated as lost.
Code:
def get_mask(image):
55
''' Creates mask with three defect regions '''
mask = np.zeros(image.shape[:-1])
mask[101:106, 0:240] = 1
mask[152:154, 0:60] = 1
mask[153:155, 60:100] = 1
mask[154:156, 100:120] = 1
mask[155:156, 120:140] = 1
mask[212:217, 0:150] = 1
mask[217:222, 150:256] = 1
return mask
3.2. Noise
1.7.11.Noise
How can an image have noise? Well images are signals and real-world signals usually
contain departures from the ideal signal, which is the perfect image, as we observe with our
eyes in real life. Such departures are referred to as noise. We can see how this image has some
color grains when zoomed in.
More specifically, noise is the result of errors in the image acquisition process that result
in pixel values that do not reflect the true intensities of the real scene. In this image we can see
how there is a variation of brightness and color that does not correspond to reality, which is
produced by the camera.
56
1.7.12.Apply noise in scikit-image:
We can add noise to an image using scikit-image, with the random noise function from
the "util" module. The image of a dog has already been preloaded. Now, we need to import the
util module and the random_noise function. We can then add random noise of various types to
the image by using this function. After doing this, we obtain a new image named noisy_image.
To compare the original and resulting noisy image we can show them side-by-side using the
show_image function we introduced in previous videos.
Code:
# Import the module and function
from skimage.util import random_noise
# Add noise to the image
noisy_image = random_noise(dog_image)
# Show original and resulting image
show_image(dog_image)
show_image(noisy_image, 'Noisy image')
By using the random_noise function, we obtain the original image with a lot of added
noise, that is distributed randomly. This type of noise is known as "salt and pepper" because
that's in fact what it looks like. So we now know how to "mess up" a picture and use it for
testing purposes.
57
1.7.13.Reducing noise
Most of the times we will want to remove or reduce the noise of images instead of adding
it in. Like in this example, you can see a noisy image of me that is being denoised. For that, we
can use several algorithms in scikit-image. The higher the resolution of the image, the longer it
may take to eliminate the noise.
Denoising types: Some types of denoising algorithms are: The total variation filter. This
filter tries to minimize the total variation of the image. It tends to produce “cartoon-like”
images, that is, piecewise-constant images. Bilateral filtering smooths images while preserving
edges. It replaces the intensity of each pixel with a weighted average of intensity values from
nearby pixels. In this course, we'll focus on these two. But there are also The wavelet denoising
filter and Non-local means denoising.
We can perform total variation filter denoising with the denoise tv chambolle function
from the restoration module. When applying this function, we can optionally set the denoising
weight. The greater the weight, the more denoising but it could also make the image smoother.
We can also specify if the image is multichannel (colored) or not. The final step is to show the
original image compared with the resulting one.
58
Code
from skimage.restoration import denoise_tv_chambolle
# Apply total variation filter denoising
denoised_image = denoise_tv_chambolle(noisy_image,
weight= 0.1,
multichannel= Tru
e)
# Show denoised image
show_image(noisy_image, 'Noisy image')
show_image(denoised_image, 'Denoised image')
We see that we obtain a denoised image with the edges preserved but a little bit smooth or
blurry
Bilateral filter denoising is accessible through the denoise bilateral function also from
the restoration module. We apply it to the noisy image, set multichannel to the appropriate
value, and we can leave other options to the default. Now we'll see the original and the
resulting one to compare.
Code
from skimage.restoration import denoise_bilateral
# Apply bilateral filter denoising
denoised_image = denoise_bilateral(noisy_image,
multichannel=True)
# Show original and resulting images
show_image(noisy_image, 'Noisy image')
59
show_image(denoised_image, 'Denoised image')
The resulting image is less smooth than the one from the total variation filter. And
preserves the edges a lot more.
The goal is to partition images into regions, or segments, to simplify and/or change the
representation into something more meaningful and easier to analyze.
60
1.7.15.Image representation
Consider how we represent images. They are represented as a grid of pixels. The issue is
that they're not a completely natural representation of an image. If I were to take a single pixel
from the image on the left and then showed it to you on the right, would you be able to tell that
the pixel came from a puppy and that this single pixel holds a logical meaning? A single pixel,
standing alone by itself, is not a natural representation.
1.7.16.Superpixels
1.7.17.Segmentation
61
unsupervised where no prior knowledge is required. These algorithms try to subdivide images
into meaningful regions automatically. The user may still be able to tweak certain settings to
obtain the desired output. Like the otsu thresholding we used in first chapter
1.7.18.Unsupervised segmentation
We can find the algorithm in the segmentation module as the "slic" function. This method
returns the segmented regions, also known as labels. Here we use this function, with default
parameters and obtain the segments. We'll use the label2rgb method from the color module to
return an image where the segments obtained from the slic method will be highlighted, either
with random colors or with the average color of the superpixel segment. In this example we'll
use the average color. So we pass the segments or labels, the image, and set the kind parameter
to average avg.
Code:
# Import the modules
from skimage.segmentation import slic
from skimage.color import label2rgb
# Obtain the segments
segments = segmentation.slic(image)
# Put segments on top of original image to compare
segmented_image = label2rgb(segments, image, kind='avg')
show_image(image)
show_image(segmented_image, "Segmented image")
62
Finally, we show the resulting segmented image. You can see how local regions with
similar color and texture distributions are part of the same superpixel group.
If we want more segments, let's say 300, we can specify this with an optional parameter,
n_segments. Its default value is 100 segments.
Code:
# Import the modules
from skimage.segmentation import slic
from skimage.color import label2rgb
# Obtain the segments
segments = segmentation.slic(image, n_segments= 300)
# Put segments on top of original image to compare
segmented_image = label2rgb(segments, image, kind='avg')
show_image(image)
show_image(segmented_image, "Segmented image")
We show the resulting segmented image
We will learn how to find the contours of the objects in an image. A contour is a closed
shape of points or line segments, representing the boundaries of these objects. Once we find the
63
contours, we can do things like identifying the total points in domino tokens, exactly what we
do in this example, where we count 35! So we can measure size, classify shapes or
determining the number of objects in an image.
First, the image needs to go through some pre-processing steps. We need to turn the
image to grayscale to later apply thresholding. We can do so by using the rgb2gray function
from the color module.
To use the find_contours function, we need the image we want to obtain contours from, to
be binary. Meaning, black and white. Here we apply thresholding to do that, so we get a
thresholded image.
And then, we use the find contours function, that is included in the measure module of
scikit-image. This function finds the contour lines or joins points(pixels) of equal elevation or
brightness in a 2D array above a given level value. We import the module "measure" from
skimage. And from measure we call the function find_contours. Passing the thresholded image
as the first parameter and a constant level value of zero point eight. We will go into more detail
about the constant level value in the next slide. The function returns a list with all contours of
the image. With the coordinates along the contour.
64
Code:
# Make the image grayscale
image = color.rgb2gray(image)
# Obtain the thresh value
thresh = threshold_otsu(image)
# Apply thresholding
thresholded_image = image > thresh
# Import the measure module
from skimage import measure
# Find contours at a constant value of 0.8
contours = measure.find_contours(thresholded_image, 0.8)
The level value varies between 0 and 1, the closer to 1 the more sensitive the method is to
detecting contours, so more complex contours will be detected. We have to find the value that
best detects the contours we care for.
To summarize, the steps for finding the contours of an image are: If it's colored, transform
to grayscale. Obtain the optimal thresh value. Apply thresholding and obtain the binary image.
Once we have our binary image, we can call the find_contours() function and set a constant
level value.
Code:
65
from skimage import measure
from skimage.filters import threshold_otsu
# Make the image grayscale
image = color.rgb2gray(image)
# Obtain the optimal thresh value of the image
thresh = threshold_otsu(image)
# Apply thresholding and obtain binary image
thresholded_image = image > thresh
# Find contours at a constant value of 0.8
contours = measure.find_contours(thresholded_image, 0.8)
Resulting in the image with contours detected:
After executing these steps we obtain a list of contours. Each contour is an ndarray of
shape (n, 2), consisting of n row and column coordinates along the contour. In this way, a
contour is like an outline formed by multiple points joined together. The bigger the contour, the
more points joined together and the wider the perimeter formed. Here we can see the shapes of
the contours found in the domino's tokens image.
The first two have a shape of 433, so we deduct they are the outer border contour of the
tokens because they are the longest. Meaning, these are the biggest objects, judging by their
shapes.
The ones that have a shape of 401 belong to the inner border of the domino token. Since
the tokens of the original image had a line around them.
The 123 are the dividing line in the middle of the tokens.
And then we see the majority of the contours have a shape of 59. These are the token
dots. If we count them, we obtain a total number of 7, the total number of dots for both tokens.
(433, 2)
(433, 2) --> Outer border
(401, 2)
66
(401, 2) --> Inner border
(123, 2)
(123, 2) --> Divisory line of tokens
(59, 2)
(59, 2)
(59, 2)
Number of dots: 7
(57, 2)
(57, 2)
(59, 2)
(59, 2) --> Dots
EXERCISE
Exercise 1: restore a damaged image
Question: In this exercise, we'll restore an image that has missing parts in it, using
the inpaint_biharmonic() function.
Loaded as defect_image.
We'll work on an image from the data module, obtained by data.astronaut(). Some of
the pixels have been replaced by 1s using a binary mask, on purpose, to simulate a damaged
image. Replacing pixels with 1s turns them totally black. The defective image is saved as an
array called defect_image.
The mask is a black and white image with patches that have the position of the image bits
that have been corrupted. We can apply the restoration function on these areas. This mask is
preloaded as mask.
Remember that inpainting is the process of reconstructing lost or deteriorated parts of
images and videos.
Code:
As we saw in the video, another use of image restoration is removing objects from an
scene. In this exercise, we'll remove the Datacamp logo from an image.
You will create and set the mask to be able to erase the logo by inpainting this area.
Remember that when you want to remove an object from an image you can either
manually delineate that object or run some image analysis algorithm to find it.
Code:
Initialize a mask with the same shape as the image, using np.zeros()
68
In the mask, set the region that will be inpainted to 1
Apply inpainting to image_with_logo using the mask
Exercise 3: Noise
Question: In this exercise, we'll practice adding noise to a fruit image.
Code:
Code:
70
Preloaded as landscape_image
Since we prefer to preserve the edges in the image, we'll use the bilateral denoising filter
Code:
71
Image preloaded as face_image
Instruction: Use .shape from NumPy which is preloaded as np, in the console to check
the width and height of the image
Code:
Code:
Import the data and the module needed for contouring detection.
Obtain the horse image shown in the context area.
Find the contours of the horse image using a constant level value of 0.8.
73
Exercise 9: Find contours of an image that is not binary
Question: Let's work a bit more on how to prepare an image to
be able to find its contours and extract information from it. We'll
process an image of two purple dices loaded as image_dices and
determine what number was rolled for each dice.
In this case, the image is not grayscale or binary yet. This means
we need to perform some image pre-processing steps before looking for the contours. First,
we'll transform the image to a 2D array grayscale image and next apply thresholding. Finally,
the contours are displayed together with the original image.
color, measure and filters modules are already imported so you can use the functions to
find contours and apply thresholding. We also import io module to load the image_dices from
local memory, using imread.
Code:
In the previous exercise, we prepared a purple dices image to find its contours:
This time we'll determine what number was rolled for the dice, by counting the dots in the
image.
The contours found in the previous exercise are preloaded as contours.
Create a list with all contour's shapes as shape_contours. You can see all the contours
shapes by calling shape_contours in the console, once you have created it.
74
Check that most of the contours aren't bigger in size than 50. If you count them, they are
the exact number of dots in the image.
show_image_contour(image, contours) is a preloaded function that displays the image
with all contours found using Matplotlib
Code:
75
CHAPTER 4. FINDING THE EDGES WITH CANNY
THEORIES:
3.5. Finding the edges with Canny
1.7.24.Detecting edges
Most of the shape information of an image is enclosed in edges. In this image we see how
the edges hold information about the domino's tokens. Representing an image by its edges has
the advantage that the amount of data is reduced significantly while retaining most of the
image information, like the shapes.
1.7.25.Edge detection
In the previous chapter you have seen how to detect edges using the Sobel filtering
technique. In this video, you'll learn about one of the most used edge detection techniques, the
Canny edge detection. This is widely considered to be the standard edge detection method in
image processing. And produces higher accuracy detecting edges and less execution time
compared with Sobel algorithm.
The detector can be applied with the canny function from the feature module of scikit-
image. This function requires the image to be a 2-dimensional array, meaning, a grayscale
image. So in this example, we convert the image from RGB-3 to grayscale, using the rgb2gray
method from the color module that we already know from previous chapters. Then we apply
76
the canny detector on the coin's image and obtain the resulting image. Let's show it and see
what it looks like.
Code:
from skimage.feature import canny
# Convert image to grayscale
coins = color.rgb2gray(coins)
# Apply Canny detector
canny_edges = canny(coins)
# Show resulted image with edges
show_image(canny_edges, "Edges with Canny")
We see how the edges are highlighted with thick white lines and that some details are
more pronounced than the rest of the image. We can also spot the boundaries and shapes of
coins; by knowing that for each closed circle or ellipse, there's a coin.
The first step of this algorithm is to apply a gaussian filter in order to remove noise in the
image. The same gaussian filter we have seen previously in the course with the gaussian
function from the filters module. So, in the canny function you can optionally set the intensity
of this Gaussian filter to be applied in the image, by using the sigma attribute. The lower the
value of this sigma, the less of gaussian filter effect is applied on the image, so it will spot
more edges. On the other hand, if you set a higher value, more noise will be removed and the
result is going to be a less edgy image. The default value of this parameter is 1. In this example
we set it to 0.5, let's see the effect in the image.
Code:
# Apply Canny detector with a sigma of 0.5
canny_edges_0_5 = canny(coins, sigma=0.5)
77
# Show resulted images with edges
show_image(canny_edges, "Sigma of 1")
show_image(canny_edges_0_5, "Sigma of 0.5")
The resulting image has a lot more edges than the previous one and this is because noise
was removed before continuing with the rest of the steps in the algorithm.
Corner detection is an approach used to extract certain types of features and infer the
contents of an image. It's frequently used in motion detection, image registration, video
tracking, panorama stitching, 3D modelling, and object recognition. We saw in the previous
video how to detect edges with the Canny Edge detector, and before that with Sobel, in chapter
2. Edges are a type of feature in images.
1.7.28.Points of interest
78
Features are the points of interest which provide rich image content information. Points of
interest are points in the image which are invariant to rotation, translation, intensity, and scale
changes. (Basically, robust and reliable). There are different interest points such as corners and
edges. So corner detection is basically detecting (one type of) interest points in an image.
1.7.29.Corners
A corner can be defined as the intersection of two edges. Intuitively, it can also be a
junction of contours. We can see some obvious corners in this checkerboard image. Or in this
building image on the right.
1.7.30.Matching corners
79
Here is another example of corner matching, this time, in a rotated image. We see how
the relevant points. are still being matched.
Harris Corner Detector is a corner detection operator that is widely used in computer
vision algorithms. Here, we see an original
image of a building, and on the right we see the
corners detected by the Harris algorithm,
marked in red.
80
Let's use this image of a Japanese gate to work with the Harris detector. We can access it
by importing the corner_harris function from the feature module of scikit-image. This function
requires grayscale images, so we need to first convert the image from rgb to gray. We can do
this with the rgb2gray function we used previously. This corner_harris function gives us the
Harris measure response image, meaning, the resulting image showing only the possible
corners that were measured.
Code:
from skimage.feature import corner_harris
# Convert image to grayscale
image = rgb2gray(image)
# Apply the Harris corner detector on the image
measure_image = corner_harris(image)
# Show the Harris response image
show_image(measure_image)
So when we show it,
We see how only some black lines are shown. These are the approximated points where
the corners candidates are.
To find the corners in the measure response image, we can use the corner_peaks function.
Which will return the coordinates of the peaks of the possible corners. Optionally, we can
make sure these peak corners are separated by a minimum distance, in pixels, using the
min_distance parameter. Here we're setting the minimum distance between corners to 5 pixels.
In this image, a total of 122 corners were found from the measure response image.
Code:
# Finds the coordinates of the corners
coords = corner_peaks(corner_harris(image), min_distance=5)
81
print("A total of", len(coords), "corners were detected.")
Corners detected: Here the image is shown with the detected corners marked in red, using
a preloaded function that uses matplotlib and the resulting coordinates to do so, similar to
show_image.
Code:
# Show image with marks in detected corners
show_image_with_detected_corners(image, coords)
Show image with contours: This function uses the coordinates of the corners to plot cross
red marks on it and show it all together.
Code:
def show_image_with_corners(image, coords, title="Corners
detected"):
plt.imshow(image, interpolation='nearest', cmap='gray')
plt.title(title)
plt.plot(coords[:, 1], coords[:, 0], '+r', markersize=15)
plt.axis('off')
plt.show()
With scikit-image, we can detect faces using a machine learning classifier, with just a
couple of lines! In this course, we won't cover machine learning concepts in depth, but it's
important to know that we use a cascade of classifiers, which is like multiple classifiers in one.
You can also use it for other things, like cats, objects, or profile faces, from a side view.
To use the face detector, we import the Cascade class from the feature module. This
detection framework needs an xml file, from which the trained data can be read. In this case
we'll use frontal face files that are included in the data module of scikit-image. Then initialize
the detector, using the Cascade class constructor. Great, we now have the detector ready to be
used on images.
Code:
# Import the classifier class
from skimage.feature import Cascade
# Load the trained file from the module root.
trained_file = data.lbp_frontal_face_cascade_filename()
# Initialize the detector cascade.
detector = Cascade(trained_file)
83
To apply the detector on images, we need to use the detect_multi_scale method, from the
same cascade class. This method searches for the object, in this case a face. It creates a window
that will be moving through the image until it finds something similar to a human face.
Searching happens on multiple scales. The window will have a minimum size, to spot the
small or far-away faces. And a maximum size to also find the larger faces in the image.
So this method takes the input image as the first parameter, a scale factor, by which the
searching window is multiplied in each step, a step ratio, in which 1 represents an exhaustive
search and usually is slow. By setting this parameter to higher values the results will be worse
but the computation will be much faster. Usually, values in the interval 1 to 1.5 give good
results. Then the minimum and maximum window size are defined. These specify the interval
for the search windows that are applied to the input image to detect the faces.
The detector will return the coordinates of the box that contains the face. When printing
the result, we see that it's a dictionary, where r represents the row position of the top left corner
of the detected window, c is the column position pixel, width is width of detected window, and
height, the height of the detected window. We'll use a function that shows the original image
with the detected face marked with red lines, forming a box containing the face.
84
Code:
# Apply detector on the image
detected = detector.detect_multi_scale(img=image,
scale_factor= 1.2,
step_ratio= 1,
min_size=(10, 10),
max_size=( 200,
200))
print(detected)
# Show image with detected face marked
show_detected_face(image, detected)
Detected face: [{'r': 115, 'c': 210, 'width': 167, 'height': 167}]
Show detected faces: With this function I draw a rectangle around detected faces. We
won't discuss this function in detail here.
Code:
def show_detected_face(result, detected, title="Face image"):
plt.imshow(result)
img_desc = plt.gca()
plt.set_cmap('gray')
plt.title(title)
plt.axis('off')
for patch in detected:
img_desc.add_patch(
patches.Rectangle(
(patch['c'], patch['r']),
85
patch['width'],
patch['height'],
fill= False,color='r',linewidth=2)
)
plt.show()
Some cases where we might need to combine several techniques are, for example,
converting to images to grayscale before detecting edges or corners. Or, detecting faces to later
on blur them by applying a gaussian filter. And even reducing noise and restoring a damaged
image.
1.7.36.Privacy protection
Let's look at how we would solve a privacy protection case by detecting faces and then
anonymizing them. We'll use this image to work with.
86
So for this case in particular, we'll first need to detect faces, using the cascade of
classifiers detector and then apply a gaussian filter to the cropped faces.
# Import Cascade of classifiers and gaussian filter
from skimage.feature import Cascade
from skimage.filters import gaussian
So, with the face detector initialized and ready to use, we can start detecting faces. For
each detected face, as the variable d, in the detected list, we'll use the coordinates to crop it out
of the image, in other words, extract it.
# Detect the faces
detected = detector.detect_multi_scale(img=image,
scale_factor= 1.2,
step_ratio=1,
min_size=( 50, 50),
max_size=(100, 100))
# For each detected face
for d in detected:
# Obtain the face cropped from detected coordinates
face = getFace(d)
This get Face function crops the face out of the image, using the detected face dictionary
that contains the coordinates. Then, we'll draw a rectangle around the detected face of the
image. Taking r, which is the row position of top left corner of detected rectangle as the X
starting position and c, which is the column as the starting Y position. These are the points
from where we'll now add a width and a height to complete the rectangle. And that's exactly
what we do next, we add the height and width to the starting points. So we have the rectangle
dimensions in the image. We then specify these dimensions in the original image from which
the face was detected so we can crop it, or slice it.
def getFace(d):
''' Extracts the face rectangle from the image using the
coordinates of the detected.'''
# X and Y starting points of the face rectangle
x, y = d['r'], d['c']
# The width and height of the face rectangle
87
width, height = d['r'] + d['width'], d['c'] + d['height']
# Extract the detected face
face= image[x:width, y:height]
return face
Now that the face is cropped from the image, we'll apply the gaussian filter to blur it and
make it unrecognizable. This resulting image is assigned to the gaussian_face variable. As a
last step, we'll merge the blurry face back to the image, using another function called merge
blurry face.
# Detect the faces
detected = detector.detect_multi_scale(img=image,
scale_factor= 1.2,
step_ratio=1,
min_size=( 50, 50),
max_size=(100, 100))
# For each detected face
for d in detected:
# Obtain the face cropped from detected coordinates
face = getFace(d)
# Apply gaussian filter to extracted face
gaussian_face = gaussian(face, multichannel=True, sigma =
10)
# Merge this blurry face to our final image and show it
resulting_image = mergeBlurryFace(image, gaussian_face)
To do so, we again specify the starting X and Y points as well as the width and height, to
slice the original image. Then, the blurry face is assigned to the result
def mergeBlurryFace(original, gaussian_image):
# X and Y starting points of the face rectangle
x, y = d['r'], d['c']
# The width and height of the face rectangle
width, height = d['r'] + d['width'], d['c'] + d['height']
original[ x:width, y:height] = gaussian_image
88
return original
So it results in an image that no longer contains people's faces in it and in this way,
personal data is anonymized. We need to remember that the classifier was only trained to
detect the front side of faces, not profile faces. So, if someone is turning the head too much to a
side, it won't recognize it. If you wnat to do that, you'll need to train the classifier with xml
files of profile faces, that you can find available online. Like some provided by the OpenCV
image processing library.
1.7.37.More cases
Just like the cases mentioned before, there are many more where you will we be able to
combine the processes that you learned during the course
89
EXERCISE:
Exercise 1: Finding the edges with Canny
Question: In this exercise you will identify the shapes in a grapefruit image by detecting
the edges, using the Canny algorithm.
Code:
90
Exercise 2: Less edgy
Question: Let's now try to spot just the outer shape of the grapefruits, the circles. You can
do this by applying a more intense Gaussian filter to first make the image smoother. This can
be achieved by specifying a bigger sigma in the canny function.
In this exercise, you'll experiment with sigma values of the canny() function.
Code:
Apply the canny edge detector to the grapefruit image with a sigma of 1.8.
Apply the canny edge detector to the grapefruit image with a sigma of 2.2.
Show the resulting images.
Exercise 3:
Question: In this exercise, you will detect the corners of a building using the Harris
corner detector.
91
Image preloaded as building_image.
Code:
Apply the harris detector to obtain the measure response image with the possible corners.
Find the peaks of the corners
92
Exercise 4: Less corners
Question: In this exercise, you will test what happens when you set the minimum distance
between corner peaks to be a higher number. Remember you do this with
the min_distance attribute parameter of the corner_peaks() function.
Code:
93
print("With a min_distance set to 2, we detect a total", len(coords_w_min
_2),
94
The Cascade of classifiers class from feature module has been already imported. The
same is true for the show_detected_face() function, that is used to display the face marked in
the image and crop so it can be shown separately.
Code:
Detect the faces in the image, setting the minimum size of the searching window to 10
pixels and 200 pixels for the maximum.
95
Image preloaded as friends_image.
The Cascade of classifiers class from feature module has already been imported, as well
as the show_detected_face() function which is used to display the face marked in the image
and crop it so it can be shown separately.
Code:
Detect the faces in the image, setting a scale_factor of 1.2 and step_ratio of 1
96
Exercise 7: Segmentation and face detection
Question: Previously, you learned how to make processes more computationally efficient
with unsupervised superpixel segmentation. In this exercise, you'll do just that!
Using the slic() function for segmentation, pre-process the image before passing it to
the face detector.
The Cascade class, the slic() function from segmentation module, and the
show_detected_face() function for visualization have already been imported. The detector is
already initialized and ready to use as detector.
Code:
Apply superpixel segmentation and obtain the segments a.k.a. labels using slic()
Obtain the segmented image using label2rgb(), passing the segments and
profile_image
Detect the faces, using the detector with multi scale method.
In this exercise, you will detect human faces in the image and for the sake of privacy,
you will anonymize data by blurring people's faces in the image automatically.
Code:
Detect the faces in the image using the detector, set the minimum size of the searching
window to 10 by 10 pixels.
Go through each detected face with a for loop.
Help Sally restore her favorite portrait which was damaged by noise, distortion, and
missing information due to a breach in her laptop.
99
Rotating it to be uprightusing rotate()
Code:
Use the chambolle algorithm to remove the noise from the image.
With the mask provided, use the biharmonic method to restore the missing parts of the
image and obtain the final image
100