Cellocity Tutorial

Step-by-step guide

This tutorial will show you how to:

  1. Load a file and create a cellocity.channel.Channel object.
  2. Preprocess the Channel object.
  3. Prepare for analysis by creating an cellocity.analysis.Analyzer object from the Channel object.
  4. Extract data by creating an cellocity.analysis.Analysis object.

Load a file and create a Channel object

from cellocity.channel import Channel
import tifffile

my_filename = "2_channel_micromanager_timelapse.ome.tif"
chToAnalyze = 0  # 0-based indexing of channels

#safely load file
with tifffile.TiffFile(my_filename, multifile=False) as tif:

    #strips ome.tif from filename
    label = my_filename.split(".")[0]
    channelName = label + "_Ch" + str(chToAnalyze + 1)
    channel_0 = Channel(chToAnalyze, tif, name=channelName)

Warning

Cellocity assumes that it can hold all Channel data in RAM.

A Tifffile does not load all its image data into RAM when created, however upon accessing data during Channel creation some of it will be cached, thus increasing its size somewhat. Channel objects store all image data in RAM and can get quite hefty for long time lapses.

Preprocess Channel object

First, we will check if the frame interval stated in the metadata is in agreement with the time stamps of the individual frames in the channel (within 1%). This is done with the Channel.doFrameIntervalSanityCheck(maxDiff=0.01) method. If there is an discrepancy between the actual frame intervals and the intended, if can be fixed by calling the Channel.fixFrameInterval() method, which overwrites the intended frame interval with the actual average frame interval.

if not channel_0.doFrameIntervalSanityCheck():
        channel_0.fixFrameInterval()

Note

Checking and fixing the frame interval is currently only possible on MicroManager ome.tif files. Individual frame timestamps are lost when saving .tif files in ImageJ.

Channel objects have convenient preprocessing methods, such as trimming frames and temporal median filtering. Let’s start by trimming our newly created channel to frames 10-60, meaning we discard frames 0-9 and from frame 60 onward to the end.

#Trim channel to include frame 10-59
channel_0.trim(10,60)

Now let’s employ a temporal median filter, meaning we do a median filtering over time. This will have the effect of filtering out fast moving free-floating debris, thus greatly reducing the noise in the final analysis. This is done by creating a child cellocity.channel.MedianChannel object. Median filtering can be done with a gliding window (default), or by binning the frames. MedianChannel takes care of properly recalculating frame intervals in either case. The default frame sampling interval is 3.

from cellocity.channel import MedianChannel

gliding_median_channel_0 = MedianChannel(channel_0)

binned_4frame_median_channel_0 = MedianChannel(channel_0,
                                                doGlidingProjection=False,
                                                frameSamplingInterval=4)

MedianChannel objects can also be created by calling the .getTemporalMedianChannel() method on a Channel. The following code gives identical results to the above example:

arguments ={doGlidingProjection = True,
                frameSamplingInterval=3,
                startFrame=0,
                stopFrame=None
                }
gliding_median_channel_0 = channel_0.getTemporalMedianChannel(arguments)

arguments = {doGlidingProjection = False,
                frameSamplingInterval=4,
                startFrame=0,
                stopFrame=None}
binned_4frame_median_channel_0 = channel_0.getTemporalMedianChannel(arguments)

Prepare for Analysis by creating an Analyzer object

Now let’s perform an optical flow analysis of our preprocessed Channel. This is done by instantiating an Analyzer object with a Channel as argument. In this case we will perform an optical flow analysis using the Farenback flow analysis from OpenCV. This is handled by a FarenbackAnalyzer, which is a specific subtype FlowAnalyzer of Analyzer.

FarenbackAnalyzer takes two arguments, one Channel and one unit. unit is a string indicating the unit that we want the output to be in. Currently only “um/s”, “um/min”, and “um/h” are implemented. Cellocity handles all unit conversions automatically in the background.

from cellocity.analysis import FarenbackAnalyzer

fb_analyzer_ch0 = FarenbackAnalyzer(channel = gliding_median_channel_0, unit = "um/h")
fb_analyzer_ch0.doFarenbackFlow()

Note

Quite a lot of effort has gone in to selecting sensible default parameters that work well for microscopy data for the FlowAnalyzer objects FarenbackAnalyzer and OpenPivAnalyzer, as is demonstrated in the Validation of the Cellocity Software section.

Extract data by creating an Analysis object.

Great, now we have calculated the optical flow of channel_0 with the default parameters. Now its time to extract data. This is done by creating Analysis objects. In our case we want to analyse the flow speeds of our channel. To do this we can utilize the FlowSpeedAnalysis class, which works on FlowAnalyzer objects.

from cellocity.analysis import FlowSpeedAnalysis

speed_analysis_ch0 = FlowSpeedAnalysis(fb_analyzer_ch0)
speed_analysis_ch0.calculateSpeeds()
speed_analysis_ch0.calculateAverageSpeeds()

When speeds have been calculated the results can be stored either as a 32-bit tif, where pixel values represent flow speeds in the location of the pixel, or the average speed of each frame can be saved as a .csv file for further processing.

from pathlib import Path

savepath = Path("path/to/save/folder")

speed_analysis_ch0.saveArrayAsTif(outdir=savepath):
speed_analysis_ch0.saveCSV(outdir=savepath, fname="mySpeeds.csv", tunit="s")

That’s it! If you want more detailed information, please check the The Cellocity API Reference , the Validation of the Cellocity Software contains more examples of different Analysis objects in use, and the Developer Information contains information on how to submit a bug report.