def _team_from_xml_elm(team_elm, f7_root) -> Team: # This should not happen here team_name, team_players = _parse_team_players(f7_root, team_elm.attrib["TeamRef"]) team_id = team_elm.attrib["TeamRef"].lstrip("t") team = Team( team_id=str(team_id), name=team_name, ground=Ground.HOME if team_elm.attrib["Side"] == "Home" else Ground.AWAY, ) team.players = [ Player( player_id=player_elm.attrib["PlayerRef"].lstrip("p"), team=team, jersey_no=int(player_elm.attrib["ShirtNumber"]), first_name=team_players[ player_elm.attrib["PlayerRef"]]["first_name"], last_name=team_players[player_elm.attrib["PlayerRef"]] ["last_name"], position=Position( position_id=player_elm.attrib["Formation_Place"], name=player_elm.attrib["Position"], coordinates=None, ), ) for player_elm in team_elm.find("PlayerLineUp").iterchildren( "MatchPlayer") ] return team
def _team_from_xml_elm(team_elm) -> Team: team = Team( team_id=team_elm.attrib["TeamId"], name=team_elm.attrib["TeamName"], ground=Ground.HOME if team_elm.attrib["Role"] == "home" else Ground.AWAY, ) team.players = [ Player( player_id=player_elm.attrib["PersonId"], team=team, jersey_no=int(player_elm.attrib["ShirtNumber"]), name=player_elm.attrib["Shortname"], first_name=player_elm.attrib["FirstName"], last_name=player_elm.attrib["LastName"], position=Position( position_id=None, name=player_elm.attrib["PlayingPosition"], coordinates=None, ) if "PlayingPosition" in player_elm.attrib else None, starting=player_elm.attrib["Starting"] == "true", ) for player_elm in team_elm.Players.iterchildren("Player") ] return team
def _load_position_data(parent_elm) -> Position: # TODO: _load_provider_parameters is called twice to set position data # and then again to set the attributes. Also, data in position should not # be duplicated in attributes either. player_provider_parameters = _load_provider_parameters(parent_elm) if "position_index" not in player_provider_parameters: return None return Position( position_id=player_provider_parameters["position_index"], name=player_provider_parameters["position_type"], coordinates=Point( player_provider_parameters["position_x"], player_provider_parameters["position_y"], ), )
def deserialize(self, inputs: SkillCornerInputs) -> TrackingDataset: metadata = self.__load_json(inputs.meta_data) raw_data = self.__load_json(inputs.raw_data) with performance_logging("Loading metadata", logger=logger): periods = self.__get_periods(raw_data) teamdict = { metadata["home_team"].get("id"): "home_team", metadata["away_team"].get("id"): "away_team", } player_id_to_team_dict = { player["trackable_object"]: player["team_id"] for player in metadata["players"] } player_dict = { player["trackable_object"]: player for player in metadata["players"] } referee_dict = { ref["trackable_object"]: "referee" for ref in metadata["referees"] } ball_id = metadata["ball"]["trackable_object"] # there are different pitch_sizes in SkillCorner pitch_size_width = metadata["pitch_width"] pitch_size_length = metadata["pitch_length"] transformer = self.get_transformer(length=pitch_size_length, width=pitch_size_width) home_team_id = metadata["home_team"]["id"] away_team_id = metadata["away_team"]["id"] players = {"HOME": {}, "AWAY": {}} home_team = Team( team_id=home_team_id, name=metadata["home_team"]["name"], ground=Ground.HOME, ) away_team = Team( team_id=away_team_id, name=metadata["away_team"]["name"], ground=Ground.AWAY, ) teams = [home_team, away_team] for player_id in player_dict.keys(): player = player_dict.get(player_id) team_id = player["team_id"] if team_id == home_team_id: team_string = "HOME" team = home_team elif team_id == away_team_id: team_string = "AWAY" team = away_team players[team_string][player_id] = Player( player_id=f"{team.ground}_{player['number']}", team=team, jersey_no=player["number"], name=f"{player['first_name']} {player['last_name']}", first_name=player["first_name"], last_name=player["last_name"], starting=player["start_time"] == "00:00:00", position=Position( position_id=player["player_role"].get("id"), name=player["player_role"].get("name"), coordinates=None, ), attributes={}, ) home_team.players = list(players["HOME"].values()) away_team.players = list(players["AWAY"].values()) anon_players = {"HOME": {}, "AWAY": {}} with performance_logging("Loading data", logger=logger): def _iter(): n = 0 sample = 1.0 / self.sample_rate for frame in raw_data: frame_period = frame["period"] if frame_period is not None: if n % sample == 0: yield frame n += 1 frames = [] n_frames = 0 for _frame in _iter(): # include frame if there is any tracking data, players or ball. # or if include_empty_frames == True if self.include_empty_frames or len(_frame["data"]) > 0: frame = self._get_frame_data( teams, teamdict, players, player_id_to_team_dict, periods, player_dict, anon_players, ball_id, referee_dict, _frame, ) frame = transformer.transform_frame(frame) frames.append(frame) n_frames += 1 if self.limit and n_frames >= self.limit: break self._set_skillcorner_attacking_directions(frames, periods) frame_rate = 10 orientation = (Orientation.HOME_TEAM if periods[1].attacking_direction == AttackingDirection.HOME_AWAY else Orientation.AWAY_TEAM) metadata = Metadata( teams=teams, periods=periods, pitch_dimensions=transformer.get_to_coordinate_system(). pitch_dimensions, score=Score( home=metadata["home_team_score"], away=metadata["away_team_score"], ), frame_rate=frame_rate, orientation=orientation, provider=Provider.SKILLCORNER, flags=~(DatasetFlag.BALL_STATE | DatasetFlag.BALL_OWNING_TEAM), coordinate_system=transformer.get_to_coordinate_system(), ) return TrackingDataset( records=frames, metadata=metadata, )
def deserialize(self, inputs: Dict[str, Readable], options: Dict = None) -> TrackingDataset: """ Deserialize SkillCorner tracking data into a `TrackingDataset`. Parameters ---------- inputs : dict input `raw_data` should point to a `Readable` object containing the 'json' formatted raw data. input `metadata` should point to the json metadata data. options : dict Options for deserialization of the TRACAB file. Possible options are: `include_empty_frames` (boolean): default = False to specify whether frames without any players_coordinates or the ball_coordinates should be loaded `sample_rate` (float between 0 and 1) to specify the amount of frames that should be loaded and `limit` (int) to specify the max number of frames that will be returned. Returns ------- dataset : TrackingDataset Raises ------ - See Also -------- Examples -------- >>> serializer = SkillCornerSerializer() >>> with open("match_data.json", "rb") as meta, \ >>> open("structured_data.json", "rb") as raw: >>> dataset = serializer.deserialize( >>> inputs={ >>> 'metadata': meta, >>> 'raw_data': raw >>> }, >>> options={ >>> } >>> ) """ self.__validate_inputs(inputs) metadata = self.__load_json(inputs["metadata"]) raw_data = self.__load_json(inputs["raw_data"]) if not options: options = {} sample_rate = float(options.get("sample_rate", 1.0)) limit = int(options.get("limit", 0)) include_empty_frames = bool(options.get("include_empty_frames", False)) with performance_logging("Loading metadata", logger=logger): periods = self.__get_periods(raw_data) teamdict = { metadata["home_team"].get("id"): "home_team", metadata["away_team"].get("id"): "away_team", } player_id_to_team_dict = { player["trackable_object"]: player["team_id"] for player in metadata["players"] } player_dict = { player["trackable_object"]: player for player in metadata["players"] } referee_dict = { ref["trackable_object"]: "referee" for ref in metadata["referees"] } ball_id = metadata["ball"]["trackable_object"] # there are different pitch_sizes in SkillCorner pitch_size_width = metadata["pitch_width"] pitch_size_length = metadata["pitch_length"] home_team_id = metadata["home_team"]["id"] away_team_id = metadata["away_team"]["id"] players = {"HOME": {}, "AWAY": {}} home_team = Team( team_id=home_team_id, name=metadata["home_team"]["name"], ground=Ground.HOME, ) self.home_team = home_team away_team = Team( team_id=away_team_id, name=metadata["away_team"]["name"], ground=Ground.AWAY, ) self.away_team = away_team teams = [home_team, away_team] for player_id in player_dict.keys(): player = player_dict.get(player_id) team_id = player["team_id"] if team_id == home_team_id: team_string = "HOME" team = home_team elif team_id == away_team_id: team_string = "AWAY" team = away_team players[team_string][player_id] = Player( player_id=f"{team.ground}_{player['number']}", team=team, jersey_no=player["number"], name=f"{player['first_name']} {player['last_name']}", first_name=player["first_name"], last_name=player["last_name"], starting=player["start_time"] == "00:00:00", position=Position( position_id=player["player_role"].get("id"), name=player["player_role"].get("name"), coordinates=None, ), attributes={}, ) home_team.players = list(players["HOME"].values()) away_team.players = list(players["AWAY"].values()) anon_players = {"HOME": {}, "AWAY": {}} with performance_logging("Loading data", logger=logger): def _iter(): n = 0 sample = 1.0 / sample_rate for frame in raw_data: frame_period = frame["period"] if frame_period is not None: if n % sample == 0: yield frame n += 1 frames = [] n_frames = 0 for _frame in _iter(): # include frame if there is any tracking data, players or ball. # or if include_empty_frames == True if include_empty_frames or len(_frame["data"]) > 0: frame = self._get_frame_data( teams, teamdict, players, player_id_to_team_dict, periods, player_dict, anon_players, ball_id, referee_dict, _frame, ) frames.append(frame) n_frames += 1 if limit and n_frames >= limit: break self._set_skillcorner_attacking_directions(frames, periods) frame_rate = 10 orientation = (Orientation.HOME_TEAM if periods[1].attacking_direction == AttackingDirection.HOME_AWAY else Orientation.AWAY_TEAM) metadata = Metadata( teams=teams, periods=periods, pitch_dimensions=PitchDimensions( x_dim=Dimension(-(pitch_size_length / 2), (pitch_size_length / 2)), y_dim=Dimension(-(pitch_size_width / 2), (pitch_size_width / 2)), x_per_meter=1, y_per_meter=1, ), score=Score( home=metadata["home_team_score"], away=metadata["away_team_score"], ), frame_rate=frame_rate, orientation=orientation, provider=Provider.SKILLCORNER, flags=~(DatasetFlag.BALL_STATE | DatasetFlag.BALL_OWNING_TEAM), ) return TrackingDataset( records=frames, metadata=metadata, )