Welcome to the homepage of Bowhead, a cell velocity Python package. This package provides tools to analyze cell velocity from time series of wound healing experiments.

The accompanying paper is found at PLOS.

Image data presented in that paper you can download here.

The source code is available at GitLab.


The package is installed via pip for python3

$ pip3 install bowhead

Getting Started

First import bowhead and Pillow

>>> import bowhead, PIL

To detect the wound on an image file called ‘wound_t08.jpg’ call bowhead.detect()

>>> threshold = .25  # 25% of cell confluency
>>> my_wound = bowhead.detect('img/wound_t08.jpg', thresh=threshold)

The result is a dictionary with values from the detection such as area and perimeter and their variances.

>>> my_wound['area']
>>> my_wound['area_variance']
>>> my_wound['center_of_mass']
(294.0, 286.0)

To visualize the detected wound on the original image use Matplotlib. The perimeter coordinates are saved in the wound dictionary with the keyword ‘edge’

>>> from matplotlib.pyplot import *
>>> gray()  # keep image plots gray scale
>>> imshow('img/wound_t08.jpg'))
<matplotlib.image.AxesImage object at ...
>>> y, x = my_wound['edge']
>>> plot(x, y, color='#127ba6')
[<matplotlib.lines.Line2D object at ...
>>> savefig('round_wound')
>>> close()

Time Series

In order to analyze a time series experiment with multiple images a list of wound detection dictionaries is needed. Call bowhead.detect() with paths and corresponding time points

>>> from glob import glob
>>> paths = sorted(glob('img/*.png'))  # time sorted images
>>> time = range(len(paths))
>>> my_series = bowhead.detect(paths, time, sigma=40)

This call detects wounds on all images and assign an experimental time point to each of them. By plotting static frames per time point allows for creating a movie of the detection (e.g. with imageio)


The returned list my_series can be used to fit a velocity model (bowhead.Model) with the function

>>> model = bowhead.Model()
<bowhead.velocity.Model object at ...

When a model is fitted it can be used to predict cell velocity t desired time points with bowhead.Model.predict(). Note that these do not have to be the original data time points

>>> velocity, std = model.predict(time, return_std=True)

When return_std=True is passed to predict, the standard deviation of the velocity is also returned. Velocity with errors can be plotted like so

>>> errorbar(time, velocity, std, c='#127ba6')
<ErrorbarContainer object of ...
>>> xlabel('hours')
Text(0.5, 0, 'hours')
>>> ylabel('pixels / hours')
Text(0, 0.5, 'pixels / hours')
>>> savefig('velocity')
>>> close()

Different ways to detect images

There are three different ways to give images to bowhead.detect(). Parse a file path to the image

>>> path = 'img/wound_t08.jpg'
>>> my_wound = bowhead.detect(path)

or a PIL image

>>> import PIL.Image
>>> pil_image =
>>> my_wound = bowhead.detect(pil_image)

or even a numpy.ndarray

>>> import numpy
>>> array_image = numpy.asarray(pil_image)
>>> my_wound = bowhead.detect(array_image)

For all of the cases above a single image or a list of images can be used as input to bowhead.detect().

Bright-field and similar image types

Some imaging techniques, such a bright-field or phase contrast, violates Bowhead’s assumption that cells are light and wounds are dark respectively. To overcome this the image gradient can be used instead of pixel intensity directly. Bowhead deploys a Scharr edge filter for this purpose. Users can use the utility function before analysis

>>> # sample image from 'TScratch' by CSElab
>>> #
>>> bright_path = 'tscratch_example_image.jpg'
>>> bright =
>>> grad = bowhead.image_gradient(bright)  # (or use file path)
>>> fig, axes = subplots(ncols=2, figsize=(12,8))
>>> original = axes[0].imshow(bright)  # bright field image
>>> gradient = axes[1].imshow(grad)  # gradient map
>>> savefig('transformed', bbox_inches='tight')
>>> close()

Or, for convenience, an argument can be given directly to bowhead.detect() to achieve the gradient transform indirectly

>>> my_wound = bowhead.detect(bright_path, use_gradient=True)
To see how the detection performs on the bright field image
>>> imshow(bright)
<matplotlib.image.AxesImage object at ...
>>> y, x = my_wound['edge']
>>> plot(x, y, color='#127ba6')
[<matplotlib.lines.Line2D object at ...
>>> savefig('bright_field_wound')
>>> close()

Contour tracing method

By default Bowhead uses the Marching Squares algorithm with linear interpolation to establish the perimeter coordinate chain. This gives a perimeter with round corners on the pixel level. As an alternative a chain code implementation is available. Chain code saves the discrete pixel values and gives a rugged perimeter. Chain code runs slightly faster than Marching Squares. The perimeter length varies slightly between the two methods.

>>> # use keyword argument to set the method
>>> path = 'img/wound_t08.jpg'
>>> marching_wound = bowhead.detect(path, method='marching')
>>> chain_wound = bowhead.detect(path, method='chain')

Package Reference

Here is a list of the available classes and functions in the package. The Index gives an alternative alphabetical listing of the package content.

class bowhead.Model(area_kwargs=None, perimeter_kwargs=None)[source]

Wound velocity model.

The model is based on Gaussian Process Regression (GPR) and numerical differentiation. The GPR uses scikit-learn GPR class sklearn.gaussian_process.GaussianProcessRegressor.

  • area_kwargs (dictionary) – The keyword arguments to the area GPR model.
  • perimeter_kwargs (dictionary) – The keyword arguments to the perimeter GPR model.
  • area (area model) – Instances of GaussianProcessRegressor from scikit-learn.
  • perimeter (perimeter model) – Instances of GaussianProcessRegressor from scikit-learn.
  • time (sequence) – Sequence of the input time points. Defined when fitted.


The keyword argument kernel is specifying the covariance function of the GPR models handling the area and perimeter. The default kernel is a sum of a linear and squared dotproduct kernel. See scikit-learn for the different kernels that can be used. Note that the kernel hyperparameters are optimized during fitting.


Fitting the velocity model to wound data.

Parameters:wounds (sequence of dictionaries) – A sequence of wound dictionaries representing an experimental time series of the wound healing assay, as returned by detect(). The area, perimeter and time point of each wound is used to fit the overall velocity model. All these attributes should be positive scalars.
Returns:self – The velocity model in a fitted state.
Return type:Model
predict(time, dt=0.1, return_std=False)[source]

Predicting a velocity curve of a wound healing experiment.

In addition to the mean of the predictive distribution, also its standard deviation (return_std=True) can be requested.

  • time (sequence) – Desired time points of the velocity prediction. Should be positive.
  • dt (scalar) – The time interval for calculating velocity.
  • return_std (bool) – Whether to include the standard deviation of the prediction or not.

velocity, [vel_std] – Velocity and (optionally) it’s standard deviation. Returned either one array or (if return_std=True) as a tuple (velocity, vel_std).

Return type:

1d arrays

bowhead.detect(images, time=None, sigma=25, thresh=0.4, err=0.05, radius=None, use_gradient=False, method='marching')[source]

Detect wound on a image with uncertainty.

  • images (sequence of [file paths | numpy.ndarray | PIL.Image]) – Images to detect wound(s) from. A single image path, array, or PIL image can be passed outside a sequence.
  • time (sequence) – The time points of the images (same order as images).
  • sigma (scalar) – The standard deviation of the image smoothing. This should be roughly the same as the distance (in pixels) between cells at confluency.
  • thresh (scalar) – Threshold factor to calculate wound boundary. Between zero and one.
  • err (scalar) – Standard error of the threshold value to calculate uncertainty of the detection.
  • radius (scalar, default is None) – If radius is not None and more than 2 images parsed the algorithm uses the mean center of mass of the two first wounds to define a circular zone of exclusion with radius radius in pixels. Subsequent wound candidates have to been inside this zone to be considered valid wounds.
  • use_gradient (boolean, default is False) – Whether to preprocess the images with a Scharr edge filter. This is useful to better detect wounds on bright-field images and other types where cells appear as a both light and dark in the microscope image.
  • method (string, default is 'marching') – Which method to use for contour tracing. Choose between ‘marching’ for the marching square algorithm or ‘chain’ for chain code tracing. Chain code is fastest. The perimeter found differs slightly because Marching square finds interpolated round edges at pixel corners where chain code result in a standard pixel chain.

wound(s) – Returns one dictionary (or a list of several) with the detected wound values

  • area
  • perimeter (without parts that touch image border)
  • area and perimeter variances
  • center of mass
  • time
  • edge (tuple of wound edge x and y coordinates)
  • filename, (image file path if loaded from disk)
  • image area

Returns None, for wounds that can not be detected.

Return type:

dictionary or a list of dictionaries


All image types and bit depth supported by Pillow can be used as input. If the images contain more than one color channel the sum of all channels will be used.

bowhead.sort_and_cutoff(wounds, min_area=0.05, abs_area=False)[source]

Sort by time and cutoff based on minimum area.

Utillity function to sort wounds by time and filter out wounds by minimum area (pixel^2).

  • wounds (sequence of dictionaries) – A sequence of wound dictionaries representing an experimental time series of the wound healing assay, as returned by detect().
  • min_area (float) – Percentage (or absolute) image size to consider a closed wound area. After this limit is hit the following time points will be excluded from the wound list.
  • abs_area (bool) – Wether to use absolute area.

wounds – A wound list sorted by time point of the wounds. The following will remove wounds from the returned list:

  • wound area smaller than min_area*image area or abs_area
  • wounds with later time point than the first removed
  • None valued wounds

Return type:

list of dictionaries


Preprocess bright-field or similar type images.

Applys a Scharr filter and normalizes the output gradient image.

Parameters:image ([file path | numpy.ndarray | PIL.Image]) – A color or grayscale image as file path numpy array or PIL image.
Returns:image – A normalized image representing the gradient (edge magnitude) of the input image.
Return type:PIL.Image (8 bit image mode ‘L’)