Source code for stonesoup.dataassociator.base

# -*- coding: utf-8 -*-
import itertools
from abc import abstractmethod

from ..base import Base, Property
from ..types.hypothesis import JointHypothesis
from ..hypothesiser import Hypothesiser


[docs]class DataAssociator(Base): """Data Associator base class A data associator is used to associate tracks and detections, and may also include an association of a missed detection. The associations generate are in the form a mapping each track to a hypothesis, based on "best" choice from hypotheses generate from a :class:`~.Hypothesiser`. """ hypothesiser: Hypothesiser = Property( doc="Generate a set of hypotheses for each track-detection pair")
[docs] @abstractmethod def associate(self, tracks, detections, timestamp=None, **kwargs): """Associate tracks and detections Parameters ---------- tracks : set of :class:`~.Track` Tracks which detections will be associated to. detections : set of :class:`~.Detection` Detections to be associated to tracks. timestamp : :class:`datetime.datetime` Timestamp to be used for missed detections. Returns ------- : mapping of :class:`~.Track` : :class:`~.Hypothesis` Mapping of track to Hypothesis """ raise NotImplementedError
[docs] @staticmethod def isvalid(joint_hypothesis): """Determine whether a joint_hypothesis is valid. Check the set of hypotheses that define a joint hypothesis to ensure a single detection is not associated to more than one track. Parameters ---------- joint_hypothesis : :class:`JointHypothesis` A set of hypotheses linking each prediction to a single detection Returns ------- bool Whether joint_hypothesis is a valid set of hypotheses """ number_hypotheses = len(joint_hypothesis) unique_hypotheses = len( {hyp.measurement for hyp in joint_hypothesis if hyp}) number_null_hypotheses = sum(not hyp for hyp in joint_hypothesis) # joint_hypothesis is invalid if one detection is assigned to more than # one prediction. Multiple missed detections are valid. if unique_hypotheses + number_null_hypotheses == number_hypotheses: return True else: return False
[docs] @classmethod def enumerate_joint_hypotheses(cls, hypotheses): """Enumerate the possible joint hypotheses. Create a list of all possible joint hypotheses from the individual hypotheses and determine whether each is valid. Parameters ---------- hypotheses : list of :class:`Hypothesis` A list of all hypotheses linking predictions to detections, including missed detections Returns ------- joint_hypotheses : list of :class:`JointHypothesis` A list of all valid joint hypotheses with a score on each """ # Create a list of dictionaries of valid track-hypothesis pairs joint_hypotheses = [ JointHypothesis({ track: hypothesis for track, hypothesis in zip(hypotheses, joint_hypothesis)}) for joint_hypothesis in itertools.product(*hypotheses.values()) if cls.isvalid(joint_hypothesis)] return joint_hypotheses
[docs]class Associator(Base): """Associator base class An associator is used to associate objects for the generation of metrics. It returns a :class:`~.AssociationSet` containing a set of :class:`~.Association` objects. """
[docs]class TrackToTrackAssociator(Associator): """Associates two sets of :class:`~.Track` objects together"""