Segmentation of a GPS track#
This section presents the problem of segmenting a GPS track based on discrete-value criteria or spatiotemporal criteria or a combination of both. The segmentation for a track consists to partition it into a number of pieces of track. The idea of segmentation is to obtain tracks where characteristics inside each ones are uniform in some sens.
In track library, segmentation takes place (cf. figure 1) in two stages. Once the indicators have been calculated, the first step is to create a new analytical feature, named “seg” for example, which value is: 0 if change of division, 1 otherwise by calling segmentation algorithm. The second step consists to split the track using “seg” analytical feature. A collection of tracks are created; all tracks are defined for all observations between the different values of 1 of “seg” AF from the original track.
Figure 1 : process to segmenting track
We have had a brief preview of this treatment in the quickstart use case. Indeed, in the GPS track corresponding to an athletics training, we segment the trajectory depending on the shifting the speed of his running. In this tutorial, we add a second analytical feature, the direction of the edge.
Let’s start by defining our environment#
This task is only useful for the online notebook
[1]:
import matplotlib.pyplot as plt
import numpy as np
import os
import sys
# Import de tracklib
module_path = os.path.abspath(os.path.join('../../..'))
if module_path not in sys.path:
sys.path.append(module_path)
import tracklib as trk
Loading GPS track data#
Data represents a runner’s track on an athletics track (identifier N°903959).
[2]:
trk.ObsTime.setReadFormat("4Y-2M-2DT2h:2m:2sZ")
param = trk.TrackFormat({'ext': 'GPX'})
tracks = trk.TrackReader.readFromFile('../../../data/gpx/activity_5807084803.gpx', param)
trace = tracks.getTrack(0)
# Transformation GEO coordinates to ENU
trace.toENUCoords()
trace.summary()
trace.rotate(-np.pi/4)
plt.figure(figsize=(3, 4))
plt.scatter(trace.getX(), trace.getY(), marker='o', c='#C0C0C0', s=2)
plt.xlim([-100, 10])
plt.ylim([-100, 100])
plt.show()
Warning: no reference point (base) provided for local projection to ENU coordinates. Arbitrarily used: [lon= 2.457019882, lat=48.830705099, hgt= 55.200]
-------------------------------------
GPS track #0 of user 0:
-------------------------------------
Nb of pt(s): 190
Ref sys id : ENU
Starting at : 11/11/2020 15:39:54
Ending at : 11/11/2020 15:52:00
Duration : 726.000 s
Length : 2412.144 m
-------------------------------------

First basic method, with table index#
Tout simplement, vous avez la liste des index des observations qui représentent les limites des différents fragments de la trace.
[3]:
idxFragments = [50, 100, 150, 189]
collection = trk.split(trace, idxFragments)
plt.figure(figsize=(3, 4))
COLORS = ['r-','g-','b-','y-','m-','c-']
for i in range(len(collection)):
collection[i].plot(COLORS[i%6], append=True)
plt.xlim([-100, 10])
plt.ylim([-100, 100])
plt.show()

Segmenting under any of these AF or any combination of these AF#
Step 1: create criteria as Analytical Feature#
Vous n’avez pas les bornes pour la segmenter mais vous avez une méthode pour les calculer. Autrement dit, vous avez un critère permettant de découper la trace. Comme par exemple, la trace du quickstart qui a été découpée suivant les changements de vitesses.
Pour cela, il faut tout d’abord créer des points de rupture, ils seront définis par un AF qui aura un ensemble fini de valeurs. Une coupure sera effective à chaque seuil passé en paramètre.
Vous pouvez même combiner plusieurs AF pour découper la trace. Par défaut l’opérateur de comparaison est AND mais on peut le changer en OU. Dans ce cas, l’ensemble des AF sont définis dans un tableau ainsi que leurs seuils.
A l’issu de la création des marqueurs, la trace est toujours conservée, mais une nouvelle AF est ajoutée. Elle a comme valeurs 0 sauf pour les ruptures, ce sera 1.
[4]:
trace.addAnalyticalFeature(trk.speed)
trace.operate(trk.Operator.DIFFERENTIATOR, "speed", "dv")
trace.operate(trk.Operator.RECTIFIER, "dv", "absdv")
trace.addAnalyticalFeature(trk.heading)
trace.operate(trk.Operator.RECTIFIER, "heading", "absheading")
print ('')
[5]:
trk.segmentation(trace, ["absdv"], "decoup1", [1.5], trk.MODE_COMPARAISON_AND)
trk.segmentation(trace, ["absheading"], "decoup2", [0.1], trk.MODE_COMPARAISON_AND)
trk.segmentation(trace, ["absdv", "absheading"], "decoup3", [1.5, 0.1], trk.MODE_COMPARAISON_AND)
Step 2: split under any of these AF or any combination of these AF#
Il reste à découper la trace suivant le marker créé précédemment. Pour cela, il faut appeler la même fonction split mais en spécifiant cette fois-ci non pas une liste des index, mais le ou les AF
Splits track according to af name (considered as a marker)
Return: No track if no segmentation, otherwise a TrackCollection object
[6]:
TRACES1 = trk.split(trace, "decoup1", limit=40)
TRACES2 = trk.split(trace, "decoup2", limit=40)
TRACES3 = trk.split(trace, "decoup3", limit=40)
[7]:
COLORS = ['r','g','b','y','m','c']
plt.figure(figsize=(10, 9))
plt.subplots_adjust(top=1.3, wspace=0.4, hspace=0.2)
# Figure 1
ax1 = plt.subplot2grid((2, 2), (0, 0))
ax1.scatter(trace.getX(), trace.getY(), marker='o', c='#000000', s=2)
ax1.set_title("A runner's track on an athletics track")
# Figure 2
ax2 = plt.subplot2grid((2, 2), (0, 1))
ax2.scatter(trace.getX(), trace.getY(), marker='o', c='#000000', s=2)
for i in range(len(TRACES1)):
track = TRACES1[i]
ax2.plot(track.getX(), track.getY(), color=COLORS[i%6], linestyle='-', linewidth=2)
ax2.set_xlim([-100, 10])
ax2.set_ylim([-100, 100])
ax2.set_title("Segmentation based on changes in his running speed")
# Figure 3
ax3 = plt.subplot2grid((2, 2), (1, 0))
ax3.scatter(trace.getX(), trace.getY(), marker='o', c='#000000', s=2)
for i in range(len(TRACES2)):
track = TRACES2[i]
ax3.plot(track.getX(), track.getY(), color=COLORS[i%6], linestyle='-', linewidth=3)
ax3.set_xlim([-100, 10])
ax3.set_ylim([-100, 100])
ax3.set_title("Segmentation based on its heading")
# Figure 4
ax4 = plt.subplot2grid((2, 2), (1, 1))
ax4.scatter(trace.getX(), trace.getY(), marker='o', c='#000000', s=2)
for i in range(len(TRACES3)):
track = TRACES3[i]
ax4.plot(track.getX(), track.getY(), color=COLORS[i%6], linestyle='-', linewidth=4)
ax4.set_xlim([-100, 10])
ax4.set_ylim([-100, 100])
ax4.set_title("Segmentation based on its heading AND on changes in his running speed")
[7]:
Text(0.5, 1.0, 'Segmentation based on its heading AND on changes in his running speed')
