Skip to main content

Case study

Benjamin Gallois

Benjamin Gallois

FastTrack creator
Copyright (C) FastTrack.
Permission is granted to copy, distribute and/or modify this document.This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Case study #1#

Objective: track multiple D. Melanogaster and determine the time spent in the upper area of the experimental apparatus. Dataset: http://cloud.ljp.upmc.fr/datasets/TD2/#DRO_004

Import the data#

import fastanalysis as fa
import seaborn as sns
import numpy as np
import matplotlib as mpl
plt.style.use("fivethirtyeight")
import warnings
warnings.filterwarnings('ignore')
data = fa.Load("tracking.txt")

Explore the tracking data#

# Distribution of vertical positions for all the objects
p0 = sns.histplot(data=data.getDataframe(), x="yBody", kde=True);
p0.set_xlabel("Vertical position");

png

# Distribution of vertical positions for each individual
p1 = sns.displot(data=data.getDataframe(), x="yBody", hue="id", kind="kde");
p1.ax.set_xlabel("Vertical position");

png

p2 = sns.boxplot(data=data.getDataframe(), x="id", y="yBody");
p2.set_xlabel("Id");
p2.set_ylabel("Vertical position");

png

Compute the preference#

# For each individual computes a preference index
pi = []
for i in range(data.getObjectNumber()):
dat = data.getObjects(i)
dat.loc[:, "diffTime"] = dat.imageNumber.diff().values
up = dat[dat.yBody > 100]
down = dat[dat.yBody <= 100]
pi.append((up.diffTime.sum() - down.diffTime.sum())/(up.diffTime.sum() + down.diffTime.sum()))
p3 = sns.boxplot(y=pi)
p3.set_ylim(-1, 1)
p3.set_ylabel("Preference index");
p3.set_title("Objects preference to the upper side");

png

p4 = sns.kdeplot(data=data.getDataframe(), x=np.random.normal(size=data.getDataframe().values.shape[0]), y="yBody", fill=True);
p4.set_xlabel("Horizontal position randomized");
p4.set_ylabel("Vertical position");
p4.set_title("Distribution of presence");

png

pi = []
for i in range(data.getObjectNumber()):
dat = data.getObjects(i)
dat.loc[:, "diffTime"] = dat.imageNumber.diff().values
pref = []
for l, __ in enumerate(dat.yBody.values):
up = dat[0:l][dat[0:l].yBody.values > 100]
down = dat[0:l][dat[0:l].yBody.values <= 100]
pref.append((up.diffTime.sum() - down.diffTime.sum())/(up.diffTime.sum() + down.diffTime.sum()))
pi.append(pref)
for i, j in enumerate(pi):
p5= sns.lineplot(x=np.arange(len(j)), y=j, label=str(i))
p5.set_xlabel("Time (images)");
p5.set_ylabel("Preference index");
p5.set_title("Preference index function of time");
p5.legend(title="id", bbox_to_anchor=(1.05, 1));

png

FastAnalysis tutorial

Benjamin Gallois

Benjamin Gallois

FastTrack creator
Copyright (C) FastTrack.
Permission is granted to copy, distribute and/or modify this document.This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Get started with FastAnalysis#

FastAnalysis is a python library that simplifies the importation of a tracking analysis performed with FastTrack. Easily select data for a given object or a given timepoint.

Package installation#

The FastAnalysis package can be installed following the provided instruction at https://github.com/FastTrackOrg/FastAnalysis.

import sys
!{sys.executable} -m pip install fastanalysis

Package usage#

import fastanalysis as fa

Load the tracking data and get the basic information.#

data = fa.Load("tracking.txt")
print("Total objects: ", data.getObjectNumber())
Total objects: 14
print("Keys: ", data.getKeys())
Keys: ['xHead', 'yHead', 'tHead', 'xTail', 'yTail', 'tTail', 'xBody', 'yBody', 'tBody', 'curvature', 'areaBody', 'perimeterBody', 'headMajorAxisLength', 'headMinorAxisLength', 'headExcentricity', 'tailMajorAxisLength', 'tailMinorAxisLength', 'tailExcentricity', 'bodyMajorAxisLength', 'bodyMinorAxisLength', 'bodyExcentricity', 'imageNumber', 'id']

Select the tracking data for a given object#

data.getObjects(0)
xHeadyHeadtHeadxTailyTailtTailxBodyyBodytBodycurvature...headMinorAxisLengthheadExcentricitytailMajorAxisLengthtailMinorAxisLengthtailExcentricitybodyMajorAxisLengthbodyMinorAxisLengthbodyExcentricityimageNumberid
0514.327333.1205.816190499.960327.7276.102260508.345330.8765.9439500.000348...2.986260.92138811.407502.064610.98348517.75782.862270.98692400
14512.965332.5755.866170499.435327.7596.052000507.626330.6735.9510200.000370...2.949200.92158910.630101.796320.98561916.59122.559000.98803410
28510.519331.4175.888830495.784327.3666.128890504.484329.7586.0208800.000285...3.026470.93193711.808201.976100.98589817.95812.761520.98810620
42508.379330.5425.978240493.210327.4606.159440502.213329.2916.0839200.000217...3.100270.92864911.670101.976230.98555818.08202.706410.98873530
56503.990331.7644.889370496.990322.5096.183440501.029327.8565.3787600.001812...2.920670.9146808.251743.012760.93096613.09475.194180.91796540
..................................................................
2414515.720332.2330.047758504.152332.7586.219550510.844332.4560.0315500.000053...2.836200.8910317.969852.214980.96060413.37942.480610.9826621950
2428514.518331.2296.173800502.533333.4480.410982509.848332.0910.1881330.000454...3.014480.8952299.275581.867100.97953114.09093.118600.9752011960
2442515.022333.3016.039930503.432330.3606.110450510.456332.1446.0461900.000040...2.862680.8945788.454941.973920.97236513.74232.443180.9840691970
2456514.364332.3220.089009501.409333.2716.061220509.183332.6990.0302770.000309...2.706090.9261439.873312.720560.96128815.09903.040300.9795181980
2470514.682333.1746.045460503.418331.4820.110999510.000332.4726.1645600.000434...2.905090.8811788.319822.311970.96061413.21192.862640.9762451990

190 rows × 23 columns

Select the tracking data for a list of objects#

data.getObjects([0, 2, 4])
xHeadyHeadtHeadxTailyTailtTailxBodyyBodytBodycurvature...headMinorAxisLengthheadExcentricitytailMajorAxisLengthtailMinorAxisLengthtailExcentricitybodyMajorAxisLengthbodyMinorAxisLengthbodyExcentricityimageNumberid
0514.3270333.1205.816190499.9600327.7276.102260508.3450330.8765.9439500.000348...2.986260.92138811.407502.064610.98348517.75782.862270.98692400
223.9978287.7153.70646034.9722278.8363.99819029.2056283.5053.8484400.000714...3.022240.87828411.092502.613040.97185816.56703.009620.98336102
4480.5800213.4821.282360478.1250228.5201.533030479.4280220.5431.4256700.000539...3.452080.87382811.803602.224890.98207517.92043.029780.98560404
14512.9650332.5755.866170499.4350327.7596.052000507.6260330.6735.9510200.000370...2.949200.92158910.630101.796320.98561916.59122.559000.98803410
1619.4579293.0224.28861025.5579281.2064.18379021.8962288.3024.2337900.000041...3.105270.8937778.954531.953080.97592415.14972.606900.98508412
..................................................................
2449477.5150253.2590.494507466.0410261.0180.831531472.8820256.3820.6224160.000357...3.183300.8903229.949442.331950.97214515.84643.121300.9804091982
2456514.3640332.3220.089009501.4090333.2716.061220509.1830332.6990.0302770.000309...2.706090.9261439.873312.720560.96128815.09903.040300.9795181980
2462413.9010332.3865.582420401.1560322.8155.799440408.5330328.3565.6579200.000666...3.249540.92055511.510302.472300.97666018.49793.051430.9863001994
2463479.2630250.7160.644442465.5060258.4760.362501473.8190253.7840.5034160.000200...2.964350.93026211.552501.764070.98827318.13292.751700.9884191992
2470514.6820333.1746.045460503.4180331.4820.110999510.0000332.4726.1645600.000434...2.905090.8811788.319822.311970.96061413.21192.862640.9762451990

544 rows × 23 columns

Select the tracking data for a given image#

data.getFrames(100)
xHeadyHeadtHeadxTailyTailtTailxBodyyBodytBodycurvature...headMinorAxisLengthheadExcentricitytailMajorAxisLengthtailMinorAxisLengthtailExcentricitybodyMajorAxisLengthbodyMinorAxisLengthbodyExcentricityimageNumberid
1220471.9020331.890000.269094460.4110335.53600.205151467.340333.34000.2859300.000054...3.023250.8793429.42872.362850.96809014.06882.711880.9812461000
1221394.0560311.183005.862420380.7090302.96605.533100388.653307.86805.7105700.000782...3.186650.91114112.05672.132180.98423818.02803.116680.9849431009
1222294.9150323.621005.928470280.3880319.39406.078460289.216321.96406.0063400.000511...3.085210.90804111.15571.664430.98880717.28672.575670.9888381002
1223219.1200191.089000.631238205.3180198.12800.088934213.337194.04100.4375130.000843...3.960580.88192710.67983.266380.95208117.76984.407370.9687531003
1224191.985048.839601.338080185.160062.87220.851539188.64855.64791.0732400.001664...3.498890.86710112.00512.620740.97588118.39143.786920.9785721005
1225504.05209.828320.558700489.462018.42430.514300497.87813.46940.5317250.000089...3.411340.91230312.33651.994890.98683919.57192.784730.98982610013
1226304.1520202.554005.721260290.9760193.59605.719690298.600198.77705.6952400.000052...3.280290.90531511.63251.985470.98532618.47332.687150.9893641007
1227413.6920329.851000.026077399.8350331.48400.161337408.339330.48200.1138990.000115...3.073540.91478610.46481.936150.98273616.16562.631910.98665710012
122884.2595119.739003.79733096.9216110.71603.73422090.450115.32903.7564200.000192...3.526030.85367012.64272.158300.98532118.53392.842530.98816910010
1229364.406035.894100.353083348.850040.42746.276460357.95937.77400.2516170.000484...3.373840.92017111.34583.336960.95577018.61913.795430.9790031004
1230490.663044.942200.503424476.704052.56560.472187485.12547.97060.4955290.000124...3.275670.92236810.99151.971340.98378518.27922.724580.98882910011
1231510.174040.702705.941170497.300034.72025.673400505.11038.34865.8304100.000431...3.116210.90213410.28662.083100.97928116.23742.872590.9842271006

12 rows × 23 columns

Select the tracking data for a list of images#

data.getFrames([100, 102])
xHeadyHeadtHeadxTailyTailtTailxBodyyBodytBodycurvature...headMinorAxisLengthheadExcentricitytailMajorAxisLengthtailMinorAxisLengthtailExcentricitybodyMajorAxisLengthbodyMinorAxisLengthbodyExcentricityimageNumberid
1220471.9020331.890000.269094460.4110335.53600.205151467.3400333.34000.2859300.000054...3.023250.8793429.428702.362850.96809014.06882.711880.9812461000
1221394.0560311.183005.862420380.7090302.96605.533100388.6530307.86805.7105700.000782...3.186650.91114112.056702.132180.98423818.02803.116680.9849431009
1222294.9150323.621005.928470280.3880319.39406.078460289.2160321.96406.0063400.000511...3.085210.90804111.155701.664430.98880717.28672.575670.9888381002
1223219.1200191.089000.631238205.3180198.12800.088934213.3370194.04100.4375130.000843...3.960580.88192710.679803.266380.95208117.76984.407370.9687531003
1224191.985048.839601.338080185.160062.87220.851539188.648055.64791.0732400.001664...3.498890.86710112.005102.620740.97588118.39143.786920.9785721005
1225504.05209.828320.558700489.462018.42430.514300497.878013.46940.5317250.000089...3.411340.91230312.336501.994890.98683919.57192.784730.98982610013
1226304.1520202.554005.721260290.9760193.59605.719690298.6000198.77705.6952400.000052...3.280290.90531511.632501.985470.98532618.47332.687150.9893641007
1227413.6920329.851000.026077399.8350331.48400.161337408.3390330.48200.1138990.000115...3.073540.91478610.464801.936150.98273616.16562.631910.98665710012
122884.2595119.739003.79733096.9216110.71603.73422090.4500115.32903.7564200.000192...3.526030.85367012.642702.158300.98532118.53392.842530.98816910010
1229364.406035.894100.353083348.850040.42746.276460357.959037.77400.2516170.000484...3.373840.92017111.345803.336960.95577018.61913.795430.9790031004
1230490.663044.942200.503424476.704052.56560.472187485.125047.97060.4955290.000124...3.275670.92236810.991501.971340.98378518.27922.724580.98882910011
1231510.174040.702705.941170497.300034.72025.673400505.110038.34865.8304100.000431...3.116210.90213410.286602.083100.97928116.23742.872590.9842271006
1244471.4650333.537000.001856455.8950333.13700.067247465.2880333.37806.2743800.000043...3.020420.92220111.221602.375280.97734117.82542.667390.9887411020
1245396.0970314.669005.861210381.8960308.44705.874390390.4180312.18005.8703400.000174...3.301170.89973711.373001.843610.98677417.80032.684290.9885641029
1246294.3930324.256005.943700279.2910320.19506.066590288.5890322.69606.0208800.000204...3.054220.91695111.740101.616880.99047117.89232.528350.9899661022
1247220.4620188.585000.373316205.5400192.79700.203012214.4550190.28100.2741690.000333...4.104330.85991510.676802.459920.97309617.73993.509930.9802311023
1248440.7830245.341000.994409432.8300259.22901.086010437.0160251.92101.0574800.000134...3.148100.90116512.806901.984030.98792719.21852.573220.9909961028
1249181.716048.267401.795220183.281064.69471.403630182.458056.22881.6187000.003078...3.549040.87775613.013903.974630.95222019.45174.327840.9749351025
1250501.16507.834230.516324484.943016.98560.489818494.558011.56410.5100980.000011...3.437800.92519512.715001.937350.98832421.22122.826280.99109210213
1251299.4490204.642005.764900288.1070193.91805.171220294.7050200.16005.5066500.004240...3.511180.91843610.650602.644290.96868917.96874.105680.9735461027
1252423.3440226.693001.685010423.8160242.81901.563020423.5670234.34301.5962000.000203...3.482680.85736612.903702.012380.98776419.01442.792580.9891561021
1253419.6690331.305000.240837405.4400333.29206.160820413.7010332.13700.1049040.000355...3.164410.90444410.927102.835840.96573716.71113.409280.97896810212
125474.8227119.963003.81445087.7565110.91203.72207080.8288115.76003.7493500.000395...3.660700.85866212.484002.126600.98538418.73892.972670.98733710210
1255372.356033.297500.324467357.087035.50026.115410365.944034.22380.1091670.000586...3.469470.90275911.640002.454000.97752417.88633.818490.9769461024
1256486.907043.341600.455006472.011050.96010.484798480.885046.42570.4720280.000043...3.400550.92001110.946802.101200.98140519.03972.830450.98888810211
1257506.598042.846105.625700494.800035.60515.914810501.873039.94925.7496800.000309...3.319370.8894439.903122.086010.97756315.91513.017960.9818561026

26 rows × 23 columns

Select the tracking data for a list of images and a list of objects#

data.getObjectsInFrames(ids=[0,2,4], indexes=[100,102])
xHeadyHeadtHeadxTailyTailtTailxBodyyBodytBodycurvature...headMinorAxisLengthheadExcentricitytailMajorAxisLengthtailMinorAxisLengthtailExcentricitybodyMajorAxisLengthbodyMinorAxisLengthbodyExcentricityimageNumberid
1220471.902331.89000.269094460.411335.53600.205151467.340333.34000.2859300.000054...3.023250.8793429.42872.362850.96809014.06882.711880.9812461000
1222294.915323.62105.928470280.388319.39406.078460289.216321.96406.0063400.000511...3.085210.90804111.15571.664430.98880717.28672.575670.9888381002
1229364.40635.89410.353083348.85040.42746.276460357.95937.77400.2516170.000484...3.373840.92017111.34583.336960.95577018.61913.795430.9790031004
1244471.465333.53700.001856455.895333.13700.067247465.288333.37806.2743800.000043...3.020420.92220111.22162.375280.97734117.82542.667390.9887411020
1246294.393324.25605.943700279.291320.19506.066590288.589322.69606.0208800.000204...3.054220.91695111.74011.616880.99047117.89232.528350.9899661022
1255372.35633.29750.324467357.08735.50026.115410365.94434.22380.1091670.000586...3.469470.90275911.64002.454000.97752417.88633.818490.9769461024

6 rows × 23 columns

Check if a list of objects is in a frame#

data.isObjectsInFrame(ids=[0,2,4], index=100)
[True, True, True]

Basic plotting#

  • Plot the velocity distribution for given objects
import matplotlib.pyplot as plt
%matplotlib inline
plotObj = fa.Plot(data)
plotObj.velocityDistribution(ids=[0, 1], key="Body", pooled=False, subplots=True);

png

plotObj.velocityDistribution(ids=[0, 1], key="Body", pooled=False, subplots=False);

png

plotObj.velocityDistribution(ids=[0, 1], key="Body", pooled=True);

png

Using seaborn on extracted data#

  • Plot the distribution of positions.
import seaborn as sns
data_object_0 = data.getObjects(0)
sns.jointplot(data=data_object_0, x="xBody", y="yBody");

png

# All objects pooled
sns.kdeplot(data=data.getObjects(list(range(data.getObjectNumber()))), x="xBody", y="yBody", shade=True);

png

  • Compare the distributions of displacements.
tmp = data.getObjects([0,2,4])
tmp["displacement"] = (tmp["xBody"]**2 + tmp["yBody"]**2)**0.5
sns.violinplot(data=tmp, x="id", y="displacement");

png

sns.boxplot(data=tmp, x="id", y="displacement");

png

sns.boxenplot(data=tmp, x="id", y="displacement");

png

Data analysis using Julia

Benjamin Gallois

Benjamin Gallois

FastTrack creator
Copyright (C) FastTrack.
Permission is granted to copy, distribute and/or modify this document.This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Data analysis using Julia#

Introduction#

The Julia documentation and installation guide can be found at https://julialang.org/. We provide here a simple example that details how to import the tracking.txt file from FastTrack, and how to extract basic information like the number of objects, the number of images etc...

using DataFrames
using CSV
using PyPlot
using Plots
using StatsPlots

Importation#

We are going to import the tracking file in a DataFrames. Note that the user needs to provide the full path to the tracking.txt file.

data = CSV.read("tracking.txt", delim='\t', DataFrame)
display(data)

2,475 rows × 23 columns (omitted printing of 14 columns)

xHeadyHeadtHeadxTailyTailtTailxBodyyBodytBody
Float64Float64Float64Float64Float64Float64Float64Float64Float64
1514.327333.125.81619499.96327.7276.10226508.345330.8765.94395
2463.603327.0510.301279449.585330.3230.245547458.058328.3460.238877
323.9978287.7153.7064634.9722278.8363.9981929.2056283.5053.84844
4372.536230.1430.194641354.226231.6046.08737364.822230.7590.0515087
5480.58213.4821.28236478.125228.521.53303479.428220.5431.42567
6171.682143.556.09077155.507140.1166.1146164.913142.1136.08216
7498.151121.326.00177483.712119.2850.0223247492.683120.556.15298
8329.56123.4186.08726312.526119.0425.9098322.531121.6146.01722
9465.256115.0454.44359470.05799.9114.40559467.106109.2054.40862
10423.66366.37890.0888056409.10567.29716.12053417.61566.76230.0292602
11424.48740.42325.48198411.59430.39125.88869418.9636.11925.64923
12370.59135.21475.99688354.67229.56335.89121364.00732.87675.94008
13498.50220.25275.66339487.2549.194995.39497493.75815.57815.5026
14367.7915.030346.05933352.0766.756030.653641361.125.759040.152688
15512.965332.5755.86617499.435327.7596.052507.626330.6735.95102
16463.385324.6590.707451.431332.1930.246265458.959327.4430.542368
1719.4579293.0224.2886125.5579281.2064.1837921.8962288.3024.23379
18379.037230.5276.10571361.728229.6160.199343371.74230.1446.25939
19478.884206.7121.27832475.454221.7571.40929477.197214.1081.35472
20173.923143.0420.00732468157.261142.1826.00453167.066142.6896.20403
21498.561122.6875.83253486.357118.1966.13893493.718120.9065.95151
22328.812124.1346.05932312.848119.6055.98617322.331122.2946.00901
23461.738116.7314.47649466.371101.7364.40285463.615110.6564.41641
24428.63169.27155.87139415.66564.64446.13862423.21867.33645.96558
25425.82144.99425.59983414.8433.20285.37159421.24840.08975.461
26368.36235.62195.97427353.2230.46255.88261362.10933.48915.94605
27503.48422.72935.76026489.63216.63155.92136497.92420.28575.86668
28369.1845.840746.15994352.6224.253286.24787362.1445.167666.19236
29510.519331.4175.88883495.784327.3666.12889504.484329.7586.02088
30464.242323.5330.290639451.756328.1940.532686459.432325.3260.37736
&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;

Basic information#

We are going to extract the basic tracking information:

  • Object's id
  • Number of objects
  • Number of images
  • Number of images with at least one object detected
objects = Set(data.id)
print("Objects id: ", objects)
Objects id: Set([10, 5, 9, 8, 13, 4, 1, 0, 12, 7, 11, 2, 3, 6])
numObjects = length(objects)
print("Number of objects: ", numObjects)
Number of objects: 14
numImages = maximum(data.imageNumber) + 1 # Image index starting at 0
print("Number of images: ", numImages)
Number of images: 200
numDetected = length(Set(data.imageNumber))
print("Number of images with at least one object detected: ", numDetected)
Number of images with at least one object detected: 200

Basic plots#

We are going to make basic plots using Plots, StatsPlots and the PyPlot (that require a valid matplotlib installation) modules. For more information about plotting see https://docs.juliaplots.org/latest/tutorial/.

objectsByImage = zeros(numImages)
for i in 1:numImages
objectsByImage[i] = length(Set(data.id[data.imageNumber .== i-1]))
end
Plots.plot(1:numImages, objectsByImage; title="Number of detected objects by frame", xlabel="Frames", ylabel="Objects", label=false)

svg

dataObject0 = data[data.id .== 0, :]
distance = sqrt.(diff(dataObject0.xBody).^2 + diff(dataObject0.yBody).^2)
framerate = 25
time = diff(dataObject0.imageNumber)/framerate
velocity = distance./time
fig, ax = PyPlot.subplots(1, 2)
fig.subplots_adjust(right = 2)
ax[1] = PyPlot.subplot(121)
plot = ax[1].scatter(dataObject0.xBody[1:end-1], dataObject0.yBody[1:end-1], c=velocity, s=40)
ax[1].set_title("Object displacement")
ax[1].set_xlabel("x-position")
ax[1].set_ylabel("y-position")
bar = fig.colorbar(plot)
bar.set_label("Velocity")
ax[2] = PyPlot.subplot(122, projection="polar")
ax[2].scatter(1:length(dataObject0.tBody), dataObject0.tBody, s=40)
ax[2].set_title("Object direction")

png

PyObject Text(0.5, 1.0715488215488216, 'Object direction')
velocities = Any[]
for i in 1:numObjects
distance = sqrt.(diff(data.xBody[data.id .== i-1]).^2 + diff(data.yBody[data.id .== i-1]).^2)
time = diff(data.imageNumber[data.id .== i-1])/25
velocity = distance./time
append!(velocities, [velocity])
end
StatsPlots.boxplot(velocities, label=false, title="Velocity distributions", ylabel="Velocity (px/s)", xlabel="Objects")

svg

Data analysis using Python

Benjamin Gallois

Benjamin Gallois

FastTrack creator
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Import the data
data = pd.read_csv("tracking.txt", sep='\t')
data

2,475 rows × 23 columns (omitted printing of 14 columns)

xHeadyHeadtHeadxTailyTailtTailxBodyyBodytBody
Float64Float64Float64Float64Float64Float64Float64Float64Float64
1514.327333.125.81619499.96327.7276.10226508.345330.8765.94395
2463.603327.0510.301279449.585330.3230.245547458.058328.3460.238877
323.9978287.7153.7064634.9722278.8363.9981929.2056283.5053.84844
4372.536230.1430.194641354.226231.6046.08737364.822230.7590.0515087
5480.58213.4821.28236478.125228.521.53303479.428220.5431.42567
6171.682143.556.09077155.507140.1166.1146164.913142.1136.08216
7498.151121.326.00177483.712119.2850.0223247492.683120.556.15298
8329.56123.4186.08726312.526119.0425.9098322.531121.6146.01722
9465.256115.0454.44359470.05799.9114.40559467.106109.2054.40862
10423.66366.37890.0888056409.10567.29716.12053417.61566.76230.0292602
11424.48740.42325.48198411.59430.39125.88869418.9636.11925.64923
12370.59135.21475.99688354.67229.56335.89121364.00732.87675.94008
13498.50220.25275.66339487.2549.194995.39497493.75815.57815.5026
14367.7915.030346.05933352.0766.756030.653641361.125.759040.152688
15512.965332.5755.86617499.435327.7596.052507.626330.6735.95102
16463.385324.6590.707451.431332.1930.246265458.959327.4430.542368
1719.4579293.0224.2886125.5579281.2064.1837921.8962288.3024.23379
18379.037230.5276.10571361.728229.6160.199343371.74230.1446.25939
19478.884206.7121.27832475.454221.7571.40929477.197214.1081.35472
20173.923143.0420.00732468157.261142.1826.00453167.066142.6896.20403
21498.561122.6875.83253486.357118.1966.13893493.718120.9065.95151
22328.812124.1346.05932312.848119.6055.98617322.331122.2946.00901
23461.738116.7314.47649466.371101.7364.40285463.615110.6564.41641
24428.63169.27155.87139415.66564.64446.13862423.21867.33645.96558
25425.82144.99425.59983414.8433.20285.37159421.24840.08975.461
26368.36235.62195.97427353.2230.46255.88261362.10933.48915.94605
27503.48422.72935.76026489.63216.63155.92136497.92420.28575.86668
28369.1845.840746.15994352.6224.253286.24787362.1445.167666.19236
29510.519331.4175.88883495.784327.3666.12889504.484329.7586.02088
30464.242323.5330.290639451.756328.1940.532686459.432325.3260.37736
&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;&vellip;
# Count the number of detected object
objectNumber = len(set(data["id"].values))
objectNumber
2
# Count the number of image
imageNumber = np.max(data["imageNumber"]) + 1
imageNumber
2000
# Plot the number of objects detected by frame
objectByFrame = np.zeros(imageNumber)
for i in range(imageNumber):
objectByFrame[i] = data[data["imageNumber"] == i].shape[0]
plt.scatter(range(imageNumber), objectByFrame)
<matplotlib.collections.PathCollection at 0x7fa41831c6d8>

png

# Plot the trajectory of the first object and its orientation
dataObject0 = data[data["id"] == 0]
distance = np.sqrt(np.diff(dataObject0["xBody"].values)**2 + np.diff(dataObject0["yBody"].values)**2)
framerate = 50
time = np.diff(dataObject0["imageNumber"].values)/framerate
velocity = distance/time
fig, ax = plt.subplots(1, 2)
fig.subplots_adjust(right = 2)
ax[0] = plt.subplot(121)
plot = ax[0].scatter(dataObject0["xBody"][0:-1], dataObject0["yBody"][0:-1], c = velocity, s = 1)
ax[0].set_xlabel("x-position")
ax[0].set_ylabel("y-position")
bar = fig.colorbar(plot)
bar.set_label("Velocity")
ax[1] = plt.subplot(122, projection='polar')
ax[1].scatter(range(dataObject0["tBody"].shape[0]), dataObject0["tBody"], s = 0.4)
ax[1].set_title("Object direction")
Text(0.5, 1.05, 'Object direction')

png

Introducing feature based registration

Benjamin Gallois

Benjamin Gallois

Fast Track creator

Fast Track is now integration feature-based registration alongside the other registration methods. Feature-based registration consists of finding stable points in an image, these points are called key points and their descriptors. Then the same key points are found in the second image. From these key points, a homography is computed between the two images and the transformation is applied to all the pixels of the image to register.

Feature automatic detection#

Fast Track used an automatic algorithm to find the key points and the descriptors (~500) in the two images. This algorithm is called ORB feature detector and was brought up by Ethan Rublee, Vincent Rabaud, Kurt Konolige and Gary R. Bradski in 2011.

Feature matching#

The key points are matched pairwise between the two images using the Hamming distance. The Hamming distance measures the minimum number of errors that could transform one feature descriptor in another one.

Compute the homography#

The homography is computed between the matching key points. It is possible that more than 30% of the features matched are incorrect. To reduce errors when finding the homography, Fast Track used Random Sample Consensus RANSAC estimation technic brought up by Fischler and Bolles in 1981.

This new registration method will be available in the 4.8 Fast Track release. It can be tested in the nightly build and on the dev branch on GitLab.

Introducing ECC registration

Benjamin Gallois

Benjamin Gallois

Fast Track creator

Fast Track is now integrating a new method of registration: the so-called ECC registration. This method was developed by Georgios D. Evangelidis and Emmanouil Z. Psarakis. It consists of maximizing the Enhanced Correlation Coefficient function to find the parameters that described the best transformation between the two images. This is done by solving iteratively a sequence of nonlinear optimization problems.

This method has several advantages:

  • Invariant with respect to photometric distortion, ie, in contrast, and brightness changes.
  • The optimization problem solution is linear, ie, the computing time is acceptable.
  • This method performs well in noisy conditions.

For the moment, only one mode of registration is integrated into Fast Track. The euclidian mode can correct the translation and rotation of the image. For example, this mode can correct small camera vibrations.

Currently in testing, this registration mode will be available in the 4.8.0 version. You can test this feature in the nightly release or in the dev branch on the GitLab.