Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Image processing, pt 3/3

Combining multiple operations

Let’s load the bacterial data again:

<Figure size 640x480 with 1 Axes>

Some (many) image features cannot be captured by application of a single image processing function.

By combining several image processing tools however, you can sometimes extract more complex features.

Let’s look at an example of this: a multi-step approach allows us to segment the bacterial picture we saw before.

<Figure size 640x480 with 1 Axes>
<Figure size 640x480 with 1 Axes>

As we saw earlier, edges correspond to values going from positive, through zero, to negative. So we can look for places where negative and positive values are close.

<Figure size 640x480 with 1 Axes>

Let’s remove lines due to background noise by using a simpler triangle mask to select the colony.

<Figure size 640x480 with 1 Axes>
<Figure size 640x480 with 1 Axes>
<Figure size 640x480 with 1 Axes>
<Figure size 640x480 with 1 Axes>

This looks pretty great, except that many bacteria are still “stuck together”.

Let’s try to identify separate bacteria.

<Figure size 640x480 with 1 Axes>
<Figure size 640x480 with 1 Axes>

We can now combine the “shrunk” but individually separated bacteria with the original binary mask, to obtain individually separated bacteria in the proper bacterial mask.

To achieve this, we’ll use a function we haven’t seen yet, which is called “watershed”.

This “fills” an image intensity profile with “water” at separate marker locations designated by a labeled map. As the global waterlevel rises, wherever water starts touching, region boundaries are set.

(Pictures via Matt Seymour on Unsplash and researchgate.) Watershed is a common algorithm to segment touching objects. It is inspired by how water would fill up a landscape. From specific seeds, the water level rises, and once separate regions touch, boundaries are established.

<Figure size 640x480 with 1 Axes>

Great! We now have a labeled map where we can access information about each of the single bacteria that were recorded.

<Figure size 354.331x354.331 with 1 Axes>

Exercise: Batch analysis of the KTR data

  • Download the file KTR-images-series.zip (link), which contains the following folders:

    • sensor/

      • KTR_sensor_frame_0000.tif

      • KTR_sensor_frame_0001.tif

      • (..)

    • nuclei/

      • KTR_nuclei_frame_0000.tif

      • KTR_nuclei_frame_0001.tif

      • (..)

  • Use a loop to load these images into one big np.array().

  • Write a function that calculates the KTR C/N ratio, like we did in part 2

    • The function should take as input arguments img_nuclei and img_KTR, respectively data from a single frame of nuclei or KTR sensor image data.

    • The function should then return all C/N ratios from that image per cell in a single array.

  • Use a loop to apply this function to all time points of the data.

  • Plot the data

Notes: Time between frames is 270.01617 seconds. Stimulation occured at 25 mins.

Hints

  • The following generic structure can be used to loop over files and load them:

for t in range(nr_frames):
    img = tiff.imread(<path> + str(t).zfill(4) + ".tif")
  • With my_list = [] you can start an array

  • With the command my_list.append(img) you can add items (likely images in this case) to an array (also when it’s empty).

  • np.array(my_list) can convert a list to a numpy array.

  • When making a plot, a loop can be used to plot different parts of the data. E.g.:

for t in range(nr_frames):
    _ = plt.scatter(<x values>, <y values for t>) 
  • The code [t]*100 creates an array of length 100 in which the value of t is repeated.

  • len(my_list) gives the length of a list.

References
  1. Fisher, A. (2014). Cloud and Cloud-Shadow Detection in SPOT5 HRG Imagery with Automated Morphological Feature Extraction. Remote Sensing, 6(1), 776–800. 10.3390/rs6010776