Пример #1
0
    def test_correct_deserialization(self):
        base_dir = os.path.dirname(__file__)

        serializer = EPTSSerializer()

        with open(f"{base_dir}/files/epts_meta.xml",
                  "rb") as metadata, open(f"{base_dir}/files/epts_raw.txt",
                                          "rb") as raw_data:

            dataset = serializer.deserialize(inputs={
                "metadata": metadata,
                "raw_data": raw_data
            })

        first_player = next(iter(dataset.records[0].players_coordinates))

        assert len(dataset.records) == 2
        assert len(dataset.metadata.periods) == 1
        assert dataset.metadata.orientation is None

        assert dataset.records[0].players_coordinates[first_player] == Point(
            x=-769, y=-2013)

        assert dataset.records[0].ball_coordinates == Point3D(x=-2656,
                                                              y=367,
                                                              z=100)
Пример #2
0
    def _frame_from_row(row: dict, metadata: EPTSMetadata) -> Frame:
        timestamp = row["timestamp"]
        if metadata.periods and row["period_id"]:
            # might want to search for it instead
            period = metadata.periods[row["period_id"] - 1]
        else:
            period = None

        players_coordinates = {}
        for team in metadata.teams:
            for player in team.players:
                if f"player_{player.player_id}_x" in row:
                    players_coordinates[player] = Point(
                        x=row[f"player_{player.player_id}_x"],
                        y=row[f"player_{player.player_id}_y"],
                    )

        return Frame(
            frame_id=row["frame_id"],
            timestamp=timestamp,
            ball_owning_team=None,
            ball_state=None,
            period=period,
            players_coordinates=players_coordinates,
            ball_coordinates=Point3D(x=row["ball_x"],
                                     y=row["ball_y"],
                                     z=row["ball_z"]),
        )
Пример #3
0
    def __change_point_coordinate_system(self, point: Union[Point, Point3D]):

        if not point:
            return None

        x = self._from_coordinate_system.pitch_dimensions.x_dim.to_base(
            point.x
        )
        y = self._from_coordinate_system.pitch_dimensions.y_dim.to_base(
            point.y
        )

        if (
            self._from_coordinate_system.vertical_orientation
            != self._to_coordinate_system.vertical_orientation
        ):
            y = 1 - y

        if not self._to_coordinate_system.normalized:
            x = self._to_coordinate_system.pitch_dimensions.x_dim.from_base(x)
            y = self._to_coordinate_system.pitch_dimensions.y_dim.from_base(y)

        if isinstance(point, Point3D):
            return Point3D(x=x, y=y, z=point.z)
        else:
            return Point(x=x, y=y)
Пример #4
0
    def test_correct_deserialization(self, meta_data: str, raw_data: str,
                                     additional_meta_data: str):
        dataset = secondspectrum.load(
            meta_data=meta_data,
            raw_data=raw_data,
            additional_meta_data=additional_meta_data,
            only_alive=False,
            coordinates="secondspectrum",
        )

        # Check provider, type, shape, etc
        assert dataset.metadata.provider == Provider.SECONDSPECTRUM
        assert dataset.dataset_type == DatasetType.TRACKING
        assert len(dataset.records) == 376
        assert len(dataset.metadata.periods) == 2
        assert dataset.metadata.orientation == Orientation.FIXED_AWAY_HOME

        # Check the Periods
        assert dataset.metadata.periods[0].id == 1
        assert dataset.metadata.periods[0].start_timestamp == 0
        assert dataset.metadata.periods[0].end_timestamp == 2982240
        assert (dataset.metadata.periods[0].attacking_direction ==
                AttackingDirection.AWAY_HOME)

        assert dataset.metadata.periods[1].id == 2
        assert dataset.metadata.periods[1].start_timestamp == 3907360
        assert dataset.metadata.periods[1].end_timestamp == 6927840
        assert (dataset.metadata.periods[1].attacking_direction ==
                AttackingDirection.HOME_AWAY)

        # Check some timestamps
        assert dataset.records[0].timestamp == 0  # First frame
        assert dataset.records[20].timestamp == 320.0  # Later frame

        # Check some players
        home_player = dataset.metadata.teams[0].players[2]
        assert home_player.player_id == "8xwx2"
        assert dataset.records[0].players_coordinates[home_player] == Point(
            x=-8.943903672572427, y=-28.171654132650364)

        away_player = dataset.metadata.teams[1].players[3]
        assert away_player.player_id == "2q0uv"
        assert dataset.records[0].players_coordinates[away_player] == Point(
            x=-45.11871334915762, y=-20.06459030559596)

        # Check the ball
        assert dataset.records[1].ball_coordinates == Point3D(
            x=-23.147073918432426, y=13.69367399756424, z=0.0)

        # Check pitch dimensions
        pitch_dimensions = dataset.metadata.pitch_dimensions
        assert pitch_dimensions.x_dim.min == -52.425
        assert pitch_dimensions.x_dim.max == 52.425
        assert pitch_dimensions.y_dim.min == -33.985
        assert pitch_dimensions.y_dim.max == 33.985
Пример #5
0
    def _frame_from_row(row: dict, metadata: EPTSMetadata,
                        transformer: DatasetTransformer) -> Frame:
        timestamp = row["timestamp"]
        if metadata.periods and row["period_id"]:
            # might want to search for it instead
            period = metadata.periods[row["period_id"] - 1]
        else:
            period = None

        other_sensors = []
        for sensor in metadata.sensors:
            if sensor.sensor_id not in ["position", "distance", "speed"]:
                other_sensors.append(sensor)

        players_data = {}
        for team in metadata.teams:
            for player in team.players:

                other_data = {}
                for sensor in other_sensors:
                    other_data.update({
                        sensor.sensor_id:
                        row[f"player_{player.player_id}_{sensor.channels[0].channel_id}"]
                    })

                players_data[player] = PlayerData(
                    coordinates=Point(
                        x=row[f"player_{player.player_id}_x"],
                        y=row[f"player_{player.player_id}_y"],
                    ) if f"player_{player.player_id}_x" in row else None,
                    speed=row[f"player_{player.player_id}_s"]
                    if f"player_{player.player_id}_s" in row else None,
                    distance=row[f"player_{player.player_id}_d"]
                    if f"player_{player.player_id}_d" in row else None,
                    other_data=other_data,
                )

        frame = Frame(
            frame_id=row["frame_id"],
            timestamp=timestamp,
            ball_owning_team=None,
            ball_state=None,
            period=period,
            players_data=players_data,
            other_data={},
            ball_coordinates=Point3D(x=row["ball_x"],
                                     y=row["ball_y"],
                                     z=row.get("ball_z")),
        )

        if transformer:
            frame = transformer.transform_frame(frame)

        return frame
Пример #6
0
    def test_transform(self):
        tracking_data = self._get_tracking_dataset()

        # orientation change AND dimension scale
        transformed_dataset = tracking_data.transform(
            to_orientation="AWAY_TEAM",
            to_pitch_dimensions=[[0, 1], [0, 1]],
        )

        assert transformed_dataset.frames[0].ball_coordinates == Point3D(x=0,
                                                                         y=1,
                                                                         z=0)
        assert transformed_dataset.frames[1].ball_coordinates == Point3D(x=1,
                                                                         y=0,
                                                                         z=1)
        assert (
            transformed_dataset.metadata.orientation == Orientation.AWAY_TEAM)
        assert transformed_dataset.metadata.coordinate_system is None
        assert (
            transformed_dataset.metadata.pitch_dimensions == PitchDimensions(
                x_dim=Dimension(min=0, max=1), y_dim=Dimension(min=0, max=1)))
Пример #7
0
    def change_point_dimensions(self, point: Union[Point, Point3D]) -> Point:

        if point is None:
            return None

        x_base = self._from_pitch_dimensions.x_dim.to_base(point.x)
        y_base = self._from_pitch_dimensions.y_dim.to_base(point.y)

        x = self._to_pitch_dimensions.x_dim.from_base(x_base)
        y = self._to_pitch_dimensions.y_dim.from_base(y_base)

        if isinstance(point, Point3D):
            return Point3D(x=x, y=y, z=point.z)
        else:
            return Point(x=x, y=y)
Пример #8
0
    def _frame_from_framedata(cls, teams, period, frame_data):

        frame_id = frame_data["frameIdx"]
        frame_timestamp = frame_data["gameClock"]

        if frame_data["ball"]["xyz"]:
            ball_x, ball_y, ball_z = frame_data["ball"]["xyz"]
            ball_coordinates = Point3D(
                float(ball_x), float(ball_y), float(ball_z)
            )
        else:
            ball_coordinates = None

        ball_state = BallState.ALIVE if frame_data["live"] else BallState.DEAD
        ball_owning_team = (
            teams[0] if frame_data["lastTouch"] == "home" else teams[1]
        )

        players_data = {}
        for team, team_str in zip(teams, ["homePlayers", "awayPlayers"]):
            for player_data in frame_data[team_str]:

                jersey_no = player_data["number"]
                x, y, _ = player_data["xyz"]
                player = team.get_player_by_jersey_number(jersey_no)

                if not player:
                    player = Player(
                        player_id=player_data["playerId"],
                        team=team,
                        jersey_no=int(jersey_no),
                    )
                    team.players.append(player)

                players_data[player] = PlayerData(
                    coordinates=Point(float(x), float(y))
                )

        return Frame(
            frame_id=frame_id,
            timestamp=frame_timestamp,
            ball_coordinates=ball_coordinates,
            ball_state=ball_state,
            ball_owning_team=ball_owning_team,
            players_data=players_data,
            period=period,
            other_data={},
        )
Пример #9
0
    def test_correct_deserialization(self, meta_data: str, raw_data: str):
        dataset = metrica.load_tracking_epts(
            meta_data=meta_data, raw_data=raw_data
        )

        first_player = next(iter(dataset.records[0].players_data))

        assert len(dataset.records) == 100
        assert len(dataset.metadata.periods) == 2
        assert dataset.metadata.orientation is None

        assert dataset.records[0].players_data[
            first_player
        ].coordinates == Point(x=0.30602, y=0.97029)

        assert dataset.records[0].ball_coordinates == Point3D(
            x=0.52867, y=0.7069, z=None
        )
Пример #10
0
    def flip_point(self, point: Union[Point, Point3D]):

        if not point:
            return None

        x_base = self._to_pitch_dimensions.x_dim.to_base(point.x)
        y_base = self._to_pitch_dimensions.y_dim.to_base(point.y)

        x_base = 1 - x_base
        y_base = 1 - y_base

        x = self._to_pitch_dimensions.x_dim.from_base(x_base)
        y = self._to_pitch_dimensions.y_dim.from_base(y_base)

        if isinstance(point, Point3D):
            return Point3D(x=x, y=y, z=point.z)
        else:
            return Point(x=x, y=y)
Пример #11
0
    def _frame_from_line(cls, teams, period, line, frame_rate):
        line = str(line)
        frame_id, players, ball = line.strip().split(":")[:3]

        players_data = {}

        for player_data in players.split(";")[:-1]:
            team_id, target_id, jersey_no, x, y, speed = player_data.split(",")
            team_id = int(team_id)

            if team_id == 1:
                team = teams[0]
            elif team_id == 0:
                team = teams[1]
            else:
                # it's probably -1, but make sure it doesn't crash
                continue

            player = team.get_player_by_jersey_number(jersey_no)

            if not player:
                player = Player(
                    player_id=f"{team.ground}_{jersey_no}",
                    team=team,
                    jersey_no=int(jersey_no),
                )
                team.players.append(player)

            players_data[player] = PlayerData(
                coordinates=Point(float(x), float(y)), speed=float(speed)
            )

        (
            ball_x,
            ball_y,
            ball_z,
            ball_speed,
            ball_owning_team,
            ball_state,
        ) = ball.rstrip(";").split(",")[:6]

        frame_id = int(frame_id)

        if ball_owning_team == "H":
            ball_owning_team = teams[0]
        elif ball_owning_team == "A":
            ball_owning_team = teams[1]
        else:
            raise DeserializationError(
                f"Unknown ball owning team: {ball_owning_team}"
            )

        if ball_state == "Alive":
            ball_state = BallState.ALIVE
        elif ball_state == "Dead":
            ball_state = BallState.DEAD
        else:
            raise DeserializationError(f"Unknown ball state: {ball_state}")

        return Frame(
            frame_id=frame_id,
            timestamp=frame_id / frame_rate - period.start_timestamp,
            ball_coordinates=Point3D(
                float(ball_x), float(ball_y), float(ball_z)
            ),
            ball_state=ball_state,
            ball_owning_team=ball_owning_team,
            players_data=players_data,
            period=period,
            other_data={},
        )
Пример #12
0
    def _get_frame_data(
        cls,
        teams,
        teamdict,
        players,
        player_id_to_team_dict,
        periods,
        player_dict,
        anon_players,
        ball_id,
        referee_dict,
        frame,
    ):
        frame_period = frame["period"]

        frame_id = frame["frame"]
        frame_time = cls._timestamp_from_timestring(frame["time"])

        ball_coordinates = None
        players_data = {}

        # ball_carrier = frame["possession"].get("trackable_object")
        ball_owning_team = frame["possession"].get("group")

        if ball_owning_team == "home team":
            ball_owning_team = teams[0]
        elif ball_owning_team == "away team":
            ball_owning_team = teams[1]
        else:
            ball_owning_team = None

        for frame_record in frame["data"]:
            # containing x, y, trackable_object, track_id, group_name
            x = frame_record.get("x")
            y = frame_record.get("y")

            trackable_object = frame_record.get("trackable_object", None)

            track_id = frame_record.get("track_id", None)
            group_name = frame_record.get("group_name", None)

            if trackable_object == ball_id:
                group_name = "ball"
                z = frame_record.get("z")
                if z is not None:
                    z = float(z)
                ball_coordinates = Point3D(x=float(x), y=float(y), z=z)
                continue

            elif trackable_object in referee_dict.keys():
                group_name = "referee"
                continue  # Skip Referee Coords

            if group_name is None:
                group_name = teamdict.get(
                    player_id_to_team_dict.get(trackable_object))

                if group_name == "home_team":
                    player = players["HOME"][trackable_object]
                elif group_name == "away_team":
                    player = players["AWAY"][trackable_object]

            if trackable_object is None:
                player_id = str(track_id)
                if group_name == "home team":
                    if f"anon_{player_id}" not in anon_players["HOME"].keys():
                        player = cls.__create_anon_player(teams, frame_record)
                        anon_players["HOME"][f"anon_home_{player_id}"] = player
                    else:
                        player = anon_players["HOME"][f"anon_home_{player_id}"]

                elif group_name == "away team":
                    if f"anon_{player_id}" not in anon_players["AWAY"].keys():
                        player = cls.__create_anon_player(teams, frame_record)
                        anon_players["AWAY"][f"anon_away_{player_id}"] = player
                    else:
                        player = anon_players["AWAY"][f"anon_away_{player_id}"]

            players_data[player] = PlayerData(coordinates=Point(x, y))

        return Frame(
            frame_id=frame_id,
            timestamp=frame_time,
            ball_coordinates=ball_coordinates,
            players_data=players_data,
            period=periods[frame_period],
            ball_state=None,
            ball_owning_team=ball_owning_team,
            other_data={},
        )
Пример #13
0
    def _get_tracking_dataset(self):
        home_team = Team(team_id="home", name="home", ground=Ground.HOME)
        away_team = Team(team_id="away", name="away", ground=Ground.AWAY)
        teams = [home_team, away_team]

        periods = [
            Period(
                id=1,
                start_timestamp=0.0,
                end_timestamp=10.0,
                attacking_direction=AttackingDirection.HOME_AWAY,
            ),
            Period(
                id=2,
                start_timestamp=15.0,
                end_timestamp=25.0,
                attacking_direction=AttackingDirection.AWAY_HOME,
            ),
        ]
        metadata = Metadata(
            flags=~(DatasetFlag.BALL_OWNING_TEAM | DatasetFlag.BALL_STATE),
            pitch_dimensions=PitchDimensions(x_dim=Dimension(0, 100),
                                             y_dim=Dimension(-50, 50)),
            orientation=Orientation.HOME_TEAM,
            frame_rate=25,
            periods=periods,
            teams=teams,
            score=None,
            provider=None,
            coordinate_system=None,
        )

        tracking_data = TrackingDataset(
            metadata=metadata,
            records=[
                Frame(
                    frame_id=1,
                    timestamp=0.1,
                    ball_owning_team=None,
                    ball_state=None,
                    period=periods[0],
                    players_data={},
                    other_data=None,
                    ball_coordinates=Point3D(x=100, y=-50, z=0),
                ),
                Frame(
                    frame_id=2,
                    timestamp=0.2,
                    ball_owning_team=None,
                    ball_state=None,
                    period=periods[0],
                    players_data={
                        Player(team=home_team, player_id="home_1", jersey_no=1):
                        PlayerData(
                            coordinates=Point(x=15, y=35),
                            distance=0.03,
                            speed=10.5,
                            other_data={"extra_data": 1},
                        )
                    },
                    other_data={"extra_data": 1},
                    ball_coordinates=Point3D(x=0, y=50, z=1),
                ),
            ],
        )
        return tracking_data
Пример #14
0
    def test_correct_deserialization(self, meta_data: str, raw_data: str):
        dataset = tracab.load(
            meta_data=meta_data,
            raw_data=raw_data,
            coordinates="tracab",
            only_alive=False,
        )

        assert dataset.metadata.provider == Provider.TRACAB
        assert dataset.dataset_type == DatasetType.TRACKING
        assert len(dataset.records) == 6
        assert len(dataset.metadata.periods) == 2
        assert dataset.metadata.orientation == Orientation.FIXED_HOME_AWAY
        assert dataset.metadata.periods[0] == Period(
            id=1,
            start_timestamp=4.0,
            end_timestamp=4.08,
            attacking_direction=AttackingDirection.HOME_AWAY,
        )

        assert dataset.metadata.periods[1] == Period(
            id=2,
            start_timestamp=8.0,
            end_timestamp=8.08,
            attacking_direction=AttackingDirection.AWAY_HOME,
        )

        player_home_19 = dataset.metadata.teams[0].get_player_by_jersey_number(
            19
        )
        assert dataset.records[0].players_data[
            player_home_19
        ].coordinates == Point(x=-1234.0, y=-294.0)

        player_away_19 = dataset.metadata.teams[1].get_player_by_jersey_number(
            19
        )
        assert dataset.records[0].players_data[
            player_away_19
        ].coordinates == Point(x=8889, y=-666)
        assert dataset.records[0].ball_coordinates == Point3D(x=-27, y=25, z=0)
        assert dataset.records[0].ball_state == BallState.ALIVE
        assert dataset.records[0].ball_owning_team == Team(
            team_id="home", name="home", ground=Ground.HOME
        )

        assert dataset.records[1].ball_owning_team == Team(
            team_id="away", name="away", ground=Ground.AWAY
        )

        assert dataset.records[2].ball_state == BallState.DEAD

        # make sure player data is only in the frame when the player is at the pitch
        assert "away_1337" not in [
            player.player_id
            for player in dataset.records[0].players_data.keys()
        ]
        assert "away_1337" in [
            player.player_id
            for player in dataset.records[3].players_data.keys()
        ]
Пример #15
0
    def test_correct_deserialization(self, raw_data: str, meta_data: str):
        dataset = skillcorner.load(
            meta_data=meta_data, raw_data=raw_data, coordinates="skillcorner"
        )

        assert dataset.metadata.provider == Provider.SKILLCORNER
        assert dataset.dataset_type == DatasetType.TRACKING
        assert len(dataset.records) == 34783
        assert len(dataset.metadata.periods) == 2
        assert dataset.metadata.orientation == Orientation.AWAY_TEAM
        assert dataset.metadata.periods[1] == Period(
            id=1,
            start_timestamp=0.0,
            end_timestamp=2753.3,
            attacking_direction=AttackingDirection.AWAY_HOME,
        )
        assert dataset.metadata.periods[2] == Period(
            id=2,
            start_timestamp=2700.0,
            end_timestamp=5509.7,
            attacking_direction=AttackingDirection.HOME_AWAY,
        )

        # are frames with wrong camera views and pregame skipped?
        assert dataset.records[0].timestamp == 11.2

        # make sure data is loaded correctly
        home_player = dataset.metadata.teams[0].players[2]
        assert dataset.records[0].players_data[
            home_player
        ].coordinates == Point(x=33.8697315398, y=-9.55742259253)

        away_player = dataset.metadata.teams[1].players[9]
        assert dataset.records[0].players_data[
            away_player
        ].coordinates == Point(x=25.9863082795, y=27.3013598578)

        assert dataset.records[1].ball_coordinates == Point3D(
            x=30.5914728131, y=35.3622277834, z=2.24371228757
        )

        # check that missing ball-z_coordinate is identified as None
        assert dataset.records[38].ball_coordinates == Point3D(
            x=11.6568802848, y=24.7214038909, z=None
        )

        # check that 'ball_z' column is included in to_pandas dataframe
        # frame = _frame_to_pandas_row_converter(dataset.records[38])
        # assert "ball_z" in frame.keys()

        # make sure player data is only in the frame when the player is in view
        assert "home_1" not in [
            player.player_id
            for player in dataset.records[0].players_data.keys()
        ]

        assert "away_1" not in [
            player.player_id
            for player in dataset.records[0].players_data.keys()
        ]

        # are anonymous players loaded correctly?
        home_anon_75 = [
            player
            for player in dataset.records[87].players_data
            if player.player_id == "home_anon_75"
        ]
        assert home_anon_75 == [
            player
            for player in dataset.records[88].players_data
            if player.player_id == "home_anon_75"
        ]

        # is pitch dimension set correctly?
        pitch_dimensions = dataset.metadata.pitch_dimensions
        assert pitch_dimensions.x_dim.min == -52.5
        assert pitch_dimensions.x_dim.max == 52.5
        assert pitch_dimensions.y_dim.min == -34
        assert pitch_dimensions.y_dim.max == 34
Пример #16
0
    def test_correct_deserialization(self):
        base_dir = os.path.dirname(__file__)

        serializer = TRACABSerializer()

        with open(f"{base_dir}/files/tracab_meta.xml",
                  "rb") as metadata, open(f"{base_dir}/files/tracab_raw.dat",
                                          "rb") as raw_data:

            dataset = serializer.deserialize(
                inputs={
                    "metadata": metadata,
                    "raw_data": raw_data
                },
                options={"only_alive": False},
            )

        assert dataset.metadata.provider == Provider.TRACAB
        assert dataset.dataset_type == DatasetType.TRACKING
        assert len(dataset.records) == 6
        assert len(dataset.metadata.periods) == 2
        assert dataset.metadata.orientation == Orientation.FIXED_HOME_AWAY
        assert dataset.metadata.periods[0] == Period(
            id=1,
            start_timestamp=4.0,
            end_timestamp=4.08,
            attacking_direction=AttackingDirection.HOME_AWAY,
        )

        assert dataset.metadata.periods[1] == Period(
            id=2,
            start_timestamp=8.0,
            end_timestamp=8.08,
            attacking_direction=AttackingDirection.AWAY_HOME,
        )

        player_home_19 = dataset.metadata.teams[0].get_player_by_jersey_number(
            "19")
        assert dataset.records[0].players_coordinates[player_home_19] == Point(
            x=-1234.0, y=-294.0)

        player_away_19 = dataset.metadata.teams[1].get_player_by_jersey_number(
            "19")
        assert dataset.records[0].players_coordinates[player_away_19] == Point(
            x=8889, y=-666)
        assert dataset.records[0].ball_coordinates == Point3D(x=-27, y=25, z=0)
        assert dataset.records[0].ball_state == BallState.ALIVE
        assert dataset.records[0].ball_owning_team == Team(team_id="home",
                                                           name="home",
                                                           ground=Ground.HOME)

        assert dataset.records[1].ball_owning_team == Team(team_id="away",
                                                           name="away",
                                                           ground=Ground.AWAY)

        assert dataset.records[2].ball_state == BallState.DEAD

        # make sure player data is only in the frame when the player is at the pitch
        assert "away_1337" not in [
            player.player_id
            for player in dataset.records[0].players_coordinates.keys()
        ]
        assert "away_1337" in [
            player.player_id
            for player in dataset.records[3].players_coordinates.keys()
        ]