{"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 numpy as np\nimport pandas as pd\nimport matplotlib.pylab as plt\nimport warnings\n\nwith warnings.catch_warnings():\n    warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n\n# Read in data files\nBASE_DIR = \"../input/nfl-player-contact-detection\"\n\n# Labels and sample submission\nlabels = pd.read_csv(f\"{BASE_DIR}/train_labels.csv\", parse_dates=[\"datetime\"])\n\nss = pd.read_csv(f\"{BASE_DIR}/sample_submission.csv\")\n\n# Player tracking data\ntr_tracking = pd.read_csv(\n    f\"{BASE_DIR}/train_player_tracking.csv\", parse_dates=[\"datetime\"]\n)\n\n# Baseline helmet detection labels\ntr_helmets = pd.read_csv(f\"{BASE_DIR}/train_baseline_helmets.csv\")\n\n# Video metadata with start/stop timestamps\ntr_video_metadata = pd.read_csv(\n    \"../input/nfl-player-contact-detection/train_video_metadata.csv\",\n    parse_dates=[\"start_time\", \"end_time\", \"snap_time\"],\n)\n","metadata":{"papermill":{"duration":38.158339,"end_time":"2022-12-05T18:52:36.128186","exception":false,"start_time":"2022-12-05T18:51:57.969847","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-01-30T07:15:07.749351Z","iopub.execute_input":"2023-01-30T07:15:07.750472Z","iopub.status.idle":"2023-01-30T07:16:06.907438Z","shell.execute_reply.started":"2023-01-30T07:15:07.750331Z","shell.execute_reply":"2023-01-30T07:16:06.906174Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def join_helmets_contact(game_play, labels, helmets, meta, view=\"Sideline\", fps=59.94):\n    \"\"\"\n    Joins helmets and labels for a given game_play. Results can be used for visualizing labels.\n    Returns a dataframe with the joint dataframe, duplicating rows if multiple contacts occur.\n    \"\"\"\n    gp_labs = labels.query(\"game_play == @game_play\").copy()\n    gp_helms = helmets.query(\"game_play == @game_play\").copy()\n\n    start_time = meta.query(\"game_play == @game_play and view == @view\")[\n        \"start_time\"\n    ].values[0]\n\n    gp_helms[\"datetime\"] = (\n        pd.to_timedelta(gp_helms[\"frame\"] * (1 / fps), unit=\"s\") + start_time\n    )\n    gp_helms[\"datetime\"] = pd.to_datetime(gp_helms[\"datetime\"], utc=True)\n    gp_helms[\"datetime_ngs\"] = (\n        pd.DatetimeIndex(gp_helms[\"datetime\"] + pd.to_timedelta(50, \"ms\"))\n        .floor(\"100ms\")\n        .values\n    )\n    gp_helms[\"datetime_ngs\"] = pd.to_datetime(gp_helms[\"datetime_ngs\"], utc=True)\n\n    gp_labs[\"datetime_ngs\"] = pd.to_datetime(gp_labs[\"datetime\"], utc=True)\n\n    gp = gp_helms.merge(\n        gp_labs.query(\"contact == 1\")[\n            [\"datetime_ngs\", \"nfl_player_id_1\", \"nfl_player_id_2\", \"contact_id\"]\n        ],\n        left_on=[\"datetime_ngs\", \"nfl_player_id\"],\n        right_on=[\"datetime_ngs\", \"nfl_player_id_1\"],\n        how=\"left\",\n    )\n    return gp\n","metadata":{"_kg_hide-input":true,"papermill":{"duration":0.138777,"end_time":"2022-12-05T18:53:47.152306","exception":false,"start_time":"2022-12-05T18:53:47.013529","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-01-30T07:16:06.909957Z","iopub.execute_input":"2023-01-30T07:16:06.910796Z","iopub.status.idle":"2023-01-30T07:16:06.925362Z","shell.execute_reply.started":"2023-01-30T07:16:06.910729Z","shell.execute_reply":"2023-01-30T07:16:06.924191Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport subprocess\nfrom IPython.display import Video, display\nimport pandas as pd\n\n\ndef video_with_contact(\n    video_path: str, baseline_boxes: pd.DataFrame, verbose=True\n) -> str:\n    \"\"\"\n    Annotates a video with baseline model boxes.\n    Helmet boxes are colored based on the contact label.\n    \"\"\"\n    VIDEO_CODEC = \"MP4V\"\n    HELMET_COLOR = (0, 0, 0)  # Black\n    video_name = os.path.basename(video_path)\n    if verbose:\n        print(f\"Running for {video_name}\")\n    baseline_boxes = baseline_boxes.copy()\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    output_path = \"contact_\" + video_name\n    tmp_output_path = \"tmp_\" + output_path\n    output_video = cv2.VideoWriter(\n        tmp_output_path, cv2.VideoWriter_fourcc(*VIDEO_CODEC), fps, (width, height)\n    )\n    frame = 0\n    while True:\n        it_worked, img = vidcap.read()\n        if not it_worked:\n            break\n        # We need to add 1 to the frame count to match the label frame index\n        # that starts at 1\n        frame += 1\n\n        # Let's add a frame index to the video so we can track where we are\n        img_name = video_name.replace('.mp4','')\n        cv2.putText(\n            img,\n            img_name,\n            (10, 30),\n            cv2.FONT_HERSHEY_SIMPLEX,\n            1,\n            HELMET_COLOR,\n            thickness=1,\n        )\n        \n        cv2.putText(\n            img,\n            str(frame),\n            (1280 - 90, 720 - 20),\n            cv2.FONT_HERSHEY_SIMPLEX,\n            1,\n            HELMET_COLOR,\n            thickness=1,\n        )\n\n        # Now, add the boxes\n        boxes = baseline_boxes.query(\"video == @video_name and frame == @frame\")\n        contact_players = boxes.dropna(subset=[\"nfl_player_id_2\"]).query(\n            'nfl_player_id_2 != \"G\"'\n        )\n        contact_ids = (\n            contact_players[\"nfl_player_id_1\"].astype(\"int\").values.tolist()\n            + contact_players[\"nfl_player_id_2\"].astype(\"int\").values.tolist()\n        )\n        for box in boxes.itertuples(index=False):\n\n            if box.nfl_player_id_2 == \"G\":\n                box_color = (0, 0, 255)  # Red\n                box_thickness = 2\n            elif int(box.nfl_player_id) in contact_ids:\n                box_color = (0, 255, 0)  # green\n                box_thickness = 2\n\n                # Add line between players in contact\n                if not np.isnan(float(box.nfl_player_id_2)):\n                    player2 = int(box.nfl_player_id_2)\n                    player2_row = boxes.query(\"nfl_player_id == @player2\")\n                    if len(player2_row) == 0:\n                        # Player 2 is not in view\n                        continue\n                    cv2.line(\n                        img,\n                        (box.left + int(box.width / 2), box.top + int(box.height / 2)),\n                        (\n                            player2_row.left.values[0]\n                            + int(player2_row.width.values[0] / 2),\n                            player2_row.top.values[0]\n                            + int(player2_row.height.values[0] / 2),\n                        ),\n                        color=(255, 0, 0),\n                        thickness=2,\n                    )\n\n            else:\n                box_color = HELMET_COLOR\n                box_thickness = 1\n\n            # Draw lines between two boxes\n\n            cv2.rectangle(\n                img,\n                (box.left, box.top),\n                (box.left + box.width, box.top + box.height),\n                box_color,\n                thickness=box_thickness,\n            )\n            cv2.putText(\n                img,\n                box.player_label,\n                (box.left + 1, max(0, box.top - 20)),\n                cv2.FONT_HERSHEY_SIMPLEX,\n                0.5,\n                HELMET_COLOR,\n                thickness=1,\n            )\n\n        output_video.write(img)\n    output_video.release()\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    if os.path.exists(output_path):\n        os.remove(output_path)\n    subprocess.run(\n        [\n            \"ffmpeg\",\n            \"-i\",\n            tmp_output_path,\n            \"-crf\",\n            \"18\",\n            \"-preset\",\n            \"veryfast\",\n            \"-hide_banner\",\n            \"-loglevel\",\n            \"error\",\n            \"-vcodec\",\n            \"libx264\",\n            output_path,\n        ]\n    )\n    os.remove(tmp_output_path)\n\n    return output_path\n","metadata":{"_kg_hide-input":true,"papermill":{"duration":0.149334,"end_time":"2022-12-05T18:53:47.421509","exception":false,"start_time":"2022-12-05T18:53:47.272175","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-01-30T07:16:06.927269Z","iopub.execute_input":"2023-01-30T07:16:06.928071Z","iopub.status.idle":"2023-01-30T07:16:07.192302Z","shell.execute_reply.started":"2023-01-30T07:16:06.928031Z","shell.execute_reply":"2023-01-30T07:16:07.191177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## All Videos with Labels\n\nNote :\n- **Black** helmet boxes indicate that player is not in contact. A unique number (home/visiting combined with jersey number) is shown next to their helmet.\n- **Green** helmet box indicates the player is in contact with one or more players.\n- **Red** helmet box indicates the player is in contact with the ground (and possibly another player).\n- **Blue** lines show the link between players in contact with each other.","metadata":{"papermill":{"duration":0.125008,"end_time":"2022-12-05T18:53:47.672104","exception":false,"start_time":"2022-12-05T18:53:47.547096","status":"completed"},"tags":[]}},{"cell_type":"code","source":"games = np.unique(labels.game_play)\nfrac = 0.65  # scaling factor for display\nfor i,game_play in enumerate(games):\n    if i == 10 :\n        break\n    for view in [\"Sideline\",\"Endzone\"]:\n        try :\n            example_video =\"/kaggle/input/nfl-player-contact-detection/train/{}_{}.mp4\".format(game_play,view)\n            print(\"Game_play : \",game_play)\n            gp = join_helmets_contact(game_play, labels, tr_helmets, tr_video_metadata,view=view)\n            output_video = video_with_contact(example_video, gp)\n            display(\n                Video(data=output_video, embed=True, height=int(720 * frac), width=int(1280 * frac))\n            )\n        except :\n            pass","metadata":{"papermill":{"duration":21.040193,"end_time":"2022-12-05T18:54:08.837849","exception":false,"start_time":"2022-12-05T18:53:47.797656","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-01-30T07:16:07.194833Z","iopub.execute_input":"2023-01-30T07:16:07.195350Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}