{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport cv2\nimport subprocess\nfrom IPython.display import Video\nfrom typing import List\nfrom dataclasses import dataclass\nimport random\nimport ast\nfrom tqdm import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-08-07T10:20:52.152604Z","iopub.execute_input":"2022-08-07T10:20:52.153029Z","iopub.status.idle":"2022-08-07T10:20:52.367283Z","shell.execute_reply.started":"2022-08-07T10:20:52.152945Z","shell.execute_reply":"2022-08-07T10:20:52.366102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"@dataclass\nclass Event:\n    video_id: int\n    event_id: int\n    begin_frame: int\n    event_frame: int\n    end_frame: int\n    event_name: str         # play, challenge, throwin\n    event_type: str = None  # pass, ball_action_forced, opponent_dispossessed, fouled, cross, challenge_during_ball_transfer, possession_retained, opponent_rounded\n    event_occ : str = None  # openplay, freekick, corner","metadata":{"execution":{"iopub.status.busy":"2022-08-07T10:20:53.501277Z","iopub.execute_input":"2022-08-07T10:20:53.502071Z","iopub.status.idle":"2022-08-07T10:20:53.509463Z","shell.execute_reply.started":"2022-08-07T10:20:53.502022Z","shell.execute_reply":"2022-08-07T10:20:53.508187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv('../input/dfl-bundesliga-data-shootout/train.csv')","metadata":{"execution":{"iopub.status.busy":"2022-08-07T10:20:54.836303Z","iopub.execute_input":"2022-08-07T10:20:54.836954Z","iopub.status.idle":"2022-08-07T10:20:54.865927Z","shell.execute_reply.started":"2022-08-07T10:20:54.836918Z","shell.execute_reply":"2022-08-07T10:20:54.864941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_event_id_col(train):\n    event_id = 0\n    for i, row in train.iterrows():\n        train.loc[i,'event_id'] = event_id\n        if row['event'] == \"end\":\n            event_id +=1 \n    train.event_id = train.event_id.astype(int)\n\ndef create_frame_col(train):\n    fps = 25\n    train['frame'] = train['time']*fps\n    train.frame = train.frame.astype(int)\n\n\ncreate_event_id_col(train)\ncreate_frame_col(train)","metadata":{"execution":{"iopub.status.busy":"2022-08-07T10:20:56.293790Z","iopub.execute_input":"2022-08-07T10:20:56.294536Z","iopub.status.idle":"2022-08-07T10:20:59.710997Z","shell.execute_reply.started":"2022-08-07T10:20:56.294483Z","shell.execute_reply":"2022-08-07T10:20:59.709858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"events = []\n\nfor (vid,eid), einfo in train.groupby(['video_id', 'event_id']):\n    begin_frame = einfo.query('event==\"start\"').frame.iloc[0]\n    end_frame   = einfo.query('event==\"end\"').frame.iloc[0]\n    \n    for _, erow in einfo.query('event !=\"start\" and event != \"end\"').iterrows():\n        event_name  = erow['event']\n        event_attrs = ast.literal_eval(erow['event_attributes'])\n        event_frame = erow['frame']\n        \n        event_type, event_occ = None, None\n        if len(event_attrs) == 2:\n            event_type, event_occ = event_attrs\n        elif len(event_attrs) == 1:\n            event_type = event_attrs[0]\n            \n        event = Event(video_id=vid, event_id=eid, begin_frame=begin_frame, event_frame = event_frame, end_frame=end_frame, event_name=event_name, event_type=event_type, event_occ=event_occ)\n        events.append(event)","metadata":{"execution":{"iopub.status.busy":"2022-08-07T10:20:59.712955Z","iopub.execute_input":"2022-08-07T10:20:59.713296Z","iopub.status.idle":"2022-08-07T10:21:22.660140Z","shell.execute_reply.started":"2022-08-07T10:20:59.713265Z","shell.execute_reply":"2022-08-07T10:21:22.659021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def annotate_img(img, event, frame):\n    \n    WHITE = (255, 255, 255)  \n    RED = (0, 0, 255) \n    \n    cv2.putText(\n        img,\n        f\"{frame} : {event.video_id}\",\n        (5, 30),\n        cv2.FONT_HERSHEY_SIMPLEX,\n        fontScale=1,\n        color=WHITE,\n        thickness=3,\n    )\n\n    cv2.putText(\n        img,\n        f\"Frame {str(frame).rjust(5, '0')}\",\n        (1920 - 300, 30),\n        cv2.FONT_HERSHEY_SIMPLEX,\n        fontScale=1,\n        color=WHITE,\n        thickness=3,\n    )\n\n    if event.event_frame - frame >= 0:\n        cv2.putText(\n            img,\n            f\"Event {event.event_name}, type {event.event_type}, occ {event.event_occ} ++ {event.event_frame - frame} frames\",\n            (350, 30),\n            cv2.FONT_HERSHEY_SIMPLEX,\n            fontScale=1,\n            color=WHITE,\n            thickness=3,\n        )\n    else:\n        cv2.putText(\n            img,\n            f\"Event {event.event_name}, type {event.event_type}, occ {event.event_occ} -- {frame - event.event_frame} frames\",\n            (350, 30),\n            cv2.FONT_HERSHEY_SIMPLEX,\n            fontScale=1,\n            color=WHITE,\n            thickness=3,\n        )\n    \n    return img\n    ","metadata":{"execution":{"iopub.status.busy":"2022-08-07T10:21:22.663908Z","iopub.execute_input":"2022-08-07T10:21:22.664238Z","iopub.status.idle":"2022-08-07T10:21:22.674693Z","shell.execute_reply.started":"2022-08-07T10:21:22.664209Z","shell.execute_reply":"2022-08-07T10:21:22.673753Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def video_into_shorts(event:Event, verbose=True, annotate=True):\n    \"\"\"\n    Find an event in a video and create a sample\n    \"\"\"\n    \n    VIDEO_CODEC = \"mp4v\"\n    video_path = os.path.join(\"../input/dfl-bundesliga-data-shootout/train\", event.video_id + '.mp4')\n    video_name = os.path.basename(video_path).replace(\".mp4\", \"\")\n    \n    if verbose:\n        print(f\"Running for {video_name}\")\n        \n    vidcap = cv2.VideoCapture(video_path)\n    fps = vidcap.get(cv2.CAP_PROP_FPS)\n    width = int(vidcap.get(cv2.CAP_PROP_FRAME_WIDTH))\n    height = int(vidcap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n    \n    et = event.event_type if event.event_type else 'None'\n    eo = event.event_occ if event.event_occ else 'None'\n    output_path = os.path.join('output', event.event_name, et, eo, str(event.event_id)+'.mp4')\n    tmp_output_path = os.path.join('output', event.event_name, et, eo, 'tmp_'+str(event.event_id)+'.mp4')\n\n    os.makedirs(os.path.split(output_path)[0], exist_ok=True)\n\n    output_video = cv2.VideoWriter(\n        tmp_output_path, cv2.VideoWriter_fourcc(*VIDEO_CODEC), fps, (width, height)\n    )\n\n    # Annotation tool\n\n    frame = event.begin_frame\n    vidcap.set(1,event.begin_frame)\n\n    while frame <= event.end_frame:\n        it_worked, img = vidcap.read()\n        if not it_worked:\n            break\n\n        frame += 1\n        \n        if annotate:\n            img = annotate_img(img, event, frame)\n\n        output_video.write(img)\n    \n    # Video is annotated\n    \n    output_video.release()\n\n    # Not all browsers support the codec, we will re-load the file at tmp_output_path\n    # and convert to a codec that is more broadly readable using ffmpeg\n\n    if os.path.exists(output_path):\n        os.remove(output_path)\n\n    subprocess.run([\"ffmpeg\", \"-i\", tmp_output_path, \"-crf\", \"18\", \"-preset\", \"veryfast\", \"-vcodec\", \"libx264\", output_path, \"-loglevel\" ,\"quiet\"])\n\n    os.remove(tmp_output_path)\n\n    return output_path","metadata":{"execution":{"iopub.status.busy":"2022-08-07T10:21:22.676739Z","iopub.execute_input":"2022-08-07T10:21:22.677088Z","iopub.status.idle":"2022-08-07T10:21:22.691219Z","shell.execute_reply.started":"2022-08-07T10:21:22.677058Z","shell.execute_reply":"2022-08-07T10:21:22.690272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"video_out = video_into_shorts(event = random.choice(events))\n\nfrac = 1 # scaling factor for display\ndisplay(Video(data=video_out,\n              embed=True,\n              height=int(720*frac),\n              width=int(1280*frac))\n       )","metadata":{"execution":{"iopub.status.busy":"2022-08-07T10:21:22.692584Z","iopub.execute_input":"2022-08-07T10:21:22.692933Z","iopub.status.idle":"2022-08-07T10:21:28.068015Z","shell.execute_reply.started":"2022-08-07T10:21:22.692902Z","shell.execute_reply":"2022-08-07T10:21:28.066409Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Cut all videos into shorts and create a dataset\n\nfor event in tqdm(events):\n    video_into_shorts(event, verbose=False, annotate=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}