Skip to content

Commit 17b7e0b

Browse files
authored
Merge pull request #189 from K-Meech/blurring_episode_jupyter
Make blurring episode jupyter compatible
2 parents 458f281 + d3ee8b5 commit 17b7e0b

File tree

2 files changed

+47
-198
lines changed

2 files changed

+47
-198
lines changed

episodes/06-blurring.md

Lines changed: 47 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,16 @@ questions:
77
objectives:
88
- "Explain why applying a low-pass blurring filter to an image is beneficial."
99
- "Apply a Gaussian blur filter to an image using skimage."
10-
- "Explain what often happens if we pass unexpected values to a Python
11-
function."
1210
keypoints:
1311
- "Applying a low-pass blurring filter smooths edges and removes noise from
1412
an image."
1513
- "Blurring is often used as a first step before we perform
16-
[Thresholding]({{ page.root }}./07-thresholding.md),
17-
[Edge Detection]({{ page.root }}./08-edge-detection), or before we find the
18-
[Contours]({{ page.root }}./09-contours) of an image."
14+
[Thresholding]({{ page.root }}/07-thresholding) or
15+
[Edge Detection]({{ page.root }}/../_extras/edge_detection.md)."
1916
- "The Gaussian blur can be applied to an image with the
2017
`skimage.filters.gaussian()` function."
2118
- "Larger sigma values may remove more noise, but they will also remove detail
2219
from an image."
23-
- "The `float()` function can be used to parse a string into an float."
2420
---
2521

2622
In this episode, we will learn how to use skimage functions to blur images.
@@ -36,9 +32,9 @@ background of the image ends and the object begins.
3632

3733
When we blur an image, we make the color transition from one side of an edge in the image to another
3834
smooth rather than sudden. The effect is to average out rapid changes in pixel intensity. A blur is
39-
a very common operation we need to perform before other tasks such as edge detection. There are
40-
several different blurring functions in the `skimage.filters` module, so we will focus on just one
41-
here, the *Gaussian blur*.
35+
a very common operation we need to perform before other tasks such as
36+
[thresholding]({{ page.root }}/07-thresholding). There are several different blurring functions
37+
in the `skimage.filters` module, so we will focus on just one here, the *Gaussian blur*.
4238

4339
> ## Filters
4440
>
@@ -194,121 +190,30 @@ order to calculate the color channel values for the blurred image.
194190
![Blur demo animation](../fig/blur-demo.gif)
195191
196192
skimage has built-in functions to perform blurring for us, so we do not have to
197-
perform all of these mathematical operations ourselves. The following Python
198-
program shows how to use the skimage Gaussian blur function.
193+
perform all of these mathematical operations ourselves. Let's work through
194+
an example of blurring an image with the skimage Gaussian blur function.
199195
196+
First, we load the image, and display it:
200197
~~~
201-
"""
202-
* Python script to demonstrate Gaussian blur.
203-
*
204-
* usage: python GaussBlur.py <filename> <sigma>
205-
"""
206198
import skimage.io
199+
import matplotlib.pyplot as plt
207200
import skimage.filters
208-
import sys
201+
%matplotlib widget
209202

210-
# get filename and kernel size from command line
211-
filename = sys.argv[1]
212-
sigma = float(sys.argv[2])
213-
~~~
214-
{: .language-python}
215-
216-
In this case, the
217-
program takes two command-line parameters. The first is the filename of the
218-
image to filter, and the second is the sigma of the Gaussian.
219-
220-
In the program, we first import the required libraries, as we
221-
have done before. Then, we read the two command-line arguments. The first, the
222-
filename, should be familiar code by now. For the sigma argument, we have
223-
to convert the second argument from a string, which is how all arguments are
224-
read into the program, into a float, which is what we will use for our
225-
sigma. This is done with the
226-
227-
`sigma = float(sys.argv[2])`
228-
229-
line of code. The `float()` function takes a string as its parameter, and returns
230-
the floating point number equivalent.
231-
232-
> ## What happens if the `float()` parameter does not look like a number? (10 min - optional, not included in timing)
233-
>
234-
> In the program fragment, we are using the `float()` function to *parse* the
235-
> second command-line argument, which comes in to the program as a string,
236-
> and convert it into a floating point number. What happens if the second command-line
237-
> argument does not look like a number? Let us perform an experiment to find
238-
> out.
239-
>
240-
> Write a simple Python program to read one command-line argument, convert the
241-
> argument to a floating point number, and then print out the result. Then, run your program
242-
> with an integer argument, again with a floating point number argument,
243-
> and then one more time with some non-numeric arguments.
244-
> For example, if your program is named `float_arg.py`, you might perform these
245-
> runs:
246-
>
247-
> ~~~
248-
> python float_arg.py 3.14159
249-
> python float_arg.py puppy
250-
> python float_arg.py 13
251-
> ~~~
252-
> {: .language-bash}
253-
>
254-
> What does `float()` do if it receives a string that cannot be parsed into an
255-
> integer?
256-
>
257-
> > ## Solution
258-
> >
259-
> > Here is a simple program to read in one command-line argument, parse it as
260-
> > and integer, and print out the result:
261-
> >
262-
> > ~~~
263-
> > """
264-
> > * Read a command-line argument, parse it as an integer, and
265-
> > * print out the result.
266-
> > *
267-
> > * usage: python float_arg.py <argument>
268-
> > """
269-
> > import sys
270-
> >
271-
> > value = float(sys.argv[1])
272-
> > print("Your command-line argument is:", value)
273-
> > ~~~
274-
> > {: .language-python}
275-
> >
276-
> > Executing this program with the three command-line arguments suggested
277-
> > above produces this output:
278-
> >
279-
> > ~~~
280-
> > Your command-line argument is: 3.14159
281-
> >
282-
> > Traceback (most recent call last):
283-
> > File "float_arg.py", line 9, in <module>
284-
> > value = float(sys.argv[1])
285-
> > ValueError: could not convert string to float: 'puppy'
286-
> >
287-
> > Your command-line argument is: 13.0
288-
> > ~~~
289-
> > {: .output}
290-
> >
291-
> > You can see that if we pass in an invalid value to the `float()` function,
292-
> > the Python interpreter halts the program and prints out an error message,
293-
> > describing what the problem was.
294-
> > Note also that the integer value, 13, passed as an argument was converted to
295-
> > a floating point number and is subsequently displayed as `13.0`.
296-
> {: .solution}
297-
{: .challenge}
298-
299-
Next, the program reads and displays the original, unblurred image. This should
300-
also be very familiar to you at this point.
203+
image = skimage.io.imread("data/gaussian-original.png")
301204

302-
~~~
303-
# read and display original image
304-
image = skimage.io.imread(fname=filename)
305-
skimage.io.imshow(image)
205+
# display the image
206+
fig, ax = plt.subplots()
207+
plt.imshow(image)
208+
plt.show()
306209
~~~
307210
{: .language-python}
211+
![Original image](../data/gaussian-original.png)
308212
309-
Now we apply the average blur:
310-
213+
Next, we apply the gaussian blur:
311214
~~~
215+
sigma = 3.0
216+
312217
# apply Gaussian blur, creating a new image
313218
blurred = skimage.filters.gaussian(
314219
image, sigma=(sigma, sigma), truncate=3.5, multichannel=True)
@@ -318,55 +223,39 @@ blurred = skimage.filters.gaussian(
318223
The first two parameters to `skimage.filters.gaussian()` are the image to blur,
319224
`image`, and a tuple defining the sigma to use in y- and x-direction,
320225
`(sigma, sigma)`. The third parameter `truncate` gives the radius of the kernel
321-
in terms of sigmas. A Gaussian is defined from -infinity to +infinity. A
322-
discrete Gaussian can only approximate the real function. The `truncate`
323-
parameter steers at what distance to the center of the function it is not
324-
approximated any more. In the above example we set `truncate` to 3.5. With a
325-
`sigma` of 1.0 the resulting kernel size would be 7.
326-
The default value for `truncate` in sklearn is 4.0.
327-
The last parameter is to tell skimage how to interpret our image, that has three
226+
in terms of sigmas. A Gaussian function is defined from -infinity to +infinity, but
227+
our kernel (which must have a finite, smaller size) can only approximate the real function.
228+
Therefore, we must choose a certain distance from the centre of the function where we stop
229+
this approximation, and set the final size of our kernel. In the above example, we set
230+
`truncate` to 3.5, which means the kernel size will be 2 * sigma * 3.5. For example,
231+
for a `sigma` of 1.0 the resulting kernel size would be 7, while for a
232+
`sigma` of 2.0 the kernel size would be 14. The default value for `truncate` in scikit-image is 4.0.
233+
234+
The last parameter to `skimage.filters.gaussian()` tells skimage to interpret our image, that has three
328235
dimensions, as a multichannel color image.
329-
After the blur filter has been executed, the program wraps things up by
330-
displaying the blurred image in a new window.
236+
237+
Finally, we display the blurred image:
331238
332239
~~~
333240
# display blurred image
334-
skimage.io.imshow(blurred)
241+
fig, ax = plt.subplots()
242+
plt.imshow(blurred)
243+
plt.show()
335244
~~~
336245
{: .language-python}
337-
338-
Here is a constructed image to use as the input for the preceding program.
339-
340-
![Original image](../data/gaussian-original.png)
341-
342-
When the program runs, it displays the original image, applies the filter,
343-
and then shows the blurred result. The following image is the result after
344-
applying a filter with a sigma of 3.0.
345-
346-
![Gaussian blurred image](../fig/gaussian-blurred.png)
246+
![Original image](../fig/gaussian-blurred.png)
347247
348248
> ## Experimenting with sigma values (10 min)
349249
>
350-
> Navigate to the `code/06-blurring/` directory
351-
> and execute the `GaussBlur.py` script, which contains the program shown
352-
> above. Execute it with two command-line parameters, like this:
353-
>
354-
> ~~~
355-
> python GaussBlur.py data/gaussian-original.png 1.0
356-
> ~~~
357-
> {: .language-bash}
358-
>
359-
> Remember that the first command-line argument is the name of the file to
360-
> filter, and the second is the sigma value. Now, experiment with the sigma
361-
> value, running the program with smaller and larger values.
250+
> Try running the code above with a range of smaller and larger sigma values.
362251
> Generally speaking, what effect does the sigma value have on the
363252
> blurred image?
364253
>
365254
> > ## Solution
366255
> >
367256
> > Generally speaking, the larger the sigma value, the more blurry the result.
368257
> > A larger sigma will tend to get rid of more noise in the image, which will
369-
> > help for other operations we will cover soon, such as edge detection.
258+
> > help for other operations we will cover soon, such as thresholding.
370259
> > However, a larger sigma also tends to eliminate some of the detail from
371260
> > the image. So, we must strike a balance with the sigma value used for
372261
> > blur filters.
@@ -375,51 +264,27 @@ applying a filter with a sigma of 3.0.
375264
376265
> ## Experimenting with kernel shape (10 min - optional, not included in timing)
377266
>
378-
> Now, modify the `GaussBlur.py` program so that it takes *three*
379-
> command-line parameters instead of two. The first parameter should still be
380-
> the name of the file to filter. The second and third parameters should be the
381-
> sigma values in y- and x-direction for the Gaussian to use, so that the
382-
> resulting kernel is rectangular instead of square. The new version of the
383-
> program should be invoked like this:
384-
>
385-
> ~~~
386-
> python GaussBlur.py data/gaussian-original.png 1.0 2.0
387-
> ~~~
388-
> {: .language-bash}
389-
>
390-
> Using the program like this utilizes a Gaussian with a sigma of 1.0 in y-
391-
> direction and 2.0 in x-direction for blurring
267+
> Now, try running the code above with different sigmas in the y and x direction.
268+
> For example, a sigma of 1.0 in the y direction, and 6.0 in the x direction.
269+
> What is the effect on the blurred image?
392270
>
393271
> > ## Solution
394272
> >
395273
> > ~~~
396-
> > """
397-
> > * Python script to demonstrate Gaussian blur.
398-
> > *
399-
> > * usage: python GaussBlur.py <filename> <sigma_y> <sigma_x>
400-
> > """
401-
> > import skimage.io
402-
> > import skimage.filters
403-
> > import sys
404-
> >
405-
> > # get filename and kernel size from command line
406-
> > filename = sys.argv[1]
407-
> > sigma_y = float(sys.argv[2])
408-
> > sigma_x = float(sys.argv[3])
409-
> >
410-
> > # read and display original image
411-
> > image = skimage.io.imread(fname=filename)
412-
> > skimage.io.imshow(image)
413-
> >
414-
> > # apply Gaussian blur, creating a new image
274+
> > # apply Gaussian blur, with a sigma of 1.0 in the y direction, and 6.0 in the x direction
415275
> > blurred = skimage.filters.gaussian(
416-
> > image, sigma=(sigma_y, sigma_x), truncate=3.5, multichannel=True
276+
> > image, sigma=(1.0, 6.0), truncate=3.5, multichannel=True
417277
> > )
418278
> >
419279
> > # display blurred image
420-
> > skimage.io.imshow(blurred)
280+
> > fig, ax = plt.subplots()
281+
> > plt.imshow(blurred)
282+
> > plt.show()
421283
> > ~~~
422284
> > {: .language-python}
285+
> > ![Rectangular kernel blurred image](../fig/rectangle-gaussian-blurred.png)
286+
> > This produces a kernel that is rectangular instead of square. Notice that the image
287+
> > is much more blurred in the x direction than the y direction.
423288
> {: .solution}
424289
{: .challenge}
425290
@@ -431,19 +296,3 @@ For other kinds of noise, e.g. "salt and pepper" or "static" noise, a
431296
median filter is typically used.
432297
See the [`skimage.filters` documentation](https://scikit-image.org/docs/dev/api/skimage.filters.html#module-skimage.filters)
433298
for a list of available filters.
434-
435-
> ## Blurring the bacteria colony images (15 min)
436-
>
437-
> As we move further into the workshop, we will see that in order to complete
438-
> the colony-counting morphometric challenge at the end, we will need to read
439-
> the bacteria colony images as grayscale, and blur them, before moving on to
440-
> the tasks of actually counting the colonies. Create a Python program to read
441-
> one of the colony images (with the filename provided as a command-line
442-
> parameter) as grayscale, and then apply a Gaussian blur to the image. You
443-
> should also provide the sigma for the blur as a second command-line
444-
> parameter. Do not alter the original image. As a reminder, the images are:
445-
>
446-
> - `data/colonies-01.tif`
447-
> - `data/colonies-02.tif`
448-
> - `data/colonies-03.tif`
449-
{: .challenge}

fig/rectangle-gaussian-blurred.png

23.6 KB
Loading

0 commit comments

Comments
 (0)