Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,27 @@ fresh eyes are always welcome.
### What to Contribute (This Lesson)

Any contributions are welcome, particularly ideas for how the existing content could be
improved or updated, and/or errors that need to be corrected. Comments on existing issues
improved or updated, and/or errors that need to be corrected. Comments on existing issues
and reviews of pull requests are similarly welcome.

If you plan to submit a pull request, please open an issue
(or comment on an existing thread) first to ensure that effort is not duplicated
or spent making a change that will not be accepted by the Maintainers.

#### Content / style guidelines
- If you add an image / figure that was generated from Python code, please include this

- If you add an image / figure that was generated from Python code, please include this
code in your PR under `episodes/fig/source`.

- Use the terms in the table below, when referring to Python libraries within the lesson.
The table gives two terms for each library: `Term for descriptive text` which should be
used when discussing the library in plain English / full sentences and `Term for code`
- If you add a new image or figure, verify that it displays correctly in the lesson’s dark mode. A color-inversion filter is applied [by Varnish to all images by default in dark mode](https://github.com/carpentries/varnish/issues/181), which may cause some images to appear incorrectly or become unreadable. If your image is affected, include an additional version of the same image with a `-dark` suffix in its filename.

- Use the terms in the table below, when referring to Python libraries within the lesson.
The table gives two terms for each library: `Term for descriptive text` which should be
used when discussing the library in plain English / full sentences and `Term for code`
which should be used when referring to code (and within code).

| Python library | Term for descriptive text | Term for code |
| :------------- | :------------- | :------------- |
| :------------- | :------------- | :------------- |
| [scikit-image](https://scikit-image.org/) | scikit-image | `skimage` |
| [NumPy](https://numpy.org/) | NumPy | `numpy` |
| [Matplotlib](https://matplotlib.org/) | Matplotlib | `matplotlib` |
Expand All @@ -101,15 +104,15 @@ or spent making a change that will not be accepted by the Maintainers.
rr, cc = ski.draw.rectangle(start=(357, 44), end=(740, 720))
```

- For reading and writing images, use the [imageio](https://imageio.readthedocs.io/en/stable/index.html)
- For reading and writing images, use the [imageio](https://imageio.readthedocs.io/en/stable/index.html)
library and avoid use of `skimage.io`. For example:
```python
import imageio.v3 as iio

chair = iio.imread(uri="data/chair.jpg") # read an image
iio.imwrite(uri="data/chair.tif", image=chair) # write an image
```

- Comments providing an overall description of a code snippet should use triple quotes `"""`, e.g.,
```python
"""Python script to load a colour image in grayscale"""
Expand Down Expand Up @@ -138,7 +141,7 @@ Although most contributions will be welcome at this stage of the curriculum's de
the time available to deliver the content in a training event is strictly limited
and needs to be accounted for when considering the addition of any new content.
If you want to suggest the addition of new content, especially whole new sections or episodes,
please open an issue to discuss this with the Maintainers first and provide the following
please open an issue to discuss this with the Maintainers first and provide the following
information alongside a summary of the content to be added:

1. A suggested location for the new content.
Expand Down
20 changes: 10 additions & 10 deletions episodes/03-skimage-images.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ Images may appear the same size in jupyter,
but you can see the size difference by comparing the scales for each.
You can also see the difference in file storage size on disk by
hovering your mouse cursor over the original
and the new files in the Jupyter file browser, using `ls -l` in your shell
and the new files in the Jupyter file browser, using `ls -l` in your shell
(`dir` with Windows PowerShell), or viewing file sizes in the OS file browser if it is configured so.

::::::::::::::: solution
Expand Down Expand Up @@ -240,7 +240,7 @@ Suppose we are interested in this maize root cluster image.
We want to be able to focus our program's attention on the roots themselves,
while ignoring the black background.

![](data/maize-root-cluster.jpg){alt='Root cluster image'}
![](fig/maize-root-cluster.jpg){alt='Root cluster image'}

Since the image is stored as an array of numbers,
we can simply look through the array for pixel colour values that are
Expand Down Expand Up @@ -379,9 +379,9 @@ the low intensity pixels while changing the high intensity ones.

The file `data/sudoku.png` is an RGB image of a sudoku puzzle:

![](data/sudoku.png){alt='Su-Do-Ku puzzle'}
![](fig/sudoku.png){alt='Su-Do-Ku puzzle'}

Your task is to load the image in grayscale format and turn all of
Your task is to load the image in grayscale format and turn all of
the bright pixels in the image to a
light gray colour. In other words, mask the bright pixels that have
a pixel value greater than, say, 192 and set their value to 192 (the
Expand All @@ -392,15 +392,15 @@ range 0-255 of an 8-bit pixel). The results should look like this:

*Hint: the `cmap`, `vmin`, and `vmax` parameters of `matplotlib.pyplot.imshow`
will be needed to display the modified image as desired. See the [Matplotlib
documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.imshow.html)
documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.imshow.html)
for more details on `cmap`, `vmin`, and `vmax`.*

::::::::::::::: solution

## Solution

First, load the image file `data/sudoku.png` as a grayscale image.
Note we may want to create a copy of the image array to avoid modifying our original variable and
First, load the image file `data/sudoku.png` as a grayscale image.
Note we may want to create a copy of the image array to avoid modifying our original variable and
also because `imageio.v3.imread` sometimes returns a non-writeable image.

```python
Expand Down Expand Up @@ -465,11 +465,11 @@ Consider this image of a whiteboard, and suppose that we want to create a
sub-image with just the portion that says "odd + even = odd," along with the
red box that is drawn around the words.

![](data/board.jpg){alt='Whiteboard image'}
![](fig/board.jpg){alt='Whiteboard image'}

Using `matplotlib.pyplot.imshow`
Using `matplotlib.pyplot.imshow`
we can determine the coordinates of the corners of the area we wish to extract
by hovering the mouse near the points of interest and noting the coordinates
by hovering the mouse near the points of interest and noting the coordinates
(remember to run `%matplotlib widget` first if you haven't already).
If we do that, we might settle on a rectangular
area with an upper-left coordinate of *(135, 60)*
Expand Down
4 changes: 2 additions & 2 deletions episodes/04-drawing.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ Copy that image to your computer, write some code to make a mask,
and apply it to select the part of the image containing your object.
For example, here is an image of a remote control:

![](data/remote-control.jpg){alt='Remote control image'}
![](fig/remote-control.jpg){alt='Remote control image'}

And, here is the end result of a program masking out everything but the remote:

Expand Down Expand Up @@ -446,7 +446,7 @@ fig, ax = plt.subplots()
ax.imshow(wellplate)
```

![](data/wellplate-01.jpg){alt='96-well plate'}
![](fig/wellplate-01.jpg){alt='96-well plate'}

Suppose that we are interested in the colours of the solutions in each of the wells.
We *do not* care about the colour of the rest of the image,
Expand Down
2 changes: 1 addition & 1 deletion episodes/05-creating-histograms.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ and histograms are also quite handy as a preparatory step before performing
We will start with grayscale images,
and then move on to colour images.
We will use this image of a plant seedling as an example:
![](data/plant-seedling.jpg){alt='Plant seedling'}
![](fig/plant-seedling.jpg){alt='Plant seedling'}

Here we load the image in grayscale instead of full colour, and display it:

Expand Down
18 changes: 9 additions & 9 deletions episodes/06-blurring.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ fig, ax = plt.subplots()
ax.imshow(image)
```

![](data/gaussian-original.png){alt='Original image'}
![](fig/gaussian-original.png){alt='Original image'}

Next, we apply the gaussian blur:

Expand Down Expand Up @@ -331,8 +331,8 @@ ax.imshow(blurred)

## Visualising Blurring

Somebody said once "an image is worth a thousand words".
What is actually happening to the image pixels when we apply blurring may be
Somebody said once "an image is worth a thousand words".
What is actually happening to the image pixels when we apply blurring may be
difficult to grasp. Let's now visualise the effects of blurring from a different
perspective.

Expand Down Expand Up @@ -430,18 +430,18 @@ but can be viewed by following the links in the captions.


![
A 3D plot of pixel intensities across the whole Petri dish image before blurring.
[Explore how this plot was created with matplotlib](https://gist.github.com/chbrandt/63ba38142630a0586ba2a13eabedf94b).
A 3D plot of pixel intensities across the whole Petri dish image before blurring.
[Explore how this plot was created with matplotlib](https://gist.github.com/chbrandt/63ba38142630a0586ba2a13eabedf94b).
Image credit: [Carlos H Brandt](https://github.com/chbrandt/).
](fig/3D_petri_before_blurring.png){
alt='3D surface plot showing pixel intensities across the whole example Petri dish image before blurring'
}

![
A 3D plot of pixel intensities after Gaussian blurring of the Petri dish image.
Note the 'smoothing' effect on the pixel intensities of the colonies in the image,
and the 'flattening' of the background noise at relatively low pixel intensities throughout the image.
[Explore how this plot was created with matplotlib](https://gist.github.com/chbrandt/63ba38142630a0586ba2a13eabedf94b).
A 3D plot of pixel intensities after Gaussian blurring of the Petri dish image.
Note the 'smoothing' effect on the pixel intensities of the colonies in the image,
and the 'flattening' of the background noise at relatively low pixel intensities throughout the image.
[Explore how this plot was created with matplotlib](https://gist.github.com/chbrandt/63ba38142630a0586ba2a13eabedf94b).
Image credit: [Carlos H Brandt](https://github.com/chbrandt/).
](fig/3D_petri_after_blurring.png){
alt='3D surface plot illustrating the smoothing effect on pixel intensities across the whole example Petri dish image after blurring'
Expand Down
26 changes: 13 additions & 13 deletions episodes/07-thresholding.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fig, ax = plt.subplots()
ax.imshow(shapes01)
```

![](data/shapes-01.jpg){alt='Image with geometric shapes on white background' .image-with-shadow}
![](fig/shapes-01.jpg){alt='Image with geometric shapes on white background' .image-with-shadow}

Now suppose we want to select only the shapes from the image.
In other words, we want to leave the pixels belonging to the shapes "on,"
Expand Down Expand Up @@ -214,7 +214,7 @@ ax.imshow(selection)
Now, it is your turn to practice. Suppose we want to use simple thresholding
to select only the coloured shapes (in this particular case we consider grayish to be a colour, too) from the image `data/shapes-02.jpg`:

![](data/shapes-02.jpg){alt='Another image with geometric shapes on white background'}
![](fig/shapes-02.jpg){alt='Another image with geometric shapes on white background'}

First, plot the grayscale histogram as in the [Creating
Histogram](05-creating-histograms.md) episode and
Expand Down Expand Up @@ -324,7 +324,7 @@ fig, ax = plt.subplots()
ax.imshow(maize_roots)
```

![](data/maize-root-cluster.jpg){alt='Image of a maize root'}
![](fig/maize-root-cluster.jpg){alt='Image of a maize root'}

We use Gaussian blur with a sigma of 1.0 to denoise the root image.
Let us look at the grayscale histogram of the denoised image.
Expand All @@ -348,25 +348,25 @@ ax.set_xlim(0, 1.0)

![](fig/maize-root-cluster-histogram.png){alt='Grayscale histogram of the maize root image'}

The histogram has a significant peak around 0.2 and then a broader "hill" around 0.6 followed by a
The histogram has a significant peak around 0.2 and then a broader "hill" around 0.6 followed by a
smaller peak near 1.0. Looking at the grayscale image, we can identify the peak at 0.2 with the
background and the broader peak with the foreground.
Thus, this image is a good candidate for thresholding with Otsu's method.
The mathematical details of how this works are complicated (see
[the scikit-image documentation](https://scikit-image.org/docs/dev/api/skimage.filters.html#threshold-otsu)
if you are interested),
but the outcome is that Otsu's method finds a threshold value between the two peaks of a grayscale
histogram which might correspond well to the foreground and background depending on the data and
histogram which might correspond well to the foreground and background depending on the data and
application.

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: instructor

The histogram of the maize root image may prompt questions from learners about the interpretation
of the peaks and the broader region around 0.6. The focus here is on the separation of background
and foreground pixel values. We note that Otsu's method does not work well
for the image with the shapes used earlier in this episode, as the foreground pixel values are more
The histogram of the maize root image may prompt questions from learners about the interpretation
of the peaks and the broader region around 0.6. The focus here is on the separation of background
and foreground pixel values. We note that Otsu's method does not work well
for the image with the shapes used earlier in this episode, as the foreground pixel values are more
distributed. These examples could be augmented with a discussion of unimodal, bimodal, and multimodal
histograms. While these points can lead to fruitful considerations, the text in this episode attempts
histograms. While these points can lead to fruitful considerations, the text in this episode attempts
to reduce cognitive load and deliberately simplifies the discussion.

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Expand Down Expand Up @@ -636,10 +636,10 @@ def enhanced_root_mass(filename, sigma):

# perform binary thresholding to mask the white label and circle
binary_mask = blurred_image < 0.95

# perform automatic thresholding using only the pixels with value True in the binary mask
t = ski.filters.threshold_otsu(blurred_image[binary_mask])

# update binary mask to identify pixels which are both less than 0.95 and greater than t
binary_mask = (blurred_image < 0.95) & (blurred_image > t)

Expand Down Expand Up @@ -677,7 +677,7 @@ The `&` operator above means that we have defined a logical AND statement. This
| False | True | False |
| True | False | False |
| True | True | True |

Knowing how to construct this kind of logical operation can be very helpful in image processing. The University of Minnesota Library's [guide to Boolean operators](https://libguides.umn.edu/BooleanOperators) is a good place to start if you want to learn more.

::::::::::::::::::::::::::::::::::::::::::::::::::
Expand Down
8 changes: 4 additions & 4 deletions episodes/08-connected-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ we have covered dividing an image into foreground and background pixels.
In the shapes example image,
we considered the coloured shapes as foreground *objects* on a white background.

![](data/shapes-01.jpg){alt='Original shapes image' .image-with-shadow}
![](fig/shapes-01.jpg){alt='Original shapes image' .image-with-shadow}

In thresholding we went from the original image to this version:

Expand Down Expand Up @@ -357,15 +357,15 @@ Those are really big numbers.
From this available space we only use the range from `0` to `11`.
When showing this image in the viewer,
it may squeeze the complete range into 256 gray values.
Therefore, the range of our numbers does not produce any visible variation. One way to rectify this
Therefore, the range of our numbers does not produce any visible variation. One way to rectify this
is to explicitly specify the data range we want the colormap to cover:

```python
fig, ax = plt.subplots()
ax.imshow(labeled_image, vmin=np.min(labeled_image), vmax=np.max(labeled_image))
```

Note this is the default behaviour for newer versions of `matplotlib.pyplot.imshow`.
Note this is the default behaviour for newer versions of `matplotlib.pyplot.imshow`.
Alternatively we could convert the image to RGB and then display it.


Expand All @@ -376,7 +376,7 @@ Alternatively we could convert the image to RGB and then display it.
## Suppressing outputs in Jupyter Notebooks

We just used `ax.set_axis_off();` to hide the axis from the image for a visually cleaner figure. The
semicolon is added to supress the output(s) of the statement, in this [case](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axis.html)
semicolon is added to supress the output(s) of the statement, in this [case](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axis.html)
the axis limits. This is specific to Jupyter Notebooks.

::::::::::::::::::::::::::::::::::::::::::::::::::
Expand Down
Binary file added episodes/fig/3D_petri_after_blurring-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/3D_petri_before_blurring-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/Gaussian_2D-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/beads-canny-ui-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/beads-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/beads-out-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/beads.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/black-and-white-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/black-and-white-edge-pixels-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/black-and-white-gradient-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/blur-demo-dark.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/board-coordinates-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/board-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/board-final-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/board.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/cartesian-coordinates-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/cat-corner-blue-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/cat-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/cat-eye-pixels-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/checkerboard-blue-channel-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/checkerboard-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/checkerboard-green-channel-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/checkerboard-red-channel-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/colonies-01-dark.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/colonies-01-gray-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added episodes/fig/colonies-01-mask-dark.png
Binary file added episodes/fig/colonies-01-summary-dark.png
Binary file added episodes/fig/colonies-02-dark.jpg
Binary file added episodes/fig/colonies-02-summary-dark.png
Binary file added episodes/fig/colonies-03-dark.jpg
Binary file added episodes/fig/colonies-03-summary-dark.png
Binary file added episodes/fig/colony-mask-dark.png
Binary file added episodes/fig/colour-table-dark.png
Binary file added episodes/fig/combination-dark.png
Binary file added episodes/fig/drawing-practice-dark.jpg
Binary file added episodes/fig/eight-dark.png
Binary file added episodes/fig/five-dark.png
Binary file added episodes/fig/four-maize-roots-binary-dark.jpg
Binary file added episodes/fig/four-maize-roots-dark.jpg
Binary file added episodes/fig/gaussian-blurred-dark.png
Binary file added episodes/fig/gaussian-kernel-dark.png
Binary file added episodes/fig/gaussian-original-dark.png
Binary file added episodes/fig/gaussian-original.png
Binary file added episodes/fig/grayscale-dark.png
Binary file added episodes/fig/image-coordinates-dark.png
Binary file added episodes/fig/left-hand-coordinates-dark.png
Binary file added episodes/fig/maize-root-cluster-dark.jpg
Binary file added episodes/fig/maize-root-cluster-mask-dark.png
Binary file added episodes/fig/maize-root-cluster.jpg
Binary file added episodes/fig/maize-roots-grayscale-dark.jpg
Binary file added episodes/fig/maize-roots-grayscale.jpg
Binary file added episodes/fig/maize-roots-threshold-dark.png
Binary file added episodes/fig/maize-seedling-enlarged-dark.jpg
Binary file added episodes/fig/maize-seedling-original-dark.jpg
Binary file added episodes/fig/maize-seedlings-dark.jpg
Binary file added episodes/fig/maize-seedlings-mask-dark.png
Binary file added episodes/fig/maize-seedlings-masked-dark.jpg
Binary file added episodes/fig/petri-dish-dark.png
Binary file added episodes/fig/plant-seedling-dark.jpg
Binary file added episodes/fig/plant-seedling-grayscale-dark.png
Binary file added episodes/fig/plant-seedling.jpg
Binary file added episodes/fig/quality-histogram-dark.jpg
Binary file added episodes/fig/quality-jpg-dark.jpg
Binary file added episodes/fig/quality-original-dark.jpg
Binary file added episodes/fig/quality-tif-dark.jpg
Binary file added episodes/fig/rectangle-gaussian-blurred-dark.png
Binary file added episodes/fig/remote-control-dark.jpg
Binary file added episodes/fig/remote-control-masked-dark.jpg
Binary file added episodes/fig/remote-control.jpg
Binary file added episodes/fig/shapes-01-canny-edge-output-dark.png
Binary file added episodes/fig/shapes-01-canny-edges-dark.png
Binary file added episodes/fig/shapes-01-canny-track-edges-dark.png
Binary file added episodes/fig/shapes-01-cca-detail-dark.png
Binary file added episodes/fig/shapes-01-dark.jpg
Binary file added episodes/fig/shapes-01-filtered-objects-dark.png
Binary file added episodes/fig/shapes-01-grayscale-dark.png
Binary file added episodes/fig/shapes-01-labeled-dark.png
Binary file added episodes/fig/shapes-01-mask-dark.png
Binary file modified episodes/fig/shapes-01-objects-coloured-by-area.png
Binary file added episodes/fig/shapes-01-selected-dark.png
Binary file added episodes/fig/shapes-01.jpg
Binary file added episodes/fig/shapes-02-dark.jpg
Binary file added episodes/fig/shapes-02-mask-dark.png
Binary file added episodes/fig/shapes-02-selected-dark.png
Binary file added episodes/fig/shapes-02.jpg
Binary file added episodes/fig/sudoku-dark.png
Binary file added episodes/fig/sudoku-gray-dark.png
Binary file added episodes/fig/sudoku.png
Binary file added episodes/fig/three-colours-dark.png
Binary file added episodes/fig/wellplate-01-dark.jpg
Binary file added episodes/fig/wellplate-01-masked-dark.jpg
Binary file added episodes/fig/wellplate-01.jpg
Binary file added episodes/fig/wellplate-02-dark.jpg
Binary file added episodes/fig/wellplate-02-histogram-dark.png
Binary file added episodes/fig/wellplate-02-masked-dark.jpg
Binary file added episodes/fig/zero-dark.png
6 changes: 3 additions & 3 deletions learners/edge-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ We will execute the program on the `data/shapes-01.jpg` image,
which we used before in
[the *Thresholding* episode](../episodes/07-thresholding.md):

![](data/shapes-01.jpg){alt='coloured shapes'}
![](fig/shapes-01.jpg){alt='coloured shapes'}

We are interested in finding the edges of the shapes in the image,
and so the colours are not important.
Expand Down Expand Up @@ -225,7 +225,7 @@ based on the contents of the image(s) to be processed.
Here is an image of some glass beads that we can use as
input into a Canny edge detection program:

![](data/beads.jpg){alt='Beads image'}
![](fig/beads.jpg){alt='Beads image'}

We could use the `code/edge-detection/CannyEdge.py` program above
to find edges in this image.
Expand Down Expand Up @@ -394,7 +394,7 @@ Consider this image of a collection of maize seedlings,
and suppose we wish to use simple fixed-level thresholding to
mask out everything that is not part of one of the plants.

![](data/maize-roots-grayscale.jpg){alt='Maize roots image'}
![](fig/maize-roots-grayscale.jpg){alt='Maize roots image'}

To perform the thresholding, we could first create a histogram,
then examine it, and select an appropriate threshold value.
Expand Down