Image analysis of colony growth

© 2021 Tom Röschinger. This work is licensed under a Creative Commons Attribution License CC-BY 4.0. All code contained herein is licensed under an MIT license


In this notebook we are going to use microscopy data of bacteria to determine their growth rate. In order to do that, we took images of the same colony over a period of about 1-2 hours.

The first step is to set the path to the data set.

Let's load an image into memory.

As we can see, an image is just a two dimensional array of intensities. We can look at an image by using the imshow function of pyplot. Since we only have one channel, we will simply use a grey scale to show the image. Some images can have multiple channels in order to image different things at the same time (such as fluorescent proteins with varying emission wavelengths).

A good step is to normalize the intensity values, such that they range from 0 to 1. This allows us to compare different images to each other.

The image looks the same to us, but that is only due to the automatic scaling of the colormap that pyplot does in the background. To be sure that we successfully transformed the image, let's take a look at the actual values of the array.

Let's look at a histogram of intensity values.

The histogram shows a bimodal distribution. This make sense, since one mode comes from the background, while the other mode is the cells. Now we can separate background from cells (a process called segmentation) by simply choosing the pixels that have a high enough intensity compared to the background (a process called thresholding). After thresholding, background pixels have value 0 and cell pixels have value 1.

This worked pretty well. However, we see that we do not clearly resolve the edges between cells, and in some region the image looks more like a lawn. There are way more sophisticated approaches to segmentation that would allow us to do that as well. But for now, simple thresholding is good enough for us. To find a good value for the threshold, we can use a the package panel to create a slider that let's us change the parameter on the fly!

Now it is time to process all images. Before we do that, we need to sort the images by their time stamp.

Now we can interate through the images and perform the segmentation. We store the total number of pixels that belong to cells, which is proportional to the area occupied by the colony.

Let's plot the results! The images were taken every 5 minutes, so we use that to scale the x-axis accordingly.

This looks already pretty exponential. Let's put the y-axis on a log-scale.

If the data is linear on a semi log plot (y-axis), it is a clear sign for an exponential curve. To get a feeling for the range of growth rates that might give a good fit to the data, we can use a dashboard with the package panel. This allows us to manipulate a parameter and automatically update a plot everytime we change the parameter, without having to run the cell again.

Now let's find the growth rate that explains the data the best. Therefore, we minimize the sum squared residuals. That means, we take the difference of each data point to the expectation from the theory, and sum up the square of these differences. The set of parameters which minimizes this sum is determined to be the "best" fit.

Let's write a function that computes the sum of squared residuals for a chosen parameter.

Now that we have the function in hand, we can apply it to a range of growth rates. We already guessed that the growth rate is about 0.03/min, so let's explore a range of growth rates around this value.

Let's have a look at the squared residuals.

This plot reinforces our guess that the optimal growth rate is about 0.03/min. We can find the best guess for a growth rate by looking for the minimum in the array.

Our final best guess for a growth rate is about 0.032/min, which equals a doubling time of about 22 minutes, which is around the doubling time of E. coli that we observe in the lab! Finally, let's have a look at the theory curve that we determined to fit the data "best".